diff options
Diffstat (limited to 'src/gui/opengl')
49 files changed, 274 insertions, 27952 deletions
diff --git a/src/gui/opengl/opengl.pri b/src/gui/opengl/opengl.pri index 24758afdeb..2ca3809b4b 100644 --- a/src/gui/opengl/opengl.pri +++ b/src/gui/opengl/opengl.pri @@ -8,57 +8,18 @@ qtConfig(opengl) { HEADERS += opengl/qopengl.h \ opengl/qopengl_p.h \ opengl/qopenglfunctions.h \ - opengl/qopenglframebufferobject.h \ - opengl/qopenglframebufferobject_p.h \ - opengl/qopenglpaintdevice.h \ - opengl/qopenglpaintdevice_p.h \ - opengl/qopenglbuffer.h \ - opengl/qopenglshaderprogram.h \ opengl/qopenglextensions_p.h \ - opengl/qopenglgradientcache_p.h \ - opengl/qopengltexturecache_p.h \ - opengl/qopenglengineshadermanager_p.h \ - opengl/qopengl2pexvertexarray_p.h \ - opengl/qopenglpaintengine_p.h \ - opengl/qopenglengineshadersource_p.h \ - opengl/qopenglcustomshaderstage_p.h \ - opengl/qopengltextureglyphcache_p.h \ - opengl/qopenglshadercache_p.h \ opengl/qopenglversionfunctions.h \ opengl/qopenglversionfunctionsfactory_p.h \ - opengl/qopenglvertexarrayobject.h \ - opengl/qopengldebug.h \ - opengl/qopengltextureblitter.h \ - opengl/qopengltexture.h \ - opengl/qopengltexture_p.h \ - opengl/qopengltexturehelper_p.h \ - opengl/qopengltextureuploader_p.h \ - opengl/qopenglpixeltransferoptions.h \ + opengl/qopenglversionprofile.h \ opengl/qopenglextrafunctions.h \ opengl/qopenglprogrambinarycache_p.h SOURCES += opengl/qopengl.cpp \ opengl/qopenglfunctions.cpp \ - opengl/qopenglframebufferobject.cpp \ - opengl/qopenglpaintdevice.cpp \ - opengl/qopenglbuffer.cpp \ - opengl/qopenglshaderprogram.cpp \ - opengl/qopenglgradientcache.cpp \ - opengl/qopengltexturecache.cpp \ - opengl/qopenglengineshadermanager.cpp \ - opengl/qopengl2pexvertexarray.cpp \ - opengl/qopenglpaintengine.cpp \ - opengl/qopenglcustomshaderstage.cpp \ - opengl/qopengltextureglyphcache.cpp \ opengl/qopenglversionfunctions.cpp \ opengl/qopenglversionfunctionsfactory.cpp \ - opengl/qopenglvertexarrayobject.cpp \ - opengl/qopengldebug.cpp \ - opengl/qopengltextureblitter.cpp \ - opengl/qopengltexture.cpp \ - opengl/qopengltexturehelper.cpp \ - opengl/qopengltextureuploader.cpp \ - opengl/qopenglpixeltransferoptions.cpp \ + opengl/qopenglversionprofile.cpp \ opengl/qopenglprogrambinarycache.cpp !qtConfig(opengles2) { @@ -87,9 +48,7 @@ qtConfig(opengl) { opengl/qopenglfunctions_4_2_compatibility.h \ opengl/qopenglfunctions_4_3_compatibility.h \ opengl/qopenglfunctions_4_4_compatibility.h \ - opengl/qopenglfunctions_4_5_compatibility.h \ - opengl/qopenglqueryhelper_p.h \ - opengl/qopengltimerquery.h + opengl/qopenglfunctions_4_5_compatibility.h SOURCES += opengl/qopenglfunctions_1_0.cpp \ opengl/qopenglfunctions_1_1.cpp \ @@ -116,8 +75,7 @@ qtConfig(opengl) { opengl/qopenglfunctions_4_2_compatibility.cpp \ opengl/qopenglfunctions_4_3_compatibility.cpp \ opengl/qopenglfunctions_4_4_compatibility.cpp \ - opengl/qopenglfunctions_4_5_compatibility.cpp \ - opengl/qopengltimerquery.cpp + opengl/qopenglfunctions_4_5_compatibility.cpp } qtConfig(opengles2) { diff --git a/src/gui/opengl/qopengl2pexvertexarray.cpp b/src/gui/opengl/qopengl2pexvertexarray.cpp deleted file mode 100644 index 04781f63c7..0000000000 --- a/src/gui/opengl/qopengl2pexvertexarray.cpp +++ /dev/null @@ -1,173 +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 "qopengl2pexvertexarray_p.h" - -#include <private/qbezier_p.h> - -QT_BEGIN_NAMESPACE - -void QOpenGL2PEXVertexArray::clear() -{ - vertexArray.reset(); - vertexArrayStops.reset(); - boundingRectDirty = true; -} - - -QOpenGLRect QOpenGL2PEXVertexArray::boundingRect() const -{ - if (boundingRectDirty) - return QOpenGLRect(0.0, 0.0, 0.0, 0.0); - else - return QOpenGLRect(minX, minY, maxX, maxY); -} - -void QOpenGL2PEXVertexArray::addClosingLine(int index) -{ - QPointF point(vertexArray.at(index)); - if (point != QPointF(vertexArray.last())) - vertexArray.add(point); -} - -void QOpenGL2PEXVertexArray::addCentroid(const QVectorPath &path, int subPathIndex) -{ - const QPointF *const points = reinterpret_cast<const QPointF *>(path.points()); - const QPainterPath::ElementType *const elements = path.elements(); - - QPointF sum = points[subPathIndex]; - int count = 1; - - for (int i = subPathIndex + 1; i < path.elementCount() && (!elements || elements[i] != QPainterPath::MoveToElement); ++i) { - sum += points[i]; - ++count; - } - - const QPointF centroid = sum / qreal(count); - vertexArray.add(centroid); -} - -void QOpenGL2PEXVertexArray::addPath(const QVectorPath &path, GLfloat curveInverseScale, bool outline) -{ - const QPointF* const points = reinterpret_cast<const QPointF*>(path.points()); - const QPainterPath::ElementType* const elements = path.elements(); - - if (boundingRectDirty) { - minX = maxX = points[0].x(); - minY = maxY = points[0].y(); - boundingRectDirty = false; - } - - if (!outline && !path.isConvex()) - addCentroid(path, 0); - - int lastMoveTo = vertexArray.size(); - vertexArray.add(points[0]); // The first element is always a moveTo - - do { - if (!elements) { -// qDebug("QVectorPath has no elements"); - // If the path has a null elements pointer, the elements implicitly - // start with a moveTo (already added) and continue with lineTos: - for (int i=1; i<path.elementCount(); ++i) - lineToArray(points[i].x(), points[i].y()); - - break; - } -// qDebug("QVectorPath has element types"); - - for (int i=1; i<path.elementCount(); ++i) { - switch (elements[i]) { - case QPainterPath::MoveToElement: - if (!outline) - addClosingLine(lastMoveTo); -// qDebug("element[%d] is a MoveToElement", i); - vertexArrayStops.add(vertexArray.size()); - if (!outline) { - if (!path.isConvex()) addCentroid(path, i); - lastMoveTo = vertexArray.size(); - } - lineToArray(points[i].x(), points[i].y()); // Add the moveTo as a new vertex - break; - case QPainterPath::LineToElement: -// qDebug("element[%d] is a LineToElement", i); - lineToArray(points[i].x(), points[i].y()); - break; - case QPainterPath::CurveToElement: { - QBezier b = QBezier::fromPoints(*(((const QPointF *) points) + i - 1), - points[i], - points[i+1], - points[i+2]); - QRectF bounds = b.bounds(); - // threshold based on same algorithm as in qtriangulatingstroker.cpp - int threshold = qMin<float>(64, qMax(bounds.width(), bounds.height()) * 3.14f / (curveInverseScale * 6)); - if (threshold < 3) threshold = 3; - qreal one_over_threshold_minus_1 = qreal(1) / (threshold - 1); - for (int t=0; t<threshold; ++t) { - QPointF pt = b.pointAt(t * one_over_threshold_minus_1); - lineToArray(pt.x(), pt.y()); - } - i += 2; - break; } - default: - break; - } - } - } while (0); - - if (!outline) - addClosingLine(lastMoveTo); - vertexArrayStops.add(vertexArray.size()); -} - -void QOpenGL2PEXVertexArray::lineToArray(const GLfloat x, const GLfloat y) -{ - vertexArray.add(QOpenGLPoint(x, y)); - - if (x > maxX) - maxX = x; - else if (x < minX) - minX = x; - if (y > maxY) - maxY = y; - else if (y < minY) - minY = y; -} - -QT_END_NAMESPACE diff --git a/src/gui/opengl/qopengl2pexvertexarray_p.h b/src/gui/opengl/qopengl2pexvertexarray_p.h deleted file mode 100644 index 5dc060ff3d..0000000000 --- a/src/gui/opengl/qopengl2pexvertexarray_p.h +++ /dev/null @@ -1,168 +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$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#ifndef QOPENGL2PEXVERTEXARRAY_P_H -#define QOPENGL2PEXVERTEXARRAY_P_H - -#include <QtGui/private/qtguiglobal_p.h> -#include <QRectF> - -#include <private/qdatabuffer_p.h> -#include <private/qvectorpath_p.h> -#include <private/qopenglcontext_p.h> - -QT_BEGIN_NAMESPACE - -class QOpenGLPoint -{ -public: - QOpenGLPoint(GLfloat new_x, GLfloat new_y) : - x(new_x), y(new_y) {}; - - QOpenGLPoint(const QPointF &p) : - x(p.x()), y(p.y()) {}; - - QOpenGLPoint(const QPointF* p) : - x(p->x()), y(p->y()) {}; - - GLfloat x; - GLfloat y; - - operator QPointF() {return QPointF(x,y);} - operator QPointF() const {return QPointF(x,y);} -}; - -struct QOpenGLRect -{ - QOpenGLRect(const QRectF &r) - : left(r.left()), top(r.top()), right(r.right()), bottom(r.bottom()) {} - - QOpenGLRect(GLfloat l, GLfloat t, GLfloat r, GLfloat b) - : left(l), top(t), right(r), bottom(b) {} - - GLfloat left; - GLfloat top; - GLfloat right; - GLfloat bottom; - - operator QRectF() const {return QRectF(left, top, right-left, bottom-top);} -}; - -class QOpenGL2PEXVertexArray -{ -public: - QOpenGL2PEXVertexArray() : - vertexArray(0), vertexArrayStops(0), - maxX(-2e10), maxY(-2e10), minX(2e10), minY(2e10), - boundingRectDirty(true) - { } - - inline void addRect(const QRectF &rect) - { - qreal top = rect.top(); - qreal left = rect.left(); - qreal bottom = rect.bottom(); - qreal right = rect.right(); - - vertexArray << QOpenGLPoint(left, top) - << QOpenGLPoint(right, top) - << QOpenGLPoint(right, bottom) - << QOpenGLPoint(right, bottom) - << QOpenGLPoint(left, bottom) - << QOpenGLPoint(left, top); - } - - inline void addQuad(const QRectF &rect) - { - qreal top = rect.top(); - qreal left = rect.left(); - qreal bottom = rect.bottom(); - qreal right = rect.right(); - - vertexArray << QOpenGLPoint(left, top) - << QOpenGLPoint(right, top) - << QOpenGLPoint(left, bottom) - << QOpenGLPoint(right, bottom); - - } - - inline void addVertex(const GLfloat x, const GLfloat y) - { - vertexArray.add(QOpenGLPoint(x, y)); - } - - void addPath(const QVectorPath &path, GLfloat curveInverseScale, bool outline = true); - void clear(); - - QOpenGLPoint* data() {return vertexArray.data();} - int *stops() const { return vertexArrayStops.data(); } - int stopCount() const { return vertexArrayStops.size(); } - QOpenGLRect boundingRect() const; - - int vertexCount() const { return vertexArray.size(); } - - void lineToArray(const GLfloat x, const GLfloat y); - -private: - QDataBuffer<QOpenGLPoint> vertexArray; - QDataBuffer<int> vertexArrayStops; - - GLfloat maxX; - GLfloat maxY; - GLfloat minX; - GLfloat minY; - bool boundingRectDirty; - void addClosingLine(int index); - void addCentroid(const QVectorPath &path, int subPathIndex); -}; - -QT_END_NAMESPACE - -#endif diff --git a/src/gui/opengl/qopenglbuffer.cpp b/src/gui/opengl/qopenglbuffer.cpp deleted file mode 100644 index 5387cc06e3..0000000000 --- a/src/gui/opengl/qopenglbuffer.cpp +++ /dev/null @@ -1,618 +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 <QtGui/qopengl.h> -#include <QtGui/private/qopenglcontext_p.h> -#include <QtCore/qatomic.h> -#include "qopenglbuffer.h" -#include <private/qopenglextensions_p.h> - -#ifndef GL_CONTEXT_LOST -#define GL_CONTEXT_LOST 0x0507 -#endif - -QT_BEGIN_NAMESPACE - -/*! - \class QOpenGLBuffer - \brief The QOpenGLBuffer class provides functions for creating and managing OpenGL buffer objects. - \since 5.0 - \ingroup painting-3D - \inmodule QtGui - - Buffer objects are created in the OpenGL server so that the - client application can avoid uploading vertices, indices, - texture image data, etc every time they are needed. - - QOpenGLBuffer objects can be copied around as a reference to the - underlying OpenGL buffer object: - - \snippet code/src_gui_opengl_qopenglbuffer.cpp 0 - - QOpenGLBuffer performs a shallow copy when objects are copied in this - manner, but does not implement copy-on-write semantics. The original - object will be affected whenever the copy is modified. -*/ - -/*! - \enum QOpenGLBuffer::Type - This enum defines the type of OpenGL buffer object to create with QOpenGLBuffer. - - \value VertexBuffer Vertex buffer object for use when specifying - vertex arrays. - \value IndexBuffer Index buffer object for use with \c{glDrawElements()}. - \value PixelPackBuffer Pixel pack buffer object for reading pixel - data from the OpenGL server (for example, with \c{glReadPixels()}). - Not supported under OpenGL/ES. - \value PixelUnpackBuffer Pixel unpack buffer object for writing pixel - data to the OpenGL server (for example, with \c{glTexImage2D()}). - Not supported under OpenGL/ES. -*/ - -/*! - \enum QOpenGLBuffer::UsagePattern - This enum defines the usage pattern of a QOpenGLBuffer object. - - \value StreamDraw The data will be set once and used a few times - for drawing operations. Under OpenGL/ES 1.1 this is identical - to StaticDraw. - \value StreamRead The data will be set once and used a few times - for reading data back from the OpenGL server. Not supported - under OpenGL/ES. - \value StreamCopy The data will be set once and used a few times - for reading data back from the OpenGL server for use in further - drawing operations. Not supported under OpenGL/ES. - \value StaticDraw The data will be set once and used many times - for drawing operations. - \value StaticRead The data will be set once and used many times - for reading data back from the OpenGL server. Not supported - under OpenGL/ES. - \value StaticCopy The data will be set once and used many times - for reading data back from the OpenGL server for use in further - drawing operations. Not supported under OpenGL/ES. - \value DynamicDraw The data will be modified repeatedly and used - many times for drawing operations. - \value DynamicRead The data will be modified repeatedly and used - many times for reading data back from the OpenGL server. - Not supported under OpenGL/ES. - \value DynamicCopy The data will be modified repeatedly and used - many times for reading data back from the OpenGL server for - use in further drawing operations. Not supported under OpenGL/ES. -*/ - -/*! - \enum QOpenGLBuffer::Access - This enum defines the access mode for QOpenGLBuffer::map(). - - \value ReadOnly The buffer will be mapped for reading only. - \value WriteOnly The buffer will be mapped for writing only. - \value ReadWrite The buffer will be mapped for reading and writing. -*/ - -/*! - \enum QOpenGLBuffer::RangeAccessFlag - This enum defines the access mode bits for QOpenGLBuffer::mapRange(). - - \value RangeRead The buffer will be mapped for reading. - \value RangeWrite The buffer will be mapped for writing. - \value RangeInvalidate Discard the previous contents of the specified range. - \value RangeInvalidateBuffer Discard the previous contents of the entire buffer. - \value RangeFlushExplicit Indicates that modifications are to be flushed explicitly via \c glFlushMappedBufferRange. - \value RangeUnsynchronized Indicates that pending operations should not be synchronized before returning from mapRange(). -*/ - -class QOpenGLBufferPrivate -{ -public: - QOpenGLBufferPrivate(QOpenGLBuffer::Type t) - : ref(1), - type(t), - guard(nullptr), - usagePattern(QOpenGLBuffer::StaticDraw), - actualUsagePattern(QOpenGLBuffer::StaticDraw), - funcs(nullptr) - { - } - - QAtomicInt ref; - QOpenGLBuffer::Type type; - QOpenGLSharedResourceGuard *guard; - QOpenGLBuffer::UsagePattern usagePattern; - QOpenGLBuffer::UsagePattern actualUsagePattern; - QOpenGLExtensions *funcs; -}; - -/*! - Constructs a new buffer object of type QOpenGLBuffer::VertexBuffer. - - Note: this constructor just creates the QOpenGLBuffer instance. The actual - buffer object in the OpenGL server is not created until create() is called. - - \sa create() -*/ -QOpenGLBuffer::QOpenGLBuffer() - : d_ptr(new QOpenGLBufferPrivate(QOpenGLBuffer::VertexBuffer)) -{ -} - -/*! - Constructs a new buffer object of \a type. - - Note: this constructor just creates the QOpenGLBuffer instance. The actual - buffer object in the OpenGL server is not created until create() is called. - - \sa create() -*/ -QOpenGLBuffer::QOpenGLBuffer(QOpenGLBuffer::Type type) - : d_ptr(new QOpenGLBufferPrivate(type)) -{ -} - -/*! - Constructs a shallow copy of \a other. - - Note: QOpenGLBuffer does not implement copy-on-write semantics, - so \a other will be affected whenever the copy is modified. -*/ -QOpenGLBuffer::QOpenGLBuffer(const QOpenGLBuffer &other) - : d_ptr(other.d_ptr) -{ - d_ptr->ref.ref(); -} - -/*! - Destroys this buffer object, including the storage being - used in the OpenGL server. -*/ -QOpenGLBuffer::~QOpenGLBuffer() -{ - if (!d_ptr->ref.deref()) { - destroy(); - delete d_ptr; - } -} - -/*! - Assigns a shallow copy of \a other to this object. - - Note: QOpenGLBuffer does not implement copy-on-write semantics, - so \a other will be affected whenever the copy is modified. -*/ -QOpenGLBuffer &QOpenGLBuffer::operator=(const QOpenGLBuffer &other) -{ - if (d_ptr != other.d_ptr) { - other.d_ptr->ref.ref(); - if (!d_ptr->ref.deref()) { - destroy(); - delete d_ptr; - } - d_ptr = other.d_ptr; - } - return *this; -} - -/*! - Returns the type of buffer represented by this object. -*/ -QOpenGLBuffer::Type QOpenGLBuffer::type() const -{ - Q_D(const QOpenGLBuffer); - return d->type; -} - -/*! - Returns the usage pattern for this buffer object. - The default value is StaticDraw. - - \sa setUsagePattern() -*/ -QOpenGLBuffer::UsagePattern QOpenGLBuffer::usagePattern() const -{ - Q_D(const QOpenGLBuffer); - return d->usagePattern; -} - -/*! - Sets the usage pattern for this buffer object to \a value. - This function must be called before allocate() or write(). - - \sa usagePattern(), allocate(), write() -*/ -void QOpenGLBuffer::setUsagePattern(QOpenGLBuffer::UsagePattern value) -{ - Q_D(QOpenGLBuffer); - d->usagePattern = d->actualUsagePattern = value; -} - -namespace { - void freeBufferFunc(QOpenGLFunctions *funcs, GLuint id) - { - funcs->glDeleteBuffers(1, &id); - } -} - -/*! - Creates the buffer object in the OpenGL server. Returns \c true if - the object was created; false otherwise. - - This function must be called with a current QOpenGLContext. - The buffer will be bound to and can only be used in - that context (or any other context that is shared with it). - - This function will return false if the OpenGL implementation - does not support buffers, or there is no current QOpenGLContext. - - \sa isCreated(), allocate(), write(), destroy() -*/ -bool QOpenGLBuffer::create() -{ - Q_D(QOpenGLBuffer); - if (d->guard && d->guard->id()) - return true; - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - if (ctx) { - delete d->funcs; - d->funcs = new QOpenGLExtensions(ctx); - GLuint bufferId = 0; - d->funcs->glGenBuffers(1, &bufferId); - if (bufferId) { - if (d->guard) - d->guard->free(); - - d->guard = new QOpenGLSharedResourceGuard(ctx, bufferId, freeBufferFunc); - return true; - } - } - return false; -} - -/*! - Returns \c true if this buffer has been created; false otherwise. - - \sa create(), destroy() -*/ -bool QOpenGLBuffer::isCreated() const -{ - Q_D(const QOpenGLBuffer); - return d->guard && d->guard->id(); -} - -/*! - Destroys this buffer object, including the storage being - used in the OpenGL server. All references to the buffer will - become invalid. -*/ -void QOpenGLBuffer::destroy() -{ - Q_D(QOpenGLBuffer); - if (d->guard) { - d->guard->free(); - d->guard = nullptr; - } - delete d->funcs; - d->funcs = nullptr; -} - -/*! - Reads the \a count bytes in this buffer starting at \a offset - into \a data. Returns \c true on success; false if reading from - the buffer is not supported. Buffer reading is not supported - under OpenGL/ES. - - It is assumed that this buffer has been bound to the current context. - - \sa write(), bind() -*/ -bool QOpenGLBuffer::read(int offset, void *data, int count) -{ -#if !defined(QT_OPENGL_ES) - Q_D(QOpenGLBuffer); - if (!d->funcs->hasOpenGLFeature(QOpenGLFunctions::Buffers) || !d->guard->id()) - return false; - - while (true) { // Clear error state. - GLenum error = d->funcs->glGetError(); - if (error == GL_NO_ERROR) - break; - if (error == GL_CONTEXT_LOST) - return false; - }; - d->funcs->glGetBufferSubData(d->type, offset, count, data); - return d->funcs->glGetError() == GL_NO_ERROR; -#else - Q_UNUSED(offset); - Q_UNUSED(data); - Q_UNUSED(count); - return false; -#endif -} - -/*! - Replaces the \a count bytes of this buffer starting at \a offset - with the contents of \a data. Any other bytes in the buffer - will be left unmodified. - - It is assumed that create() has been called on this buffer and that - it has been bound to the current context. - - \sa create(), read(), allocate() -*/ -void QOpenGLBuffer::write(int offset, const void *data, int count) -{ -#ifndef QT_NO_DEBUG - if (!isCreated()) - qWarning("QOpenGLBuffer::write(): buffer not created"); -#endif - Q_D(QOpenGLBuffer); - if (d->guard && d->guard->id()) - d->funcs->glBufferSubData(d->type, offset, count, data); -} - -/*! - Allocates \a count bytes of space to the buffer, initialized to - the contents of \a data. Any previous contents will be removed. - - It is assumed that create() has been called on this buffer and that - it has been bound to the current context. - - \sa create(), read(), write() -*/ -void QOpenGLBuffer::allocate(const void *data, int count) -{ -#ifndef QT_NO_DEBUG - if (!isCreated()) - qWarning("QOpenGLBuffer::allocate(): buffer not created"); -#endif - Q_D(QOpenGLBuffer); - if (d->guard && d->guard->id()) - d->funcs->glBufferData(d->type, count, data, d->actualUsagePattern); -} - -/*! - \fn void QOpenGLBuffer::allocate(int count) - \overload - - Allocates \a count bytes of space to the buffer. Any previous - contents will be removed. - - It is assumed that create() has been called on this buffer and that - it has been bound to the current context. - - \sa create(), write() -*/ - -/*! - Binds the buffer associated with this object to the current - OpenGL context. Returns \c false if binding was not possible, usually because - type() is not supported on this OpenGL implementation. - - The buffer must be bound to the same QOpenGLContext current when create() - was called, or to another QOpenGLContext that is sharing with it. - Otherwise, false will be returned from this function. - - \sa release(), create() -*/ -bool QOpenGLBuffer::bind() -{ -#ifndef QT_NO_DEBUG - if (!isCreated()) - qWarning("QOpenGLBuffer::bind(): buffer not created"); -#endif - Q_D(const QOpenGLBuffer); - GLuint bufferId = d->guard ? d->guard->id() : 0; - if (bufferId) { - if (d->guard->group() != QOpenGLContextGroup::currentContextGroup()) { -#ifndef QT_NO_DEBUG - qWarning("QOpenGLBuffer::bind: buffer is not valid in the current context"); -#endif - return false; - } - d->funcs->glBindBuffer(d->type, bufferId); - return true; - } else { - return false; - } -} - -/*! - Releases the buffer associated with this object from the - current OpenGL context. - - This function must be called with the same QOpenGLContext current - as when bind() was called on the buffer. - - \sa bind() -*/ -void QOpenGLBuffer::release() -{ -#ifndef QT_NO_DEBUG - if (!isCreated()) - qWarning("QOpenGLBuffer::release(): buffer not created"); -#endif - Q_D(const QOpenGLBuffer); - if (d->guard && d->guard->id()) - d->funcs->glBindBuffer(d->type, 0); -} - -/*! - Releases the buffer associated with \a type in the current - QOpenGLContext. - - This function is a direct call to \c{glBindBuffer(type, 0)} - for use when the caller does not know which QOpenGLBuffer has - been bound to the context but wants to make sure that it - is released. - - \snippet code/src_gui_opengl_qopenglbuffer.cpp 1 -*/ -void QOpenGLBuffer::release(QOpenGLBuffer::Type type) -{ - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - if (ctx) - ctx->functions()->glBindBuffer(GLenum(type), 0); -} - -/*! - Returns the OpenGL identifier associated with this buffer; zero if - the buffer has not been created. - - \sa isCreated() -*/ -GLuint QOpenGLBuffer::bufferId() const -{ - Q_D(const QOpenGLBuffer); - return d->guard ? d->guard->id() : 0; -} - -/*! - Returns the size of the data in this buffer, for reading operations. - Returns -1 if fetching the buffer size is not supported, or the - buffer has not been created. - - It is assumed that this buffer has been bound to the current context. - - \sa isCreated(), bind() -*/ -int QOpenGLBuffer::size() const -{ - Q_D(const QOpenGLBuffer); - if (!d->guard || !d->guard->id()) - return -1; - GLint value = -1; - d->funcs->glGetBufferParameteriv(d->type, GL_BUFFER_SIZE, &value); - return value; -} - -/*! - Maps the contents of this buffer into the application's memory - space and returns a pointer to it. Returns null if memory - mapping is not possible. The \a access parameter indicates the - type of access to be performed. - - It is assumed that create() has been called on this buffer and that - it has been bound to the current context. - - \note This function is only supported under OpenGL ES 2.0 or - earlier if the \c GL_OES_mapbuffer extension is present. - - \note On OpenGL ES 3.0 and newer, or, in case if desktop OpenGL, - if \c GL_ARB_map_buffer_range is supported, this function uses - \c glMapBufferRange instead of \c glMapBuffer. - - \sa unmap(), create(), bind(), mapRange() -*/ -void *QOpenGLBuffer::map(QOpenGLBuffer::Access access) -{ - Q_D(QOpenGLBuffer); -#ifndef QT_NO_DEBUG - if (!isCreated()) - qWarning("QOpenGLBuffer::map(): buffer not created"); -#endif - if (!d->guard || !d->guard->id()) - return nullptr; - if (d->funcs->hasOpenGLExtension(QOpenGLExtensions::MapBufferRange)) { - QOpenGLBuffer::RangeAccessFlags rangeAccess; - switch (access) { - case QOpenGLBuffer::ReadOnly: - rangeAccess = QOpenGLBuffer::RangeRead; - break; - case QOpenGLBuffer::WriteOnly: - rangeAccess = QOpenGLBuffer::RangeWrite; - break; - case QOpenGLBuffer::ReadWrite: - rangeAccess = QOpenGLBuffer::RangeRead | QOpenGLBuffer::RangeWrite; - break; - } - return d->funcs->glMapBufferRange(d->type, 0, size(), rangeAccess); - } else { - return d->funcs->glMapBuffer(d->type, access); - } -} - -/*! - Maps the range specified by \a offset and \a count of the contents - of this buffer into the application's memory space and returns a - pointer to it. Returns null if memory mapping is not possible. - The \a access parameter specifies a combination of access flags. - - It is assumed that create() has been called on this buffer and that - it has been bound to the current context. - - \note This function is not available on OpenGL ES 2.0 and earlier. - - \sa unmap(), create(), bind() - */ -void *QOpenGLBuffer::mapRange(int offset, int count, QOpenGLBuffer::RangeAccessFlags access) -{ - Q_D(QOpenGLBuffer); -#ifndef QT_NO_DEBUG - if (!isCreated()) - qWarning("QOpenGLBuffer::mapRange(): buffer not created"); -#endif - if (!d->guard || !d->guard->id()) - return nullptr; - return d->funcs->glMapBufferRange(d->type, offset, count, access); -} - -/*! - Unmaps the buffer after it was mapped into the application's - memory space with a previous call to map(). Returns \c true if - the unmap succeeded; false otherwise. - - It is assumed that this buffer has been bound to the current context, - and that it was previously mapped with map(). - - \note This function is only supported under OpenGL ES 2.0 and - earlier if the \c{GL_OES_mapbuffer} extension is present. - - \sa map() -*/ -bool QOpenGLBuffer::unmap() -{ - Q_D(QOpenGLBuffer); -#ifndef QT_NO_DEBUG - if (!isCreated()) - qWarning("QOpenGLBuffer::unmap(): buffer not created"); -#endif - if (!d->guard || !d->guard->id()) - return false; - return d->funcs->glUnmapBuffer(d->type) == GL_TRUE; -} - -QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglbuffer.h b/src/gui/opengl/qopenglbuffer.h deleted file mode 100644 index a810783731..0000000000 --- a/src/gui/opengl/qopenglbuffer.h +++ /dev/null @@ -1,145 +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 QOPENGLBUFFER_H -#define QOPENGLBUFFER_H - -#include <QtGui/qtguiglobal.h> - -#ifndef QT_NO_OPENGL - -#include <QtCore/qscopedpointer.h> -#include <QtGui/qopengl.h> - -QT_BEGIN_NAMESPACE - - -class QOpenGLBufferPrivate; - -class Q_GUI_EXPORT QOpenGLBuffer -{ -public: - enum Type - { - VertexBuffer = 0x8892, // GL_ARRAY_BUFFER - IndexBuffer = 0x8893, // GL_ELEMENT_ARRAY_BUFFER - PixelPackBuffer = 0x88EB, // GL_PIXEL_PACK_BUFFER - PixelUnpackBuffer = 0x88EC // GL_PIXEL_UNPACK_BUFFER - }; - - QOpenGLBuffer(); - explicit QOpenGLBuffer(QOpenGLBuffer::Type type); - QOpenGLBuffer(const QOpenGLBuffer &other); - ~QOpenGLBuffer(); - - QOpenGLBuffer &operator=(const QOpenGLBuffer &other); - - enum UsagePattern - { - StreamDraw = 0x88E0, // GL_STREAM_DRAW - StreamRead = 0x88E1, // GL_STREAM_READ - StreamCopy = 0x88E2, // GL_STREAM_COPY - StaticDraw = 0x88E4, // GL_STATIC_DRAW - StaticRead = 0x88E5, // GL_STATIC_READ - StaticCopy = 0x88E6, // GL_STATIC_COPY - DynamicDraw = 0x88E8, // GL_DYNAMIC_DRAW - DynamicRead = 0x88E9, // GL_DYNAMIC_READ - DynamicCopy = 0x88EA // GL_DYNAMIC_COPY - }; - - enum Access - { - ReadOnly = 0x88B8, // GL_READ_ONLY - WriteOnly = 0x88B9, // GL_WRITE_ONLY - ReadWrite = 0x88BA // GL_READ_WRITE - }; - - enum RangeAccessFlag - { - RangeRead = 0x0001, // GL_MAP_READ_BIT - RangeWrite = 0x0002, // GL_MAP_WRITE_BIT - RangeInvalidate = 0x0004, // GL_MAP_INVALIDATE_RANGE_BIT - RangeInvalidateBuffer = 0x0008, // GL_MAP_INVALIDATE_BUFFER_BIT - RangeFlushExplicit = 0x0010, // GL_MAP_FLUSH_EXPLICIT_BIT - RangeUnsynchronized = 0x0020 // GL_MAP_UNSYNCHRONIZED_BIT - }; - Q_DECLARE_FLAGS(RangeAccessFlags, RangeAccessFlag) - - QOpenGLBuffer::Type type() const; - - QOpenGLBuffer::UsagePattern usagePattern() const; - void setUsagePattern(QOpenGLBuffer::UsagePattern value); - - bool create(); - bool isCreated() const; - - void destroy(); - - bool bind(); - void release(); - - static void release(QOpenGLBuffer::Type type); - - GLuint bufferId() const; - - int size() const; - - bool read(int offset, void *data, int count); - void write(int offset, const void *data, int count); - - void allocate(const void *data, int count); - inline void allocate(int count) { allocate(nullptr, count); } - - void *map(QOpenGLBuffer::Access access); - void *mapRange(int offset, int count, QOpenGLBuffer::RangeAccessFlags access); - bool unmap(); - -private: - QOpenGLBufferPrivate *d_ptr; - - Q_DECLARE_PRIVATE(QOpenGLBuffer) -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLBuffer::RangeAccessFlags) - -QT_END_NAMESPACE - -#endif // QT_NO_OPENGL - -#endif diff --git a/src/gui/opengl/qopenglcustomshaderstage.cpp b/src/gui/opengl/qopenglcustomshaderstage.cpp deleted file mode 100644 index a95a0a5767..0000000000 --- a/src/gui/opengl/qopenglcustomshaderstage.cpp +++ /dev/null @@ -1,137 +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 "qopenglcustomshaderstage_p.h" -#include "qopenglengineshadermanager_p.h" -#include "qopenglpaintengine_p.h" -#include <private/qpainter_p.h> - -QT_BEGIN_NAMESPACE - -class QOpenGLCustomShaderStagePrivate -{ -public: - QOpenGLCustomShaderStagePrivate() : - m_manager(nullptr) {} - - QPointer<QOpenGLEngineShaderManager> m_manager; - QByteArray m_source; -}; - - - - -QOpenGLCustomShaderStage::QOpenGLCustomShaderStage() - : d_ptr(new QOpenGLCustomShaderStagePrivate) -{ -} - -QOpenGLCustomShaderStage::~QOpenGLCustomShaderStage() -{ - Q_D(QOpenGLCustomShaderStage); - if (d->m_manager) { - d->m_manager->removeCustomStage(); - d->m_manager->sharedShaders->cleanupCustomStage(this); - } - delete d_ptr; -} - -void QOpenGLCustomShaderStage::setUniformsDirty() -{ - Q_D(QOpenGLCustomShaderStage); - if (d->m_manager) - d->m_manager->setDirty(); // ### Probably a bit overkill! -} - -bool QOpenGLCustomShaderStage::setOnPainter(QPainter* p) -{ - Q_D(QOpenGLCustomShaderStage); - if (p->paintEngine()->type() != QPaintEngine::OpenGL2) { - qWarning("QOpenGLCustomShaderStage::setOnPainter() - paint engine not OpenGL2"); - return false; - } - if (d->m_manager) - qWarning("Custom shader is already set on a painter"); - - QOpenGL2PaintEngineEx *engine = static_cast<QOpenGL2PaintEngineEx*>(p->paintEngine()); - d->m_manager = QOpenGL2PaintEngineExPrivate::shaderManagerForEngine(engine); - Q_ASSERT(d->m_manager); - - d->m_manager->setCustomStage(this); - return true; -} - -void QOpenGLCustomShaderStage::removeFromPainter(QPainter* p) -{ - Q_D(QOpenGLCustomShaderStage); - if (p->paintEngine()->type() != QPaintEngine::OpenGL2) - return; - - QOpenGL2PaintEngineEx *engine = static_cast<QOpenGL2PaintEngineEx*>(p->paintEngine()); - d->m_manager = QOpenGL2PaintEngineExPrivate::shaderManagerForEngine(engine); - Q_ASSERT(d->m_manager); - - // Just set the stage to null, don't call removeCustomStage(). - // This should leave the program in a compiled/linked state - // if the next custom shader stage is this one again. - d->m_manager->setCustomStage(nullptr); - d->m_manager = nullptr; -} - -QByteArray QOpenGLCustomShaderStage::source() const -{ - Q_D(const QOpenGLCustomShaderStage); - return d->m_source; -} - -// Called by the shader manager if another custom shader is attached or -// the manager is deleted -void QOpenGLCustomShaderStage::setInactive() -{ - Q_D(QOpenGLCustomShaderStage); - d->m_manager = nullptr; -} - -void QOpenGLCustomShaderStage::setSource(const QByteArray& s) -{ - Q_D(QOpenGLCustomShaderStage); - d->m_source = s; -} - -QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglcustomshaderstage_p.h b/src/gui/opengl/qopenglcustomshaderstage_p.h deleted file mode 100644 index ce3e9efd23..0000000000 --- a/src/gui/opengl/qopenglcustomshaderstage_p.h +++ /dev/null @@ -1,90 +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 QOPENGL_CUSTOM_SHADER_STAGE_H -#define QOPENGL_CUSTOM_SHADER_STAGE_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtGui/private/qtguiglobal_p.h> -#include <QOpenGLShaderProgram> - -QT_BEGIN_NAMESPACE - - -class QPainter; -class QOpenGLCustomShaderStagePrivate; -class Q_GUI_EXPORT QOpenGLCustomShaderStage -{ - Q_DECLARE_PRIVATE(QOpenGLCustomShaderStage) -public: - QOpenGLCustomShaderStage(); - virtual ~QOpenGLCustomShaderStage(); - virtual void setUniforms(QOpenGLShaderProgram*) {} - - void setUniformsDirty(); - - bool setOnPainter(QPainter*); - void removeFromPainter(QPainter*); - QByteArray source() const; - - void setInactive(); -protected: - void setSource(const QByteArray&); - -private: - QOpenGLCustomShaderStagePrivate* d_ptr; - - Q_DISABLE_COPY_MOVE(QOpenGLCustomShaderStage) -}; - - -QT_END_NAMESPACE - - -#endif diff --git a/src/gui/opengl/qopengldebug.cpp b/src/gui/opengl/qopengldebug.cpp deleted file mode 100644 index 310006feaf..0000000000 --- a/src/gui/opengl/qopengldebug.cpp +++ /dev/null @@ -1,1826 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> -** 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 <QtCore/private/qobject_p.h> -#include <QtCore/qglobal.h> -#include <QtCore/qvarlengtharray.h> -#include <QtGui/qopengl.h> -#include <QtGui/qopenglfunctions.h> -#include <QtGui/qoffscreensurface.h> - -#include "qopengldebug.h" - -QT_BEGIN_NAMESPACE - -/*! - \class QOpenGLDebugMessage - \brief The QOpenGLDebugMessage class wraps an OpenGL debug message. - \inmodule QtGui - \reentrant - \since 5.1 - \ingroup shared - \ingroup painting-3D - - Debug messages are usually created by the OpenGL server and then read by - OpenGL clients (either from the OpenGL internal debug log, or logged in real-time). - A debug message has a textual representation, a vendor-specific numeric id, - a source, a type and a severity. - - It's also possible for applications or third-party libraries and toolkits - to create and insert messages in the debug log. In order to do so, you can use - the createApplicationMessage() or the createThirdPartyMessage() static functions. - - \sa QOpenGLDebugLogger -*/ - -/*! - \class QOpenGLDebugLogger - \brief The QOpenGLDebugLogger enables logging of OpenGL debugging messages. - \inmodule QtGui - \since 5.1 - \ingroup painting-3D - - \tableofcontents - - \section1 Introduction - - OpenGL programming can be very error prone. Most of the time, a single - failing call to OpenGL can cause an entire portion of an application to - stop working, with nothing being drawn on the screen. - - The only way to be sure that no errors are being returned from the OpenGL - implementation is checking with \c{glGetError} after each and every API - call. Moreover, OpenGL errors stack up, therefore glGetError should always - be used in a loop like this: - - \snippet code/src_gui_opengl_qopengldebug.cpp 0 - - If you try to clear the error stack, make sure not just keep going until - GL_NO_ERROR is returned but also break on GL_CONTEXT_LOST as that error - value will keep repeating. - - There are also many other information we are interested in (as application - developers), for instance performance issues, or warnings about using - deprecated APIs. Those kind of messages are not reported through the - ordinary OpenGL error reporting mechanisms. - - QOpenGLDebugLogger aims at addressing these issues by providing access to - the \e{OpenGL debug log}. If your OpenGL implementation supports it (by - exposing the \c{GL_KHR_debug} extension), messages from the OpenGL server - will be either logged in an internal OpenGL log, or passed in "real-time" - to listeners as they're generated from OpenGL. - - QOpenGLDebugLogger supports both these modes of operation. Refer to the - following sections to find out the differences between them. - - \section1 Creating an OpenGL Debug Context - - For efficiency reasons, OpenGL implementations are allowed not to create - any debug output at all, unless the OpenGL context is a debug context. In order - to create a debug context from Qt, you must set the QSurfaceFormat::DebugContext - format option on the QSurfaceFormat used to create the QOpenGLContext object: - - \snippet code/src_gui_opengl_qopengldebug.cpp 1 - - Note that requesting a 3.2 OpenGL Core Profile is just for the example's - purposes; this class is not tied to any specific OpenGL or OpenGL ES - version, as it relies on the availability of the \c{GL_KHR_debug} extension - (see below). - - \section1 Creating and Initializing a QOpenGLDebugLogger - - QOpenGLDebugLogger is a simple QObject-derived class. Just like all QObject - subclasses, you create an instance (and optionally specify a parent - object), and like the other OpenGL functions in Qt you \e{must} initialize - it before usage by calling initialize() whilst there is a current OpenGL context: - - \snippet code/src_gui_opengl_qopengldebug.cpp 2 - - Note that the \c{GL_KHR_debug} extension \e{must} be available in the context - in order to access the messages logged by OpenGL. You can check the - presence of this extension by calling: - - \snippet code/src_gui_opengl_qopengldebug.cpp 3 - - where \c{ctx} is a valid QOpenGLContext. If the extension is not available, - initialize() will return false. - - \section1 Reading the Internal OpenGL Debug Log - - OpenGL implementations keep an internal log of debug messages. Messages - stored in this log can be retrieved by using the loggedMessages() function: - - \snippet code/src_gui_opengl_qopengldebug.cpp 4 - - The internal log has a limited size; when it fills up, older messages will - get discarded to make room for the new incoming messages. When you call - loggedMessages(), the internal log will be emptied as well. - - If you want to be sure not to lose any debug message, you must use real-time - logging instead of calling this function. However, debug messages might - still be generated in the timespan between context creation and activation - of real-time logging (or, in general, when the real-time logging is disabled). - - \section1 Real-time logging of messages - - It is also possible to receive a stream of debug messages from the OpenGL - server \e{as they are generated} by the implementation. In order to do so, - you need to connect a suitable slot to the messageLogged() signal, and - start logging by calling startLogging(): - - \snippet code/src_gui_opengl_qopengldebug.cpp 5 - - Similarly, logging can be disabled at any time by calling the stopLogging() - function. - - Real-time logging can be either asynchronous or synchronous, depending on - the parameter passed to startLogging(). When logging in asynchronous mode - (the default, as it has a very small overhead), the OpenGL implementation - can generate messages at any time, and/or in an order which is different from the - order of the OpenGL commands which caused those messages to be logged. - The messages could also be generated from a thread that it's different from - the thread the context is currently bound to. This is because OpenGL - implementations are usually highly threaded and asynchronous, and therefore - no warranties are made about the relative order and the timings of the - debug messages. - - On the other hand, logging in synchronous mode has a high overhead, but - the OpenGL implementation guarantees that all the messages caused by a - certain command are received in order, before the command returns, - and from the same thread the OpenGL context is bound to. - - This means that when logging in synchronous mode you will be able to run - your OpenGL application in a debugger, put a breakpoint on a slot connected - to the messageLogged() signal, and see in the backtrace the exact call - that caused the logged message. This can be extremely useful to debug - an OpenGL problem. Note that if OpenGL rendering is happening in another - thread, you must force the signal/slot connection type to Qt::DirectConnection - in order to be able to see the actual backtrace. - - Refer to the LoggingMode enum documentation for more information about - logging modes. - - \note When real-time logging is enabled, debug messages will \e{not} be - inserted in the internal OpenGL debug log any more; messages already - present in the internal log will not be deleted, nor they will be emitted - through the messageLogged() signal. Since some messages might be generated - before real-time logging is started (and therefore be kept in the internal - OpenGL log), it is important to always check if it contains any message - after calling startLogging(). - - \section1 Inserting Messages in the Debug Log - - It is possible for applications and libraries to insert custom messages in - the debug log, for instance for marking a group of related OpenGL commands - and therefore being then able to identify eventual messages coming from them. - - In order to do so, you can create a QOpenGLDebugMessage object by calling - \l{QOpenGLDebugMessage::}{createApplicationMessage()} or - \l{QOpenGLDebugMessage::}{createThirdPartyMessage()}, and then inserting it - into the log by calling logMessage(): - - \snippet code/src_gui_opengl_qopengldebug.cpp 6 - - Note that OpenGL implementations have a vendor-specific limit to the length - of the messages that can be inserted in the debug log. You can retrieve - this length by calling the maximumMessageLength() method; messages longer - than the limit will automatically get truncated. - - \section1 Controlling the Debug Output - - QOpenGLDebugMessage is also able to apply filters to the debug messages, and - therefore limit the amount of messages logged. You can enable or disable - logging of messages by calling enableMessages() and disableMessages() - respectively. By default, all messages are logged. - - It is possible to enable or disable messages by selecting them by: - - \list - \li source, type and severity (and including all ids in the selection); - \li id, source and type (and including all severities in the selection). - \endlist - - Note that the "enabled" status for a given message is a property of the - (id, source, type, severity) tuple; the message attributes \e{do not} form - a hierarchy of any kind. You should be careful about the order of the calls - to enableMessages() and disableMessages(), as it will change which - messages will are enabled / disabled. - - It's not possible to filter by the message text itself; applications - have to do that on their own (in slots connected to the messageLogged() - signal, or after fetching the messages in the internal debug log - through loggedMessages()). - - In order to simplify the management of the enabled / disabled statuses, - QOpenGLDebugMessage also supports the concept of \c{debug groups}. A debug - group contains the group of enabled / disabled configurations of debug - messages. Moreover, debug groups are organized in a stack: it is possible - to push and pop groups by calling pushGroup() and popGroup() respectively. - (When an OpenGL context is created, there is already a group in the stack). - - The enableMessages() and disableMessages() functions will modify the - configuration in the current debug group, that is, the one at the top of - the debug groups stack. - - When a new group is pushed onto the debug groups stack, it will inherit - the configuration of the group that was previously on the top of the stack. - Vice versa, popping a debug group will restore the configuration of - the debug group that becomes the new top. - - Pushing (respectively popping) debug groups will also automatically generate - a debug message of type QOpenGLDebugMessage::GroupPushType (respectively - \l{QOpenGLDebugMessage::}{GroupPopType}). - - \sa QOpenGLDebugMessage -*/ - -/*! - \enum QOpenGLDebugMessage::Source - - The Source enum defines the source of the debug message. - - \value InvalidSource - The source of the message is invalid; this is the source of a - default-constructed QOpenGLDebugMessage object. - - \value APISource - The message was generated in response to OpenGL API calls. - - \value WindowSystemSource - The message was generated by the window system. - - \value ShaderCompilerSource - The message was generated by the shader compiler. - - \value ThirdPartySource - The message was generated by a third party, for instance an OpenGL - framework a or debugging toolkit. - - \value ApplicationSource - The message was generated by the application itself. - - \value OtherSource - The message was generated by a source not included in this - enumeration. - - \omitvalue LastSource - - \value AnySource - This value corresponds to a mask of all possible message sources. -*/ - -/*! - \enum QOpenGLDebugMessage::Type - - The Type enum defines the type of the debug message. - - \value InvalidType - The type of the message is invalid; this is the type of a - default-constructed QOpenGLDebugMessage object. - - \value ErrorType - The message represents an error. - - \value DeprecatedBehaviorType - The message represents an usage of deprecated behavior. - - \value UndefinedBehaviorType - The message represents an usage of undefined behavior. - - \value PortabilityType - The message represents an usage of vendor-specific behavior, - that might pose portability concerns. - - \value PerformanceType - The message represents a performance issue. - - \value OtherType - The message represents a type not included in this - enumeration. - - \value MarkerType - The message represents a marker in the debug log. - - \value GroupPushType - The message represents a debug group push operation. - - \value GroupPopType - The message represents a debug group pop operation. - - \omitvalue LastType - - \value AnyType - This value corresponds to a mask of all possible message types. -*/ - -/*! - \enum QOpenGLDebugMessage::Severity - - The Severity enum defines the severity of the debug message. - - \value InvalidSeverity - The severity of the message is invalid; this is the severity of a - default-constructed QOpenGLDebugMessage object. - - \value HighSeverity - The message has a high severity. - - \value MediumSeverity - The message has a medium severity. - - \value LowSeverity - The message has a low severity. - - \value NotificationSeverity - The message is a notification. - - \omitvalue LastSeverity - - \value AnySeverity - This value corresponds to a mask of all possible message severities. -*/ - -/*! - \property QOpenGLDebugLogger::loggingMode - - \brief the logging mode passed to startLogging(). - - Note that logging must have been started or the value of this property - will be meaningless. - - \sa startLogging(), isLogging() -*/ -/*! - \enum QOpenGLDebugLogger::LoggingMode - - The LoggingMode enum defines the logging mode of the logger object. - - \value AsynchronousLogging - Messages from the OpenGL server are logged asynchronously. This means - that messages can be logged some time after the corresponding OpenGL - actions that caused them, and even be received in an out-of-order - fashion, depending on the OpenGL implementation. This mode has a very low - performance penalty, as OpenGL implementations are heavily threaded - and asynchronous by nature. - - \value SynchronousLogging - Messages from the OpenGL server are logged synchronously and - sequentially. This has a severe performance hit, as OpenGL - implementations are very asynchronous by nature; but it's very useful - to debug OpenGL problems, as OpenGL guarantees that the messages - generated by a OpenGL command will be logged before the corresponding - command execution has returned. Therefore, you can install a breakpoint - on the messageLogged() signal and see in the backtrace which OpenGL - command caused it; the only caveat is that if you are using OpenGL from - multiple threads you may need to force direct connection when - connecting to the messageLogged() signal. -*/ - -// When using OpenGL ES 2.0, all the necessary GL_KHR_debug constants are -// provided in qopengles2ext.h. Unfortunately, newer versions of that file -// suffix everything with _KHR which causes extra headache when the goal is -// to have a single piece of code that builds in all our target -// environments. Therefore, try to detect this and use our custom defines -// instead, which we anyway need for OS X. - -#if defined(GL_KHR_debug) && defined(GL_DEBUG_SOURCE_API_KHR) -#define USE_MANUAL_DEFS -#endif - -// Under OSX (at least up to 10.8) we cannot include our copy of glext.h, -// but we use the system-wide one, which unfortunately lacks all the needed -// defines/typedefs. In order to make the code compile, we just add here -// the GL_KHR_debug defines. - -#ifndef GL_KHR_debug -#define GL_KHR_debug 1 -#define USE_MANUAL_DEFS -#endif - -#ifdef USE_MANUAL_DEFS - -#ifndef GL_DEBUG_OUTPUT_SYNCHRONOUS -#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242 -#endif -#ifndef GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH -#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243 -#endif -#ifndef GL_DEBUG_CALLBACK_FUNCTION -#define GL_DEBUG_CALLBACK_FUNCTION 0x8244 -#endif -#ifndef GL_DEBUG_CALLBACK_USER_PARAM -#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245 -#endif -#ifndef GL_DEBUG_SOURCE_API -#define GL_DEBUG_SOURCE_API 0x8246 -#endif -#ifndef GL_DEBUG_SOURCE_WINDOW_SYSTEM -#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247 -#endif -#ifndef GL_DEBUG_SOURCE_SHADER_COMPILER -#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248 -#endif -#ifndef GL_DEBUG_SOURCE_THIRD_PARTY -#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249 -#endif -#ifndef GL_DEBUG_SOURCE_APPLICATION -#define GL_DEBUG_SOURCE_APPLICATION 0x824A -#endif -#ifndef GL_DEBUG_SOURCE_OTHER -#define GL_DEBUG_SOURCE_OTHER 0x824B -#endif -#ifndef GL_DEBUG_TYPE_ERROR -#define GL_DEBUG_TYPE_ERROR 0x824C -#endif -#ifndef GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR -#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D -#endif -#ifndef GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR -#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E -#endif -#ifndef GL_DEBUG_TYPE_PORTABILITY -#define GL_DEBUG_TYPE_PORTABILITY 0x824F -#endif -#ifndef GL_DEBUG_TYPE_PERFORMANCE -#define GL_DEBUG_TYPE_PERFORMANCE 0x8250 -#endif -#ifndef GL_DEBUG_TYPE_OTHER -#define GL_DEBUG_TYPE_OTHER 0x8251 -#endif -#ifndef GL_DEBUG_TYPE_MARKER -#define GL_DEBUG_TYPE_MARKER 0x8268 -#endif -#ifndef GL_DEBUG_TYPE_PUSH_GROUP -#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269 -#endif -#ifndef GL_DEBUG_TYPE_POP_GROUP -#define GL_DEBUG_TYPE_POP_GROUP 0x826A -#endif -#ifndef GL_DEBUG_SEVERITY_NOTIFICATION -#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B -#endif -#ifndef GL_MAX_DEBUG_GROUP_STACK_DEPTH -#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C -#endif -#ifndef GL_DEBUG_GROUP_STACK_DEPTH -#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D -#endif -#ifndef GL_BUFFER -#define GL_BUFFER 0x82E0 -#endif -#ifndef GL_SHADER -#define GL_SHADER 0x82E1 -#endif -#ifndef GL_PROGRAM -#define GL_PROGRAM 0x82E2 -#endif -#ifndef GL_QUERY -#define GL_QUERY 0x82E3 -#endif -#ifndef GL_PROGRAM_PIPELINE -#define GL_PROGRAM_PIPELINE 0x82E4 -#endif -#ifndef GL_SAMPLER -#define GL_SAMPLER 0x82E6 -#endif -#ifndef GL_DISPLAY_LIST -#define GL_DISPLAY_LIST 0x82E7 -#endif -#ifndef GL_MAX_LABEL_LENGTH -#define GL_MAX_LABEL_LENGTH 0x82E8 -#endif -#ifndef GL_MAX_DEBUG_MESSAGE_LENGTH -#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143 -#endif -#ifndef GL_MAX_DEBUG_LOGGED_MESSAGES -#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144 -#endif -#ifndef GL_DEBUG_LOGGED_MESSAGES -#define GL_DEBUG_LOGGED_MESSAGES 0x9145 -#endif -#ifndef GL_DEBUG_SEVERITY_HIGH -#define GL_DEBUG_SEVERITY_HIGH 0x9146 -#endif -#ifndef GL_DEBUG_SEVERITY_MEDIUM -#define GL_DEBUG_SEVERITY_MEDIUM 0x9147 -#endif -#ifndef GL_DEBUG_SEVERITY_LOW -#define GL_DEBUG_SEVERITY_LOW 0x9148 -#endif -#ifndef GL_DEBUG_OUTPUT -#define GL_DEBUG_OUTPUT 0x92E0 -#endif -#ifndef GL_CONTEXT_FLAG_DEBUG_BIT -#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002 -#endif -#ifndef GL_STACK_OVERFLOW -#define GL_STACK_OVERFLOW 0x0503 -#endif -#ifndef GL_STACK_UNDERFLOW -#define GL_STACK_UNDERFLOW 0x0504 -#endif - -typedef void (QOPENGLF_APIENTRY *GLDEBUGPROC)(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const GLchar *message,const GLvoid *userParam); - -#endif /* USE_MANUAL_DEFS */ - - -/*! - \internal -*/ -static QOpenGLDebugMessage::Source qt_messageSourceFromGL(GLenum source) -{ - switch (source) { - case GL_DEBUG_SOURCE_API: - return QOpenGLDebugMessage::APISource; - case GL_DEBUG_SOURCE_WINDOW_SYSTEM: - return QOpenGLDebugMessage::WindowSystemSource; - case GL_DEBUG_SOURCE_SHADER_COMPILER: - return QOpenGLDebugMessage::ShaderCompilerSource; - case GL_DEBUG_SOURCE_THIRD_PARTY: - return QOpenGLDebugMessage::ThirdPartySource; - case GL_DEBUG_SOURCE_APPLICATION: - return QOpenGLDebugMessage::ApplicationSource; - case GL_DEBUG_SOURCE_OTHER: - return QOpenGLDebugMessage::OtherSource; - } - - Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown message source from GL"); - return QOpenGLDebugMessage::OtherSource; -} - -/*! - \internal -*/ -static GLenum qt_messageSourceToGL(QOpenGLDebugMessage::Source source) -{ - switch (source) { - case QOpenGLDebugMessage::InvalidSource: - break; - case QOpenGLDebugMessage::APISource: - return GL_DEBUG_SOURCE_API; - case QOpenGLDebugMessage::WindowSystemSource: - return GL_DEBUG_SOURCE_WINDOW_SYSTEM; - case QOpenGLDebugMessage::ShaderCompilerSource: - return GL_DEBUG_SOURCE_SHADER_COMPILER; - case QOpenGLDebugMessage::ThirdPartySource: - return GL_DEBUG_SOURCE_THIRD_PARTY; - case QOpenGLDebugMessage::ApplicationSource: - return GL_DEBUG_SOURCE_APPLICATION; - case QOpenGLDebugMessage::OtherSource: - return GL_DEBUG_SOURCE_OTHER; - case QOpenGLDebugMessage::AnySource: - break; - } - - Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid message source"); - return GL_DEBUG_SOURCE_OTHER; -} - -/*! - \internal -*/ -static QString qt_messageSourceToString(QOpenGLDebugMessage::Source source) -{ - switch (source) { - case QOpenGLDebugMessage::InvalidSource: - return QStringLiteral("InvalidSource"); - case QOpenGLDebugMessage::APISource: - return QStringLiteral("APISource"); - case QOpenGLDebugMessage::WindowSystemSource: - return QStringLiteral("WindowSystemSource"); - case QOpenGLDebugMessage::ShaderCompilerSource: - return QStringLiteral("ShaderCompilerSource"); - case QOpenGLDebugMessage::ThirdPartySource: - return QStringLiteral("ThirdPartySource"); - case QOpenGLDebugMessage::ApplicationSource: - return QStringLiteral("ApplicationSource"); - case QOpenGLDebugMessage::OtherSource: - return QStringLiteral("OtherSource"); - case QOpenGLDebugMessage::AnySource: - return QStringLiteral("AnySource"); - } - - Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown message source"); - return QString(); -} - -/*! - \internal -*/ -static QOpenGLDebugMessage::Type qt_messageTypeFromGL(GLenum type) -{ - switch (type) { - case GL_DEBUG_TYPE_ERROR: - return QOpenGLDebugMessage::ErrorType; - case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: - return QOpenGLDebugMessage::DeprecatedBehaviorType; - case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: - return QOpenGLDebugMessage::UndefinedBehaviorType; - case GL_DEBUG_TYPE_PORTABILITY: - return QOpenGLDebugMessage::PortabilityType; - case GL_DEBUG_TYPE_PERFORMANCE: - return QOpenGLDebugMessage::PerformanceType; - case GL_DEBUG_TYPE_OTHER: - return QOpenGLDebugMessage::OtherType; - case GL_DEBUG_TYPE_MARKER: - return QOpenGLDebugMessage::MarkerType; - case GL_DEBUG_TYPE_PUSH_GROUP: - return QOpenGLDebugMessage::GroupPushType; - case GL_DEBUG_TYPE_POP_GROUP: - return QOpenGLDebugMessage::GroupPopType; - } - - Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown message type from GL"); - return QOpenGLDebugMessage::OtherType; -} - -/*! - \internal -*/ -static GLenum qt_messageTypeToGL(QOpenGLDebugMessage::Type type) -{ - switch (type) { - case QOpenGLDebugMessage::InvalidType: - break; - case QOpenGLDebugMessage::ErrorType: - return GL_DEBUG_TYPE_ERROR; - case QOpenGLDebugMessage::DeprecatedBehaviorType: - return GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR; - case QOpenGLDebugMessage::UndefinedBehaviorType: - return GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR; - case QOpenGLDebugMessage::PortabilityType: - return GL_DEBUG_TYPE_PORTABILITY; - case QOpenGLDebugMessage::PerformanceType: - return GL_DEBUG_TYPE_PERFORMANCE; - case QOpenGLDebugMessage::OtherType: - return GL_DEBUG_TYPE_OTHER; - case QOpenGLDebugMessage::MarkerType: - return GL_DEBUG_TYPE_MARKER; - case QOpenGLDebugMessage::GroupPushType: - return GL_DEBUG_TYPE_PUSH_GROUP; - case QOpenGLDebugMessage::GroupPopType: - return GL_DEBUG_TYPE_POP_GROUP; - case QOpenGLDebugMessage::AnyType: - break; - } - - Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid message type"); - return GL_DEBUG_TYPE_OTHER; -} - -/*! - \internal -*/ -static QString qt_messageTypeToString(QOpenGLDebugMessage::Type type) -{ - switch (type) { - case QOpenGLDebugMessage::InvalidType: - return QStringLiteral("InvalidType"); - case QOpenGLDebugMessage::ErrorType: - return QStringLiteral("ErrorType"); - case QOpenGLDebugMessage::DeprecatedBehaviorType: - return QStringLiteral("DeprecatedBehaviorType"); - case QOpenGLDebugMessage::UndefinedBehaviorType: - return QStringLiteral("UndefinedBehaviorType"); - case QOpenGLDebugMessage::PortabilityType: - return QStringLiteral("PortabilityType"); - case QOpenGLDebugMessage::PerformanceType: - return QStringLiteral("PerformanceType"); - case QOpenGLDebugMessage::OtherType: - return QStringLiteral("OtherType"); - case QOpenGLDebugMessage::MarkerType: - return QStringLiteral("MarkerType"); - case QOpenGLDebugMessage::GroupPushType: - return QStringLiteral("GroupPushType"); - case QOpenGLDebugMessage::GroupPopType: - return QStringLiteral("GroupPopType"); - case QOpenGLDebugMessage::AnyType: - return QStringLiteral("AnyType"); - } - - Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown message type"); - return QString(); -} - -/*! - \internal -*/ -static QOpenGLDebugMessage::Severity qt_messageSeverityFromGL(GLenum severity) -{ - switch (severity) { - case GL_DEBUG_SEVERITY_HIGH: - return QOpenGLDebugMessage::HighSeverity; - case GL_DEBUG_SEVERITY_MEDIUM: - return QOpenGLDebugMessage::MediumSeverity; - case GL_DEBUG_SEVERITY_LOW: - return QOpenGLDebugMessage::LowSeverity; - case GL_DEBUG_SEVERITY_NOTIFICATION: - return QOpenGLDebugMessage::NotificationSeverity; - } - - Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown message severity from GL"); - return QOpenGLDebugMessage::NotificationSeverity; -} - -/*! - \internal -*/ -static GLenum qt_messageSeverityToGL(QOpenGLDebugMessage::Severity severity) -{ - switch (severity) { - case QOpenGLDebugMessage::InvalidSeverity: - break; - case QOpenGLDebugMessage::HighSeverity: - return GL_DEBUG_SEVERITY_HIGH; - case QOpenGLDebugMessage::MediumSeverity: - return GL_DEBUG_SEVERITY_MEDIUM; - case QOpenGLDebugMessage::LowSeverity: - return GL_DEBUG_SEVERITY_LOW; - case QOpenGLDebugMessage::NotificationSeverity: - return GL_DEBUG_SEVERITY_NOTIFICATION; - case QOpenGLDebugMessage::AnySeverity: - break; - } - - Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid message severity"); - return GL_DEBUG_SEVERITY_NOTIFICATION; -} - -/*! - \internal -*/ -static QString qt_messageSeverityToString(QOpenGLDebugMessage::Severity severity) -{ - switch (severity) { - case QOpenGLDebugMessage::InvalidSeverity: - return QStringLiteral("InvalidSeverity"); - case QOpenGLDebugMessage::HighSeverity: - return QStringLiteral("HighSeverity"); - case QOpenGLDebugMessage::MediumSeverity: - return QStringLiteral("MediumSeverity"); - case QOpenGLDebugMessage::LowSeverity: - return QStringLiteral("LowSeverity"); - case QOpenGLDebugMessage::NotificationSeverity: - return QStringLiteral("NotificationSeverity"); - case QOpenGLDebugMessage::AnySeverity: - return QStringLiteral("AnySeverity"); - } - - Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown message severity"); - return QString(); -} - -class QOpenGLDebugMessagePrivate : public QSharedData -{ -public: - QOpenGLDebugMessagePrivate(); - - QString message; - GLuint id; - QOpenGLDebugMessage::Source source; - QOpenGLDebugMessage::Type type; - QOpenGLDebugMessage::Severity severity; -}; - -/*! - \internal -*/ -QOpenGLDebugMessagePrivate::QOpenGLDebugMessagePrivate() - : message(), - id(0), - source(QOpenGLDebugMessage::InvalidSource), - type(QOpenGLDebugMessage::InvalidType), - severity(QOpenGLDebugMessage::InvalidSeverity) -{ -} - - -/*! - Constructs a debug message with an empty message string, id set to 0, - source set to InvalidSource, type set to InvalidType, and severity set to - InvalidSeverity. - - \note This constructor should not be used to create a debug message; - instead, use the createApplicationMessage() or the createThirdPartyMessage() - static functions. - - \sa createApplicationMessage(), createThirdPartyMessage() -*/ -QOpenGLDebugMessage::QOpenGLDebugMessage() - : d(new QOpenGLDebugMessagePrivate) -{ -} - -/*! - Constructs a debug message as a copy of \a debugMessage. - - \sa operator=() -*/ -QOpenGLDebugMessage::QOpenGLDebugMessage(const QOpenGLDebugMessage &debugMessage) - : d(debugMessage.d) -{ -} - -/*! - Destroys this debug message. -*/ -QOpenGLDebugMessage::~QOpenGLDebugMessage() -{ -} - -/*! - Assigns the message \a debugMessage to this object, and returns a reference - to the copy. -*/ -QOpenGLDebugMessage &QOpenGLDebugMessage::operator=(const QOpenGLDebugMessage &debugMessage) -{ - d = debugMessage.d; - return *this; -} - -/*! - \fn QOpenGLDebugMessage &QOpenGLDebugMessage::operator=(QOpenGLDebugMessage &&debugMessage) - - Move-assigns \a debugMessage to this object. -*/ - -/*! - \fn void QOpenGLDebugMessage::swap(QOpenGLDebugMessage &debugMessage) - - Swaps the message \a debugMessage with this message. This operation is very - fast and never fails. -*/ - -/*! - Returns the source of the debug message. -*/ -QOpenGLDebugMessage::Source QOpenGLDebugMessage::source() const -{ - return d->source; -} - -/*! - Returns the type of the debug message. -*/ -QOpenGLDebugMessage::Type QOpenGLDebugMessage::type() const -{ - return d->type; -} - -/*! - Returns the severity of the debug message. -*/ -QOpenGLDebugMessage::Severity QOpenGLDebugMessage::severity() const -{ - return d->severity; -} - -/*! - Returns the id of the debug message. Ids are generally vendor-specific. -*/ -GLuint QOpenGLDebugMessage::id() const -{ - return d->id; -} - -/*! - Returns the textual message contained by this debug message. -*/ -QString QOpenGLDebugMessage::message() const -{ - return d->message; -} - -/*! - Constructs and returns a debug message with \a text as its text, \a id - as id, \a severity as severity, and \a type as type. The message source - will be set to ApplicationSource. - - \sa QOpenGLDebugLogger::logMessage(), createThirdPartyMessage() -*/ -QOpenGLDebugMessage QOpenGLDebugMessage::createApplicationMessage(const QString &text, - GLuint id, - QOpenGLDebugMessage::Severity severity, - QOpenGLDebugMessage::Type type) -{ - QOpenGLDebugMessage m; - m.d->message = text; - m.d->id = id; - m.d->severity = severity; - m.d->type = type; - m.d->source = ApplicationSource; - return m; -} - -/*! - Constructs and returns a debug message with \a text as its text, \a id - as id, \a severity as severity, and \a type as type. The message source - will be set to ThirdPartySource. - - \sa QOpenGLDebugLogger::logMessage(), createApplicationMessage() -*/ -QOpenGLDebugMessage QOpenGLDebugMessage::createThirdPartyMessage(const QString &text, - GLuint id, - QOpenGLDebugMessage::Severity severity, - QOpenGLDebugMessage::Type type) -{ - QOpenGLDebugMessage m; - m.d->message = text; - m.d->id = id; - m.d->severity = severity; - m.d->type = type; - m.d->source = ThirdPartySource; - return m; -} - -/*! - Returns \c true if this debug message is equal to \a debugMessage, or false - otherwise. Two debugging messages are equal if they have the same textual - message, the same id, the same source, the same type and the same severity. - - \sa operator!=() -*/ -bool QOpenGLDebugMessage::operator==(const QOpenGLDebugMessage &debugMessage) const -{ - return (d == debugMessage.d) - || (d->id == debugMessage.d->id - && d->source == debugMessage.d->source - && d->type == debugMessage.d->type - && d->severity == debugMessage.d->severity - && d->message == debugMessage.d->message); -} - -/*! - \fn bool QOpenGLDebugMessage::operator!=(const QOpenGLDebugMessage &debugMessage) const - - Returns \c true if this message is different from \a debugMessage, or false - otherwise. - - \sa operator==() -*/ - -#ifndef QT_NO_DEBUG_STREAM -/*! - \relates QOpenGLDebugMessage - - Writes the source \a source into the debug object \a debug for debugging - purposes. -*/ -QDebug operator<<(QDebug debug, QOpenGLDebugMessage::Source source) -{ - QDebugStateSaver saver(debug); - debug.nospace() << "QOpenGLDebugMessage::Source(" - << qt_messageSourceToString(source) - << ')'; - return debug; -} - -/*! - \relates QOpenGLDebugMessage - - Writes the type \a type into the debug object \a debug for debugging - purposes. -*/ -QDebug operator<<(QDebug debug, QOpenGLDebugMessage::Type type) -{ - QDebugStateSaver saver(debug); - debug.nospace() << "QOpenGLDebugMessage::Type(" - << qt_messageTypeToString(type) - << ')'; - return debug; -} - -/*! - \relates QOpenGLDebugMessage - - Writes the severity \a severity into the debug object \a debug for debugging - purposes. -*/ -QDebug operator<<(QDebug debug, QOpenGLDebugMessage::Severity severity) -{ - QDebugStateSaver saver(debug); - debug.nospace() << "QOpenGLDebugMessage::Severity(" - << qt_messageSeverityToString(severity) - << ')'; - return debug; -} - -/*! - \relates QOpenGLDebugMessage - - Writes the message \a message into the debug object \a debug for debugging - purposes. -*/ -QDebug operator<<(QDebug debug, const QOpenGLDebugMessage &message) -{ - QDebugStateSaver saver(debug); - debug.nospace() << "QOpenGLDebugMessage(" - << qt_messageSourceToString(message.source()) << ", " - << message.id() << ", " - << message.message() << ", " - << qt_messageSeverityToString(message.severity()) << ", " - << qt_messageTypeToString(message.type()) << ')'; - return debug; - -} -#endif // QT_NO_DEBUG_STREAM - -typedef void (QOPENGLF_APIENTRYP qt_glDebugMessageControl_t)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled); -typedef void (QOPENGLF_APIENTRYP qt_glDebugMessageInsert_t)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf); -typedef void (QOPENGLF_APIENTRYP qt_glDebugMessageCallback_t)(GLDEBUGPROC callback, const void *userParam); -typedef GLuint (QOPENGLF_APIENTRYP qt_glGetDebugMessageLog_t)(GLuint count, GLsizei bufsize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog); -typedef void (QOPENGLF_APIENTRYP qt_glPushDebugGroup_t)(GLenum source, GLuint id, GLsizei length, const GLchar *message); -typedef void (QOPENGLF_APIENTRYP qt_glPopDebugGroup_t)(); -typedef void (QOPENGLF_APIENTRYP qt_glGetPointerv_t)(GLenum pname, GLvoid **params); - -class QOpenGLDebugLoggerPrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QOpenGLDebugLogger) -public: - QOpenGLDebugLoggerPrivate(); - - void handleMessage(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *rawMessage); - void controlDebugMessages(QOpenGLDebugMessage::Sources sources, - QOpenGLDebugMessage::Types types, - QOpenGLDebugMessage::Severities severities, - const QVector<GLuint> &ids, - const QByteArray &callerName, - bool enable); - void _q_contextAboutToBeDestroyed(); - - qt_glDebugMessageControl_t glDebugMessageControl; - qt_glDebugMessageInsert_t glDebugMessageInsert; - qt_glDebugMessageCallback_t glDebugMessageCallback; - qt_glGetDebugMessageLog_t glGetDebugMessageLog; - qt_glPushDebugGroup_t glPushDebugGroup; - qt_glPopDebugGroup_t glPopDebugGroup; - qt_glGetPointerv_t glGetPointerv; - - GLDEBUGPROC oldDebugCallbackFunction; - void *oldDebugCallbackParameter; - QOpenGLContext *context; - GLint maxMessageLength; - QOpenGLDebugLogger::LoggingMode loggingMode; - bool initialized : 1; - bool isLogging : 1; - bool debugWasEnabled : 1; - bool syncDebugWasEnabled : 1; -}; - -/*! - \internal -*/ -QOpenGLDebugLoggerPrivate::QOpenGLDebugLoggerPrivate() - : glDebugMessageControl(nullptr), - glDebugMessageInsert(nullptr), - glDebugMessageCallback(nullptr), - glGetDebugMessageLog(nullptr), - glPushDebugGroup(nullptr), - glPopDebugGroup(nullptr), - oldDebugCallbackFunction(nullptr), - context(nullptr), - maxMessageLength(0), - loggingMode(QOpenGLDebugLogger::AsynchronousLogging), - initialized(false), - isLogging(false), - debugWasEnabled(false), - syncDebugWasEnabled(false) -{ -} - -/*! - \internal -*/ -void QOpenGLDebugLoggerPrivate::handleMessage(GLenum source, - GLenum type, - GLuint id, - GLenum severity, - GLsizei length, - const GLchar *rawMessage) -{ - if (oldDebugCallbackFunction) - oldDebugCallbackFunction(source, type, id, severity, length, rawMessage, oldDebugCallbackParameter); - - QOpenGLDebugMessage message; - - QOpenGLDebugMessagePrivate *messagePrivate = message.d.data(); - messagePrivate->source = qt_messageSourceFromGL(source); - messagePrivate->type = qt_messageTypeFromGL(type); - messagePrivate->id = id; - messagePrivate->severity = qt_messageSeverityFromGL(severity); - // not passing the length to fromUtf8, as some bugged OpenGL drivers - // do not handle the length correctly. Just rely on the message to be NUL terminated. - messagePrivate->message = QString::fromUtf8(rawMessage); - - Q_Q(QOpenGLDebugLogger); - emit q->messageLogged(message); -} - -/*! - \internal -*/ -void QOpenGLDebugLoggerPrivate::controlDebugMessages(QOpenGLDebugMessage::Sources sources, - QOpenGLDebugMessage::Types types, - QOpenGLDebugMessage::Severities severities, - const QVector<GLuint> &ids, - const QByteArray &callerName, - bool enable) -{ - if (!initialized) { - qWarning("QOpenGLDebugLogger::%s(): object must be initialized before enabling/disabling messages", callerName.constData()); - return; - } - if (sources == QOpenGLDebugMessage::InvalidSource) { - qWarning("QOpenGLDebugLogger::%s(): invalid source specified", callerName.constData()); - return; - } - if (types == QOpenGLDebugMessage::InvalidType) { - qWarning("QOpenGLDebugLogger::%s(): invalid type specified", callerName.constData()); - return; - } - if (severities == QOpenGLDebugMessage::InvalidSeverity) { - qWarning("QOpenGLDebugLogger::%s(): invalid severity specified", callerName.constData()); - return; - } - - QVarLengthArray<GLenum, 8> glSources; - QVarLengthArray<GLenum, 8> glTypes; - QVarLengthArray<GLenum, 8> glSeverities; - - if (ids.count() > 0) { - Q_ASSERT(severities == QOpenGLDebugMessage::AnySeverity); - - // The GL_KHR_debug extension says: - // - // - If <count> is greater than zero, then <ids> is an array of <count> - // message IDs for the specified combination of <source> and <type>. In - // this case, if <source> or <type> is DONT_CARE, or <severity> is not - // DONT_CARE, the error INVALID_OPERATION is generated. If <count> is - // zero, the value if <ids> is ignored. - // - // This means we can't convert AnySource or AnyType into DONT_CARE, but we have to roll - // them into individual sources/types. - - if (sources == QOpenGLDebugMessage::AnySource) { - sources = QOpenGLDebugMessage::InvalidSource; - for (uint i = 1; i <= QOpenGLDebugMessage::LastSource; i = i << 1) - sources |= QOpenGLDebugMessage::Source(i); - } - - if (types == QOpenGLDebugMessage::AnyType) { - types = QOpenGLDebugMessage::InvalidType; - for (uint i = 1; i <= QOpenGLDebugMessage::LastType; i = i << 1) - types |= QOpenGLDebugMessage::Type(i); - } - } - -#define CONVERT_TO_GL_DEBUG_MESSAGE_CONTROL_PARAMETERS(type, source, target) \ - if (source == QOpenGLDebugMessage::Any ## type) { \ - target << GL_DONT_CARE; \ - } else { \ - for (uint i = 1; i <= QOpenGLDebugMessage::Last ## type; i = i << 1) \ - if (source.testFlag(QOpenGLDebugMessage:: type (i))) \ - target << qt_message ## type ## ToGL (QOpenGLDebugMessage:: type (i)); \ - } - - CONVERT_TO_GL_DEBUG_MESSAGE_CONTROL_PARAMETERS(Source, sources, glSources) - CONVERT_TO_GL_DEBUG_MESSAGE_CONTROL_PARAMETERS(Type, types, glTypes) - CONVERT_TO_GL_DEBUG_MESSAGE_CONTROL_PARAMETERS(Severity, severities, glSeverities) -#undef CONVERT_TO_GL_DEBUG_MESSAGE_CONTROL_PARAMETERS - - const GLsizei idCount = ids.count(); - // The GL_KHR_debug extension says that if idCount is 0, idPtr must be ignored. - // Unfortunately, some bugged drivers do NOT ignore it, so pass NULL in case. - const GLuint * const idPtr = idCount ? ids.constData() : nullptr; - - for (GLenum source : glSources) - for (GLenum type : glTypes) - for (GLenum severity : glSeverities) - glDebugMessageControl(source, type, severity, idCount, idPtr, GLboolean(enable)); -} - -/*! - \internal -*/ -void QOpenGLDebugLoggerPrivate::_q_contextAboutToBeDestroyed() -{ - Q_ASSERT(context); - - // Re-make our context current somehow, otherwise stopLogging will fail. - - // Save the current context and its surface in case we need to set them back - QOpenGLContext *currentContext = QOpenGLContext::currentContext(); - QSurface *currentSurface = nullptr; - - QScopedPointer<QOffscreenSurface> offscreenSurface; - - if (context != currentContext) { - // Make our old context current on a temporary surface - if (currentContext) - currentSurface = currentContext->surface(); - - offscreenSurface.reset(new QOffscreenSurface); - offscreenSurface->setFormat(context->format()); - offscreenSurface->create(); - if (!context->makeCurrent(offscreenSurface.data())) - qWarning("QOpenGLDebugLoggerPrivate::_q_contextAboutToBeDestroyed(): could not make the owning GL context current for cleanup"); - } - - Q_Q(QOpenGLDebugLogger); - q->stopLogging(); - - if (offscreenSurface) { - // We did change the current context: set it back - if (currentContext) - currentContext->makeCurrent(currentSurface); - else - context->doneCurrent(); - } - - QObject::disconnect(context, SIGNAL(aboutToBeDestroyed()), q, SLOT(_q_contextAboutToBeDestroyed())); - context = nullptr; - initialized = false; -} - -extern "C" { -static void QOPENGLF_APIENTRY qt_opengl_debug_callback(GLenum source, - GLenum type, - GLuint id, - GLenum severity, - GLsizei length, - const GLchar *rawMessage, - const GLvoid *userParam) -{ - QOpenGLDebugLoggerPrivate *loggerPrivate = static_cast<QOpenGLDebugLoggerPrivate *>(const_cast<GLvoid *>(userParam)); - loggerPrivate->handleMessage(source, type, id, severity, length, rawMessage); -} -} - -/*! - Constructs a new logger object with the given \a parent. - - \note The object must be initialized before logging can happen. - - \sa initialize() -*/ -QOpenGLDebugLogger::QOpenGLDebugLogger(QObject *parent) - : QObject(*new QOpenGLDebugLoggerPrivate, parent) -{ - // QOpenGLDebugMessage is going to be mostly used as an argument - // of a cross thread connection, therefore let's ease the life for the users - // and register the type for them. - qRegisterMetaType<QOpenGLDebugMessage>(); -} - -/*! - Destroys the logger object. -*/ -QOpenGLDebugLogger::~QOpenGLDebugLogger() -{ - stopLogging(); -} - -/*! - Initializes the object in the current OpenGL context. The context must - support the \c{GL_KHR_debug} extension for the initialization to succeed. - The object must be initialized before any logging can happen. - - It is safe to call this function multiple times from the same context. - - This function can also be used to change the context of a previously - initialized object; note that in this case the object must not be logging - when you call this function. - - Returns \c true if the logger is successfully initialized; false otherwise. - - \sa QOpenGLContext -*/ -bool QOpenGLDebugLogger::initialize() -{ - QOpenGLContext *context = QOpenGLContext::currentContext(); - if (!context) { - qWarning("QOpenGLDebugLogger::initialize(): no current OpenGL context found."); - return false; - } - - Q_D(QOpenGLDebugLogger); - if (d->context == context) { - // context is non-NULL, d->context is non NULL only on successful initialization. - Q_ASSERT(d->initialized); - return true; - } - - if (d->isLogging) { - qWarning("QOpenGLDebugLogger::initialize(): cannot initialize the object while logging. Please stop the logging first."); - return false; - } - - if (d->context) - disconnect(d->context, SIGNAL(aboutToBeDestroyed()), this, SLOT(_q_contextAboutToBeDestroyed())); - - d->initialized = false; - d->context = nullptr; - - if (!context->hasExtension(QByteArrayLiteral("GL_KHR_debug"))) - return false; - - d->context = context; - connect(d->context, SIGNAL(aboutToBeDestroyed()), this, SLOT(_q_contextAboutToBeDestroyed())); - -#define GET_DEBUG_PROC_ADDRESS(procName) \ - d->procName = reinterpret_cast< qt_ ## procName ## _t >( \ - d->context->getProcAddress(d->context->isOpenGLES() ? (#procName "KHR") : (#procName)) \ - ); - - GET_DEBUG_PROC_ADDRESS(glDebugMessageControl); - GET_DEBUG_PROC_ADDRESS(glDebugMessageInsert); - GET_DEBUG_PROC_ADDRESS(glDebugMessageCallback); - GET_DEBUG_PROC_ADDRESS(glGetDebugMessageLog); - GET_DEBUG_PROC_ADDRESS(glPushDebugGroup); - GET_DEBUG_PROC_ADDRESS(glPopDebugGroup); - GET_DEBUG_PROC_ADDRESS(glGetPointerv) - -#undef GET_DEBUG_PROC_ADDRESS - - QOpenGLContext::currentContext()->functions()->glGetIntegerv(GL_MAX_DEBUG_MESSAGE_LENGTH, &d->maxMessageLength); - -#ifndef QT_NO_DEBUG - if (!d->context->format().testOption(QSurfaceFormat::DebugContext)) { - qWarning("QOpenGLDebugLogger::initialize(): the current context is not a debug context:\n" - " this means that the GL may not generate any debug output at all.\n" - " To avoid this warning, try creating the context with the\n" - " QSurfaceFormat::DebugContext surface format option."); - } -#endif // QT_NO_DEBUG - - d->initialized = true; - return true; -} - -/*! - Returns \c true if this object is currently logging, false otherwise. - - \sa startLogging() -*/ -bool QOpenGLDebugLogger::isLogging() const -{ - Q_D(const QOpenGLDebugLogger); - return d->isLogging; -} - -/*! - Starts logging messages coming from the OpenGL server. When a new message - is received, the signal messageLogged() is emitted, carrying the logged - message as argument. - - \a loggingMode specifies whether the logging must be asynchronous (the default) - or synchronous. - - QOpenGLDebugLogger will record the values of \c{GL_DEBUG_OUTPUT} and - \c{GL_DEBUG_OUTPUT_SYNCHRONOUS} when logging is started, and set them back - when logging is stopped. Moreover, any user-defined OpenGL debug callback - installed when this function is invoked will be restored when logging is - stopped; QOpenGLDebugLogger will ensure that the pre-existing callback will - still be invoked when logging. - - \note It's not possible to change the logging mode without stopping and - starting logging again. This might change in a future version of Qt. - - \note The object must be initialized before logging can happen. - - \sa stopLogging(), initialize() -*/ -void QOpenGLDebugLogger::startLogging(QOpenGLDebugLogger::LoggingMode loggingMode) -{ - Q_D(QOpenGLDebugLogger); - if (!d->initialized) { - qWarning("QOpenGLDebugLogger::startLogging(): object must be initialized before logging can start"); - return; - } - if (d->isLogging) { - qWarning("QOpenGLDebugLogger::startLogging(): this object is already logging"); - return; - } - - d->isLogging = true; - d->loggingMode = loggingMode; - - d->glGetPointerv(GL_DEBUG_CALLBACK_FUNCTION, reinterpret_cast<void **>(&d->oldDebugCallbackFunction)); - d->glGetPointerv(GL_DEBUG_CALLBACK_USER_PARAM, &d->oldDebugCallbackParameter); - - d->glDebugMessageCallback(&qt_opengl_debug_callback, d); - - QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); - d->debugWasEnabled = funcs->glIsEnabled(GL_DEBUG_OUTPUT); - d->syncDebugWasEnabled = funcs->glIsEnabled(GL_DEBUG_OUTPUT_SYNCHRONOUS); - - if (d->loggingMode == SynchronousLogging) - funcs->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - else - funcs->glDisable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - - funcs->glEnable(GL_DEBUG_OUTPUT); -} - -/*! - Returns the logging mode of the object. - - \sa startLogging() -*/ -QOpenGLDebugLogger::LoggingMode QOpenGLDebugLogger::loggingMode() const -{ - Q_D(const QOpenGLDebugLogger); - return d->loggingMode; -} - -/*! - Stops logging messages from the OpenGL server. - - \sa startLogging() -*/ -void QOpenGLDebugLogger::stopLogging() -{ - Q_D(QOpenGLDebugLogger); - if (!d->isLogging) - return; - - QOpenGLContext *currentContext = QOpenGLContext::currentContext(); - if (!currentContext || currentContext != d->context) { - qWarning("QOpenGLDebugLogger::stopLogging(): attempting to stop logging with the wrong OpenGL context current"); - return; - } - - d->isLogging = false; - - d->glDebugMessageCallback(d->oldDebugCallbackFunction, d->oldDebugCallbackParameter); - - QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); - if (!d->debugWasEnabled) - funcs->glDisable(GL_DEBUG_OUTPUT); - - if (d->syncDebugWasEnabled) - funcs->glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); - else - funcs->glDisable(GL_DEBUG_OUTPUT_SYNCHRONOUS); -} - -/*! - Inserts the message \a debugMessage into the OpenGL debug log. This provides - a way for applications or libraries to insert custom messages that can - ease the debugging of OpenGL applications. - - \note \a debugMessage must have QOpenGLDebugMessage::ApplicationSource or - QOpenGLDebugMessage::ThirdPartySource as its source, and a valid - type and severity, otherwise it will not be inserted into the log. - - \note The object must be initialized before logging can happen. - - \sa initialize() -*/ -void QOpenGLDebugLogger::logMessage(const QOpenGLDebugMessage &debugMessage) -{ - Q_D(QOpenGLDebugLogger); - if (!d->initialized) { - qWarning("QOpenGLDebugLogger::logMessage(): object must be initialized before logging messages"); - return; - } - if (debugMessage.source() != QOpenGLDebugMessage::ApplicationSource - && debugMessage.source() != QOpenGLDebugMessage::ThirdPartySource) { - qWarning("QOpenGLDebugLogger::logMessage(): using a message source different from ApplicationSource\n" - " or ThirdPartySource is not supported by GL_KHR_debug. The message will not be logged."); - return; - } - if (debugMessage.type() == QOpenGLDebugMessage::InvalidType - || debugMessage.type() == QOpenGLDebugMessage::AnyType - || debugMessage.severity() == QOpenGLDebugMessage::InvalidSeverity - || debugMessage.severity() == QOpenGLDebugMessage::AnySeverity) { - qWarning("QOpenGLDebugLogger::logMessage(): the message has a non-valid type and/or severity. The message will not be logged."); - return; - } - - const GLenum source = qt_messageSourceToGL(debugMessage.source()); - const GLenum type = qt_messageTypeToGL(debugMessage.type()); - const GLenum severity = qt_messageSeverityToGL(debugMessage.severity()); - QByteArray rawMessage = debugMessage.message().toUtf8(); - rawMessage.append('\0'); - - if (rawMessage.length() > d->maxMessageLength) { - qWarning("QOpenGLDebugLogger::logMessage(): message too long, truncating it\n" - " (%d bytes long, but the GL accepts up to %d bytes)", rawMessage.length(), d->maxMessageLength); - rawMessage.resize(d->maxMessageLength - 1); - rawMessage.append('\0'); - } - - // Don't pass rawMessage.length(), as unfortunately bugged - // OpenGL drivers will eat the trailing NUL in the message. Just rely - // on the message being NUL terminated. - d->glDebugMessageInsert(source, - type, - debugMessage.id(), - severity, - -1, - rawMessage.constData()); -} - -/*! - Pushes a debug group with name \a name, id \a id, and source \a source onto - the debug groups stack. If the group is successfully pushed, OpenGL will - automatically log a message with message \a name, id \a id, source \a - source, type QOpenGLDebugMessage::GroupPushType and severity - QOpenGLDebugMessage::NotificationSeverity. - - The newly pushed group will inherit the same filtering settings of the - group that was on the top of the stack; that is, the filtering will not be - changed by pushing a new group. - - \note The \a source must either be QOpenGLDebugMessage::ApplicationSource or - QOpenGLDebugMessage::ThirdPartySource, otherwise the group will not be pushed. - - \note The object must be initialized before managing debug groups. - - \sa popGroup(), enableMessages(), disableMessages() -*/ -void QOpenGLDebugLogger::pushGroup(const QString &name, GLuint id, QOpenGLDebugMessage::Source source) -{ - Q_D(QOpenGLDebugLogger); - if (!d->initialized) { - qWarning("QOpenGLDebugLogger::pushGroup(): object must be initialized before pushing a debug group"); - return; - } - if (source != QOpenGLDebugMessage::ApplicationSource - && source != QOpenGLDebugMessage::ThirdPartySource) { - qWarning("QOpenGLDebugLogger::pushGroup(): using a source different from ApplicationSource\n" - " or ThirdPartySource is not supported by GL_KHR_debug. The group will not be pushed."); - return; - } - - QByteArray rawName = name.toUtf8(); - rawName.append('\0'); - if (rawName.length() > d->maxMessageLength) { - qWarning("QOpenGLDebugLogger::pushGroup(): group name too long, truncating it\n" - " (%d bytes long, but the GL accepts up to %d bytes)", rawName.length(), d->maxMessageLength); - rawName.resize(d->maxMessageLength - 1); - rawName.append('\0'); - } - - // Don't pass rawMessage.length(), as unfortunately bugged - // OpenGL drivers will eat the trailing NUL in the name. Just rely - // on the name being NUL terminated. - d->glPushDebugGroup(qt_messageSourceToGL(source), id, -1, rawName.constData()); -} - -/*! - Pops the topmost debug group from the debug groups stack. If the group is - successfully popped, OpenGL will automatically log a message with message, - id and source matching those of the popped group, type - QOpenGLDebugMessage::GroupPopType and severity - QOpenGLDebugMessage::NotificationSeverity. - - Popping a debug group will restore the message filtering settings of the - group that becomes the top of the debug groups stack. - - \note The object must be initialized before managing debug groups. - - \sa pushGroup() -*/ -void QOpenGLDebugLogger::popGroup() -{ - Q_D(QOpenGLDebugLogger); - if (!d->initialized) { - qWarning("QOpenGLDebugLogger::pushGroup(): object must be initialized before popping a debug group"); - return; - } - - d->glPopDebugGroup(); -} - -/*! - Enables the logging of messages from the given \a sources, of the given \a - types and with the given \a severities and any message id. - - The logging will be enabled in the current control group. - - \sa disableMessages(), pushGroup(), popGroup() -*/ -void QOpenGLDebugLogger::enableMessages(QOpenGLDebugMessage::Sources sources, - QOpenGLDebugMessage::Types types, - QOpenGLDebugMessage::Severities severities) -{ - Q_D(QOpenGLDebugLogger); - d->controlDebugMessages(sources, - types, - severities, - QVector<GLuint>(), - QByteArrayLiteral("enableMessages"), - true); -} - -/*! - Enables the logging of messages with the given \a ids, from the given \a - sources and of the given \a types and any severity. - - The logging will be enabled in the current control group. - - \sa disableMessages(), pushGroup(), popGroup() -*/ -void QOpenGLDebugLogger::enableMessages(const QVector<GLuint> &ids, - QOpenGLDebugMessage::Sources sources, - QOpenGLDebugMessage::Types types) -{ - Q_D(QOpenGLDebugLogger); - d->controlDebugMessages(sources, - types, - QOpenGLDebugMessage::AnySeverity, - ids, - QByteArrayLiteral("enableMessages"), - true); -} - -/*! - Disables the logging of messages with the given \a sources, of the given \a - types and with the given \a severities and any message id. - - The logging will be disabled in the current control group. - - \sa enableMessages(), pushGroup(), popGroup() -*/ -void QOpenGLDebugLogger::disableMessages(QOpenGLDebugMessage::Sources sources, - QOpenGLDebugMessage::Types types, - QOpenGLDebugMessage::Severities severities) -{ - Q_D(QOpenGLDebugLogger); - d->controlDebugMessages(sources, - types, - severities, - QVector<GLuint>(), - QByteArrayLiteral("disableMessages"), - false); -} - -/*! - Disables the logging of messages with the given \a ids, from the given \a - sources and of the given \a types and any severity. - - The logging will be disabled in the current control group. - - \sa enableMessages(), pushGroup(), popGroup() -*/ -void QOpenGLDebugLogger::disableMessages(const QVector<GLuint> &ids, - QOpenGLDebugMessage::Sources sources, - QOpenGLDebugMessage::Types types) -{ - Q_D(QOpenGLDebugLogger); - d->controlDebugMessages(sources, - types, - QOpenGLDebugMessage::AnySeverity, - ids, - QByteArrayLiteral("disableMessages"), - false); -} - -/*! - Reads all the available messages in the OpenGL internal debug log and - returns them. Moreover, this function will clear the internal debug log, - so that subsequent invocations will not return messages that were - already returned. - - \sa startLogging() -*/ -QList<QOpenGLDebugMessage> QOpenGLDebugLogger::loggedMessages() const -{ - Q_D(const QOpenGLDebugLogger); - if (!d->initialized) { - qWarning("QOpenGLDebugLogger::loggedMessages(): object must be initialized before reading logged messages"); - return QList<QOpenGLDebugMessage>(); - } - - static const GLuint maxMessageCount = 128; - GLuint messagesRead; - GLenum messageSources[maxMessageCount]; - GLenum messageTypes[maxMessageCount]; - GLuint messageIds[maxMessageCount]; - GLenum messageSeverities[maxMessageCount]; - GLsizei messageLengths[maxMessageCount]; - - QByteArray messagesBuffer; - messagesBuffer.resize(maxMessageCount * d->maxMessageLength); - - QList<QOpenGLDebugMessage> messages; - do { - messagesRead = d->glGetDebugMessageLog(maxMessageCount, - GLsizei(messagesBuffer.size()), - messageSources, - messageTypes, - messageIds, - messageSeverities, - messageLengths, - messagesBuffer.data()); - - const char *messagesBufferPtr = messagesBuffer.constData(); - for (GLuint i = 0; i < messagesRead; ++i) { - QOpenGLDebugMessage message; - - QOpenGLDebugMessagePrivate *messagePrivate = message.d.data(); - messagePrivate->source = qt_messageSourceFromGL(messageSources[i]); - messagePrivate->type = qt_messageTypeFromGL(messageTypes[i]); - messagePrivate->id = messageIds[i]; - messagePrivate->severity = qt_messageSeverityFromGL(messageSeverities[i]); - messagePrivate->message = QString::fromUtf8(messagesBufferPtr, messageLengths[i] - 1); - - messagesBufferPtr += messageLengths[i]; - messages << message; - } - } while (messagesRead == maxMessageCount); - - return messages; -} - -/*! - \fn void QOpenGLDebugLogger::messageLogged(const QOpenGLDebugMessage &debugMessage) - - This signal is emitted when a debug message (wrapped by the \a debugMessage - argument) is logged from the OpenGL server. - - Depending on the OpenGL implementation, this signal can be emitted - from other threads than the one(s) the receiver(s) lives in, and even - different from the thread the QOpenGLContext in which this object has - been initialized lives in. Moreover, the signal could be emitted from - multiple threads at the same time. This is normally not a problem, - as Qt will utilize a queued connection for cross-thread signal emissions, - but if you force the connection type to Direct then you must be aware of - the potential races in the slots connected to this signal. - - If logging have been started in SynchronousLogging mode, OpenGL guarantees - that this signal will be emitted from the same thread the QOpenGLContext - has been bound to, and no concurrent invocations will ever happen. - - \note Logging must have been started, or this signal will not be emitted. - - \sa startLogging() -*/ - -/*! - Returns the maximum supported length, in bytes, for the text of the messages - passed to logMessage(). This is also the maximum length of a debug group - name, as pushing or popping groups will automatically log a message with - the debug group name as the message text. - - If a message text is too long, it will be automatically truncated by - QOpenGLDebugLogger. - - \note Message texts are encoded in UTF-8 when they get passed to OpenGL, so - their size in bytes does not usually match the amount of UTF-16 code units, - as returned, for instance, by QString::length(). (It does if the message contains - 7-bit ASCII only data, which is typical for debug messages.) -*/ -qint64 QOpenGLDebugLogger::maximumMessageLength() const -{ - Q_D(const QOpenGLDebugLogger); - if (!d->initialized) { - qWarning("QOpenGLDebugLogger::maximumMessageLength(): object must be initialized before reading the maximum message length"); - return -1; - } - return d->maxMessageLength; -} - - -QT_END_NAMESPACE - -#include "moc_qopengldebug.cpp" diff --git a/src/gui/opengl/qopengldebug.h b/src/gui/opengl/qopengldebug.h deleted file mode 100644 index 7363985d60..0000000000 --- a/src/gui/opengl/qopengldebug.h +++ /dev/null @@ -1,221 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> -** 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 QOPENGLDEBUG_H -#define QOPENGLDEBUG_H - -#include <QtGui/qtguiglobal.h> - -#ifndef QT_NO_OPENGL - -#include <QtCore/qshareddata.h> -#include <QtCore/qflags.h> -#include <QtCore/qlist.h> -#include <QtCore/qvector.h> -#include <QtCore/qmetatype.h> -#include <QtCore/qdebug.h> -#include <QtGui/qopenglcontext.h> - -#if defined(Q_CLANG_QDOC) -#undef GLuint -typedef unsigned int GLuint; -#endif - -QT_BEGIN_NAMESPACE - -class QOpenGLDebugLogger; -class QOpenGLDebugLoggerPrivate; -class QOpenGLDebugMessagePrivate; - -class Q_GUI_EXPORT QOpenGLDebugMessage -{ -public: - enum Source { - InvalidSource = 0x00000000, - APISource = 0x00000001, - WindowSystemSource = 0x00000002, - ShaderCompilerSource = 0x00000004, - ThirdPartySource = 0x00000008, - ApplicationSource = 0x00000010, - OtherSource = 0x00000020, - LastSource = OtherSource, // private API - AnySource = 0xffffffff - }; - Q_DECLARE_FLAGS(Sources, Source) - - enum Type { - InvalidType = 0x00000000, - ErrorType = 0x00000001, - DeprecatedBehaviorType = 0x00000002, - UndefinedBehaviorType = 0x00000004, - PortabilityType = 0x00000008, - PerformanceType = 0x00000010, - OtherType = 0x00000020, - MarkerType = 0x00000040, - GroupPushType = 0x00000080, - GroupPopType = 0x00000100, - LastType = GroupPopType, // private API - AnyType = 0xffffffff - }; - Q_DECLARE_FLAGS(Types, Type) - - enum Severity { - InvalidSeverity = 0x00000000, - HighSeverity = 0x00000001, - MediumSeverity = 0x00000002, - LowSeverity = 0x00000004, - NotificationSeverity = 0x00000008, - LastSeverity = NotificationSeverity, // private API - AnySeverity = 0xffffffff - }; - Q_DECLARE_FLAGS(Severities, Severity) - - QOpenGLDebugMessage(); - QOpenGLDebugMessage(const QOpenGLDebugMessage &debugMessage); - - QOpenGLDebugMessage &operator=(const QOpenGLDebugMessage &debugMessage); - QOpenGLDebugMessage &operator=(QOpenGLDebugMessage &&other) noexcept { swap(other); return *this; } - ~QOpenGLDebugMessage(); - - void swap(QOpenGLDebugMessage &other) noexcept { qSwap(d, other.d); } - - Source source() const; - Type type() const; - Severity severity() const; - GLuint id() const; - QString message() const; - - static QOpenGLDebugMessage createApplicationMessage(const QString &text, - GLuint id = 0, - Severity severity = NotificationSeverity, - Type type = OtherType); - static QOpenGLDebugMessage createThirdPartyMessage(const QString &text, - GLuint id = 0, - Severity severity = NotificationSeverity, - Type type = OtherType); - - bool operator==(const QOpenGLDebugMessage &debugMessage) const; - inline bool operator!=(const QOpenGLDebugMessage &debugMessage) const { return !operator==(debugMessage); } - -private: - friend class QOpenGLDebugLogger; - friend class QOpenGLDebugLoggerPrivate; - QSharedDataPointer<QOpenGLDebugMessagePrivate> d; -}; - -Q_DECLARE_SHARED(QOpenGLDebugMessage) -Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLDebugMessage::Sources) -Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLDebugMessage::Types) -Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLDebugMessage::Severities) - -#ifndef QT_NO_DEBUG_STREAM -Q_GUI_EXPORT QDebug operator<<(QDebug debug, const QOpenGLDebugMessage &message); -Q_GUI_EXPORT QDebug operator<<(QDebug debug, QOpenGLDebugMessage::Source source); -Q_GUI_EXPORT QDebug operator<<(QDebug debug, QOpenGLDebugMessage::Type type); -Q_GUI_EXPORT QDebug operator<<(QDebug debug, QOpenGLDebugMessage::Severity severity); -#endif - -class QOpenGLDebugLoggerPrivate; - -class Q_GUI_EXPORT QOpenGLDebugLogger : public QObject -{ - Q_OBJECT - Q_PROPERTY(LoggingMode loggingMode READ loggingMode) - -public: - enum LoggingMode { - AsynchronousLogging, - SynchronousLogging - }; - Q_ENUM(LoggingMode) - - explicit QOpenGLDebugLogger(QObject *parent = nullptr); - ~QOpenGLDebugLogger(); - - bool initialize(); - - bool isLogging() const; - LoggingMode loggingMode() const; - - qint64 maximumMessageLength() const; - - void pushGroup(const QString &name, - GLuint id = 0, - QOpenGLDebugMessage::Source source = QOpenGLDebugMessage::ApplicationSource); - void popGroup(); - - void enableMessages(QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, - QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType, - QOpenGLDebugMessage::Severities severities = QOpenGLDebugMessage::AnySeverity); - - void enableMessages(const QVector<GLuint> &ids, - QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, - QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType); - - void disableMessages(QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, - QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType, - QOpenGLDebugMessage::Severities severities = QOpenGLDebugMessage::AnySeverity); - - void disableMessages(const QVector<GLuint> &ids, - QOpenGLDebugMessage::Sources sources = QOpenGLDebugMessage::AnySource, - QOpenGLDebugMessage::Types types = QOpenGLDebugMessage::AnyType); - - QList<QOpenGLDebugMessage> loggedMessages() const; - -public Q_SLOTS: - void logMessage(const QOpenGLDebugMessage &debugMessage); - void startLogging(LoggingMode loggingMode = AsynchronousLogging); - void stopLogging(); - -Q_SIGNALS: - void messageLogged(const QOpenGLDebugMessage &debugMessage); - -private: - Q_DISABLE_COPY(QOpenGLDebugLogger) - Q_DECLARE_PRIVATE(QOpenGLDebugLogger) - Q_PRIVATE_SLOT(d_func(), void _q_contextAboutToBeDestroyed()) -}; - -QT_END_NAMESPACE - -Q_DECLARE_METATYPE(QOpenGLDebugMessage) - -#endif // QT_NO_OPENGL - -#endif // QOPENGLDEBUG_H diff --git a/src/gui/opengl/qopenglengineshadermanager.cpp b/src/gui/opengl/qopenglengineshadermanager.cpp deleted file mode 100644 index a569975486..0000000000 --- a/src/gui/opengl/qopenglengineshadermanager.cpp +++ /dev/null @@ -1,898 +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 "qopenglengineshadermanager_p.h" -#include "qopenglengineshadersource_p.h" -#include "qopenglpaintengine_p.h" -#include "qopenglshadercache_p.h" - -#include <QtGui/private/qopenglcontext_p.h> -#include <QtCore/qthreadstorage.h> - -#include <algorithm> - -#if defined(QT_DEBUG) -#include <QMetaEnum> -#endif - -// #define QT_GL_SHARED_SHADER_DEBUG - -QT_BEGIN_NAMESPACE - -class QOpenGLEngineSharedShadersResource : public QOpenGLSharedResource -{ -public: - QOpenGLEngineSharedShadersResource(QOpenGLContext *ctx) - : QOpenGLSharedResource(ctx->shareGroup()) - , m_shaders(new QOpenGLEngineSharedShaders(ctx)) - { - } - - ~QOpenGLEngineSharedShadersResource() - { - delete m_shaders; - } - - void invalidateResource() override - { - delete m_shaders; - m_shaders = nullptr; - } - - void freeResource(QOpenGLContext *) override - { - } - - QOpenGLEngineSharedShaders *shaders() const { return m_shaders; } - -private: - QOpenGLEngineSharedShaders *m_shaders; -}; - -class QOpenGLShaderStorage -{ -public: - QOpenGLEngineSharedShaders *shadersForThread(QOpenGLContext *context) { - QOpenGLMultiGroupSharedResource *&shaders = m_storage.localData(); - if (!shaders) - shaders = new QOpenGLMultiGroupSharedResource; - QOpenGLEngineSharedShadersResource *resource = - shaders->value<QOpenGLEngineSharedShadersResource>(context); - return resource ? resource->shaders() : nullptr; - } - -private: - QThreadStorage<QOpenGLMultiGroupSharedResource *> m_storage; -}; - -Q_GLOBAL_STATIC(QOpenGLShaderStorage, qt_shader_storage); - -QOpenGLEngineSharedShaders *QOpenGLEngineSharedShaders::shadersForContext(QOpenGLContext *context) -{ - return qt_shader_storage()->shadersForThread(context); -} - -const char* QOpenGLEngineSharedShaders::qShaderSnippets[] = { - 0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0 -}; - -QOpenGLEngineSharedShaders::QOpenGLEngineSharedShaders(QOpenGLContext* context) - : blitShaderProg(nullptr) - , simpleShaderProg(nullptr) -{ - -/* - Rather than having the shader source array statically initialised, it is initialised - here instead. This is to allow new shader names to be inserted or existing names moved - around without having to change the order of the glsl strings. It is hoped this will - make future hard-to-find runtime bugs more obvious and generally give more solid code. -*/ - - // Check if the user has requested an OpenGL 3.2 Core Profile or higher - // and if so use GLSL 1.50 core shaders instead of legacy ones. - const QSurfaceFormat &fmt = context->format(); - const bool isCoreProfile = fmt.profile() == QSurfaceFormat::CoreProfile && fmt.version() >= qMakePair(3,2); - - const char** code = qShaderSnippets; // shortcut - - if (isCoreProfile) { - code[MainVertexShader] = qopenglslMainVertexShader_core; - code[MainWithTexCoordsVertexShader] = qopenglslMainWithTexCoordsVertexShader_core; - code[MainWithTexCoordsAndOpacityVertexShader] = qopenglslMainWithTexCoordsAndOpacityVertexShader_core; - - code[UntransformedPositionVertexShader] = qopenglslUntransformedPositionVertexShader_core; - code[PositionOnlyVertexShader] = qopenglslPositionOnlyVertexShader_core; - code[ComplexGeometryPositionOnlyVertexShader] = qopenglslComplexGeometryPositionOnlyVertexShader_core; - code[PositionWithPatternBrushVertexShader] = qopenglslPositionWithPatternBrushVertexShader_core; - code[PositionWithLinearGradientBrushVertexShader] = qopenglslPositionWithLinearGradientBrushVertexShader_core; - code[PositionWithConicalGradientBrushVertexShader] = qopenglslPositionWithConicalGradientBrushVertexShader_core; - code[PositionWithRadialGradientBrushVertexShader] = qopenglslPositionWithRadialGradientBrushVertexShader_core; - code[PositionWithTextureBrushVertexShader] = qopenglslPositionWithTextureBrushVertexShader_core; - code[AffinePositionWithPatternBrushVertexShader] = qopenglslAffinePositionWithPatternBrushVertexShader_core; - code[AffinePositionWithLinearGradientBrushVertexShader] = qopenglslAffinePositionWithLinearGradientBrushVertexShader_core; - code[AffinePositionWithConicalGradientBrushVertexShader] = qopenglslAffinePositionWithConicalGradientBrushVertexShader_core; - code[AffinePositionWithRadialGradientBrushVertexShader] = qopenglslAffinePositionWithRadialGradientBrushVertexShader_core; - code[AffinePositionWithTextureBrushVertexShader] = qopenglslAffinePositionWithTextureBrushVertexShader_core; - - code[MainFragmentShader_MO] = qopenglslMainFragmentShader_MO_core; - code[MainFragmentShader_M] = qopenglslMainFragmentShader_M_core; - code[MainFragmentShader_O] = qopenglslMainFragmentShader_O_core; - code[MainFragmentShader] = qopenglslMainFragmentShader_core; - code[MainFragmentShader_ImageArrays] = qopenglslMainFragmentShader_ImageArrays_core; - - code[ImageSrcFragmentShader] = qopenglslImageSrcFragmentShader_core; - code[ImageSrcWithPatternFragmentShader] = qopenglslImageSrcWithPatternFragmentShader_core; - code[NonPremultipliedImageSrcFragmentShader] = qopenglslNonPremultipliedImageSrcFragmentShader_core; - code[GrayscaleImageSrcFragmentShader] = qopenglslGrayscaleImageSrcFragmentShader_core; - code[AlphaImageSrcFragmentShader] = qopenglslAlphaImageSrcFragmentShader_core; - code[CustomImageSrcFragmentShader] = qopenglslCustomSrcFragmentShader_core; // Calls "customShader", which must be appended - code[SolidBrushSrcFragmentShader] = qopenglslSolidBrushSrcFragmentShader_core; - - code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader_core; - code[TextureBrushSrcWithPatternFragmentShader] = qopenglslTextureBrushSrcWithPatternFragmentShader_core; - code[PatternBrushSrcFragmentShader] = qopenglslPatternBrushSrcFragmentShader_core; - code[LinearGradientBrushSrcFragmentShader] = qopenglslLinearGradientBrushSrcFragmentShader_core; - code[RadialGradientBrushSrcFragmentShader] = qopenglslRadialGradientBrushSrcFragmentShader_core; - code[ConicalGradientBrushSrcFragmentShader] = qopenglslConicalGradientBrushSrcFragmentShader_core; - code[ShockingPinkSrcFragmentShader] = qopenglslShockingPinkSrcFragmentShader_core; - - code[NoMaskFragmentShader] = ""; - code[MaskFragmentShader] = qopenglslMaskFragmentShader_core; - code[RgbMaskFragmentShaderPass1] = qopenglslRgbMaskFragmentShaderPass1_core; - code[RgbMaskFragmentShaderPass2] = qopenglslRgbMaskFragmentShaderPass2_core; - code[RgbMaskWithGammaFragmentShader] = ""; //### - } else { - code[MainVertexShader] = qopenglslMainVertexShader; - code[MainWithTexCoordsVertexShader] = qopenglslMainWithTexCoordsVertexShader; - code[MainWithTexCoordsAndOpacityVertexShader] = qopenglslMainWithTexCoordsAndOpacityVertexShader; - - code[UntransformedPositionVertexShader] = qopenglslUntransformedPositionVertexShader; - code[PositionOnlyVertexShader] = qopenglslPositionOnlyVertexShader; - code[ComplexGeometryPositionOnlyVertexShader] = qopenglslComplexGeometryPositionOnlyVertexShader; - code[PositionWithPatternBrushVertexShader] = qopenglslPositionWithPatternBrushVertexShader; - code[PositionWithLinearGradientBrushVertexShader] = qopenglslPositionWithLinearGradientBrushVertexShader; - code[PositionWithConicalGradientBrushVertexShader] = qopenglslPositionWithConicalGradientBrushVertexShader; - code[PositionWithRadialGradientBrushVertexShader] = qopenglslPositionWithRadialGradientBrushVertexShader; - code[PositionWithTextureBrushVertexShader] = qopenglslPositionWithTextureBrushVertexShader; - code[AffinePositionWithPatternBrushVertexShader] = qopenglslAffinePositionWithPatternBrushVertexShader; - code[AffinePositionWithLinearGradientBrushVertexShader] = qopenglslAffinePositionWithLinearGradientBrushVertexShader; - code[AffinePositionWithConicalGradientBrushVertexShader] = qopenglslAffinePositionWithConicalGradientBrushVertexShader; - code[AffinePositionWithRadialGradientBrushVertexShader] = qopenglslAffinePositionWithRadialGradientBrushVertexShader; - code[AffinePositionWithTextureBrushVertexShader] = qopenglslAffinePositionWithTextureBrushVertexShader; - - code[MainFragmentShader_MO] = qopenglslMainFragmentShader_MO; - code[MainFragmentShader_M] = qopenglslMainFragmentShader_M; - code[MainFragmentShader_O] = qopenglslMainFragmentShader_O; - code[MainFragmentShader] = qopenglslMainFragmentShader; - code[MainFragmentShader_ImageArrays] = qopenglslMainFragmentShader_ImageArrays; - - code[ImageSrcFragmentShader] = qopenglslImageSrcFragmentShader; - code[ImageSrcWithPatternFragmentShader] = qopenglslImageSrcWithPatternFragmentShader; - code[NonPremultipliedImageSrcFragmentShader] = qopenglslNonPremultipliedImageSrcFragmentShader; - code[GrayscaleImageSrcFragmentShader] = qopenglslGrayscaleImageSrcFragmentShader; - code[AlphaImageSrcFragmentShader] = qopenglslAlphaImageSrcFragmentShader; - code[CustomImageSrcFragmentShader] = qopenglslCustomSrcFragmentShader; // Calls "customShader", which must be appended - code[SolidBrushSrcFragmentShader] = qopenglslSolidBrushSrcFragmentShader; - code[TextureBrushSrcFragmentShader] = qopenglslTextureBrushSrcFragmentShader; - code[TextureBrushSrcWithPatternFragmentShader] = qopenglslTextureBrushSrcWithPatternFragmentShader; - code[PatternBrushSrcFragmentShader] = qopenglslPatternBrushSrcFragmentShader; - code[LinearGradientBrushSrcFragmentShader] = qopenglslLinearGradientBrushSrcFragmentShader; - code[RadialGradientBrushSrcFragmentShader] = qopenglslRadialGradientBrushSrcFragmentShader; - code[ConicalGradientBrushSrcFragmentShader] = qopenglslConicalGradientBrushSrcFragmentShader; - code[ShockingPinkSrcFragmentShader] = qopenglslShockingPinkSrcFragmentShader; - - code[NoMaskFragmentShader] = ""; - code[MaskFragmentShader] = qopenglslMaskFragmentShader; - code[RgbMaskFragmentShaderPass1] = qopenglslRgbMaskFragmentShaderPass1; - code[RgbMaskFragmentShaderPass2] = qopenglslRgbMaskFragmentShaderPass2; - code[RgbMaskWithGammaFragmentShader] = ""; //### - } - - // The composition shaders are just layout qualifiers and the same - // for all profiles that support them. - code[NoCompositionModeFragmentShader] = ""; - code[MultiplyCompositionModeFragmentShader] = qopenglslMultiplyCompositionModeFragmentShader; - code[ScreenCompositionModeFragmentShader] = qopenglslScreenCompositionModeFragmentShader; - code[OverlayCompositionModeFragmentShader] = qopenglslOverlayCompositionModeFragmentShader; - code[DarkenCompositionModeFragmentShader] = qopenglslDarkenCompositionModeFragmentShader; - code[LightenCompositionModeFragmentShader] = qopenglslLightenCompositionModeFragmentShader; - code[ColorDodgeCompositionModeFragmentShader] = qopenglslColorDodgeCompositionModeFragmentShader; - code[ColorBurnCompositionModeFragmentShader] = qopenglslColorBurnCompositionModeFragmentShader; - code[HardLightCompositionModeFragmentShader] = qopenglslHardLightCompositionModeFragmentShader; - code[SoftLightCompositionModeFragmentShader] = qopenglslSoftLightCompositionModeFragmentShader; - code[DifferenceCompositionModeFragmentShader] = qopenglslDifferenceCompositionModeFragmentShader; - code[ExclusionCompositionModeFragmentShader] = qopenglslExclusionCompositionModeFragmentShader; - -#if defined(QT_DEBUG) - // Check that all the elements have been filled: - for (int i = 0; i < TotalSnippetCount; ++i) { - if (Q_UNLIKELY(!qShaderSnippets[i])) { - qFatal("Shader snippet for %s (#%d) is missing!", - snippetNameStr(SnippetName(i)).constData(), i); - } - } -#endif - - QByteArray vertexSource; - QByteArray fragSource; - - // Compile up the simple shader: -#ifdef Q_OS_WASM - vertexSource.append(qShaderSnippets[PositionOnlyVertexShader]); - vertexSource.append(qShaderSnippets[MainVertexShader]); -#else - vertexSource.append(qShaderSnippets[MainVertexShader]); - vertexSource.append(qShaderSnippets[PositionOnlyVertexShader]); -#endif - fragSource.append(qShaderSnippets[MainFragmentShader]); - fragSource.append(qShaderSnippets[ShockingPinkSrcFragmentShader]); - - simpleShaderProg = new QOpenGLShaderProgram; - - CachedShader simpleShaderCache(fragSource, vertexSource); - - bool inCache = simpleShaderCache.load(simpleShaderProg, context); - - if (!inCache) { - if (!simpleShaderProg->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vertexSource)) - qWarning("Vertex shader for simpleShaderProg (MainVertexShader & PositionOnlyVertexShader) failed to compile"); - if (!simpleShaderProg->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fragSource)) - qWarning("Fragment shader for simpleShaderProg (MainFragmentShader & ShockingPinkSrcFragmentShader) failed to compile"); - - simpleShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); - simpleShaderProg->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR); - simpleShaderProg->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR); - simpleShaderProg->bindAttributeLocation("pmvMatrix3", QT_PMV_MATRIX_3_ATTR); - } - - simpleShaderProg->link(); - - if (Q_UNLIKELY(!simpleShaderProg->isLinked())) { - qCritical("Errors linking simple shader: %s", qPrintable(simpleShaderProg->log())); - } else { - if (!inCache) - simpleShaderCache.store(simpleShaderProg, context); - } - - // Compile the blit shader: - vertexSource.clear(); - vertexSource.append(qShaderSnippets[MainWithTexCoordsVertexShader]); - vertexSource.append(qShaderSnippets[UntransformedPositionVertexShader]); - - fragSource.clear(); - fragSource.append(qShaderSnippets[MainFragmentShader]); - fragSource.append(qShaderSnippets[ImageSrcFragmentShader]); - - blitShaderProg = new QOpenGLShaderProgram; - - CachedShader blitShaderCache(fragSource, vertexSource); - - inCache = blitShaderCache.load(blitShaderProg, context); - - if (!inCache) { - if (!blitShaderProg->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vertexSource)) - qWarning("Vertex shader for blitShaderProg (MainWithTexCoordsVertexShader & UntransformedPositionVertexShader) failed to compile"); - if (!blitShaderProg->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fragSource)) - qWarning("Fragment shader for blitShaderProg (MainFragmentShader & ImageSrcFragmentShader) failed to compile"); - - blitShaderProg->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); - blitShaderProg->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); - } - - blitShaderProg->link(); - if (Q_UNLIKELY(!blitShaderProg->isLinked())) { - qCritical("Errors linking blit shader: %s", qPrintable(blitShaderProg->log())); - } else { - if (!inCache) - blitShaderCache.store(blitShaderProg, context); - } - -#ifdef QT_GL_SHARED_SHADER_DEBUG - qDebug(" -> QOpenGLEngineSharedShaders() %p for thread %p.", this, QThread::currentThread()); -#endif -} - -QOpenGLEngineSharedShaders::~QOpenGLEngineSharedShaders() -{ -#ifdef QT_GL_SHARED_SHADER_DEBUG - qDebug(" -> ~QOpenGLEngineSharedShaders() %p for thread %p.", this, QThread::currentThread()); -#endif - qDeleteAll(cachedPrograms); - cachedPrograms.clear(); - - if (blitShaderProg) { - delete blitShaderProg; - blitShaderProg = nullptr; - } - - if (simpleShaderProg) { - delete simpleShaderProg; - simpleShaderProg = nullptr; - } -} - -#if defined (QT_DEBUG) -QByteArray QOpenGLEngineSharedShaders::snippetNameStr(SnippetName name) -{ - QMetaEnum m = staticMetaObject.enumerator(staticMetaObject.indexOfEnumerator("SnippetName")); - return QByteArray(m.valueToKey(name)); -} -#endif - -// The address returned here will only be valid until next time this function is called. -// The program is return bound. -QOpenGLEngineShaderProg *QOpenGLEngineSharedShaders::findProgramInCache(const QOpenGLEngineShaderProg &prog) -{ - for (int i = 0; i < cachedPrograms.size(); ++i) { - QOpenGLEngineShaderProg *cachedProg = cachedPrograms[i]; - if (*cachedProg == prog) { - // Move the program to the top of the list as a poor-man's cache algo - cachedPrograms.move(i, 0); - cachedProg->program->bind(); - return cachedProg; - } - } - - QScopedPointer<QOpenGLEngineShaderProg> newProg; - - do { - QByteArray fragSource; - // Insert the custom stage before the srcPixel shader to work around an ATI driver bug - // where you cannot forward declare a function that takes a sampler as argument. - if (prog.srcPixelFragShader == CustomImageSrcFragmentShader) - fragSource.append(prog.customStageSource); - fragSource.append(qShaderSnippets[prog.mainFragShader]); - fragSource.append(qShaderSnippets[prog.srcPixelFragShader]); - if (prog.compositionFragShader) - fragSource.append(qShaderSnippets[prog.compositionFragShader]); - if (prog.maskFragShader) - fragSource.append(qShaderSnippets[prog.maskFragShader]); - - QByteArray vertexSource; -#ifdef Q_OS_WASM - vertexSource.append(qShaderSnippets[prog.positionVertexShader]); - vertexSource.append(qShaderSnippets[prog.mainVertexShader]); -#else - vertexSource.append(qShaderSnippets[prog.mainVertexShader]); - vertexSource.append(qShaderSnippets[prog.positionVertexShader]); -#endif - QScopedPointer<QOpenGLShaderProgram> shaderProgram(new QOpenGLShaderProgram); - - CachedShader shaderCache(fragSource, vertexSource); - bool inCache = shaderCache.load(shaderProgram.data(), QOpenGLContext::currentContext()); - - if (!inCache) { - if (!shaderProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vertexSource)) { - QByteArray description; -#if defined(QT_DEBUG) - description.append("Vertex shader: main="); - description.append(snippetNameStr(prog.mainVertexShader)); - description.append(", position="); - description.append(snippetNameStr(prog.positionVertexShader)); -#endif - qWarning("Warning: \"%s\" failed to compile!", description.constData()); - break; - } - if (!shaderProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fragSource)) { - QByteArray description; -#if defined(QT_DEBUG) - description.append("Fragment shader: main="); - description.append(snippetNameStr(prog.mainFragShader)); - description.append(", srcPixel="); - description.append(snippetNameStr(prog.srcPixelFragShader)); - if (prog.compositionFragShader) { - description.append(", composition="); - description.append(snippetNameStr(prog.compositionFragShader)); - } - if (prog.maskFragShader) { - description.append(", mask="); - description.append(snippetNameStr(prog.maskFragShader)); - } -#endif - qWarning("Warning: \"%s\" failed to compile!", description.constData()); - break; - } - - // We have to bind the vertex attribute names before the program is linked: - shaderProgram->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); - if (prog.useTextureCoords) - shaderProgram->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); - if (prog.useOpacityAttribute) - shaderProgram->bindAttributeLocation("opacityArray", QT_OPACITY_ATTR); - if (prog.usePmvMatrixAttribute) { - shaderProgram->bindAttributeLocation("pmvMatrix1", QT_PMV_MATRIX_1_ATTR); - shaderProgram->bindAttributeLocation("pmvMatrix2", QT_PMV_MATRIX_2_ATTR); - shaderProgram->bindAttributeLocation("pmvMatrix3", QT_PMV_MATRIX_3_ATTR); - } - } - - newProg.reset(new QOpenGLEngineShaderProg(prog)); - newProg->program = shaderProgram.take(); - - newProg->program->link(); - if (newProg->program->isLinked()) { - if (!inCache) - shaderCache.store(newProg->program, QOpenGLContext::currentContext()); - } else { - QString error; - error = QLatin1String("Shader program failed to link") - + QLatin1String(" Error Log:\n") - + QLatin1String(" ") + newProg->program->log(); - qWarning() << error; - break; - } - - newProg->program->bind(); - - if (newProg->maskFragShader != QOpenGLEngineSharedShaders::NoMaskFragmentShader) { - GLuint location = newProg->program->uniformLocation("maskTexture"); - newProg->program->setUniformValue(location, QT_MASK_TEXTURE_UNIT); - } - - if (cachedPrograms.count() > 30) { - // The cache is full, so delete the last 5 programs in the list. - // These programs will be least used, as a program us bumped to - // the top of the list when it's used. - for (int i = 0; i < 5; ++i) { - delete cachedPrograms.last(); - cachedPrograms.removeLast(); - } - } - - cachedPrograms.insert(0, newProg.data()); - } while (false); - - return newProg.take(); -} - -void QOpenGLEngineSharedShaders::cleanupCustomStage(QOpenGLCustomShaderStage* stage) -{ - auto hasStageAsCustomShaderSouce = [stage](QOpenGLEngineShaderProg *cachedProg) -> bool { - if (cachedProg->customStageSource == stage->source()) { - delete cachedProg; - return true; - } - return false; - }; - cachedPrograms.erase(std::remove_if(cachedPrograms.begin(), cachedPrograms.end(), - hasStageAsCustomShaderSouce), - cachedPrograms.end()); -} - - -QOpenGLEngineShaderManager::QOpenGLEngineShaderManager(QOpenGLContext* context) - : ctx(context), - shaderProgNeedsChanging(true), - complexGeometry(false), - srcPixelType(Qt::NoBrush), - opacityMode(NoOpacity), - maskType(NoMask), - compositionMode(QPainter::CompositionMode_SourceOver), - customSrcStage(nullptr), - currentShaderProg(nullptr) -{ - sharedShaders = QOpenGLEngineSharedShaders::shadersForContext(context); -} - -QOpenGLEngineShaderManager::~QOpenGLEngineShaderManager() -{ - //### - removeCustomStage(); -} - -GLuint QOpenGLEngineShaderManager::getUniformLocation(Uniform id) -{ - if (!currentShaderProg) - return 0; - - QVector<uint> &uniformLocations = currentShaderProg->uniformLocations; - if (uniformLocations.isEmpty()) - uniformLocations.fill(GLuint(-1), NumUniforms); - - const char uniformNames[][26] = { - "imageTexture", - "patternColor", - "globalOpacity", - "depth", - "maskTexture", - "fragmentColor", - "linearData", - "angle", - "halfViewportSize", - "fmp", - "fmp2_m_radius2", - "inverse_2_fmp2_m_radius2", - "sqrfr", - "bradius", - "invertedTextureSize", - "brushTransform", - "brushTexture", - "matrix" - }; - - if (uniformLocations.at(id) == GLuint(-1)) - uniformLocations[id] = currentShaderProg->program->uniformLocation(uniformNames[id]); - - return uniformLocations.at(id); -} - - -void QOpenGLEngineShaderManager::optimiseForBrushTransform(QTransform::TransformationType transformType) -{ - Q_UNUSED(transformType); // Currently ignored -} - -void QOpenGLEngineShaderManager::setDirty() -{ - shaderProgNeedsChanging = true; -} - -void QOpenGLEngineShaderManager::setSrcPixelType(Qt::BrushStyle style) -{ - Q_ASSERT(style != Qt::NoBrush); - if (srcPixelType == PixelSrcType(style)) - return; - - srcPixelType = style; - shaderProgNeedsChanging = true; //### -} - -void QOpenGLEngineShaderManager::setSrcPixelType(PixelSrcType type) -{ - if (srcPixelType == type) - return; - - srcPixelType = type; - shaderProgNeedsChanging = true; //### -} - -void QOpenGLEngineShaderManager::setOpacityMode(OpacityMode mode) -{ - if (opacityMode == mode) - return; - - opacityMode = mode; - shaderProgNeedsChanging = true; //### -} - -void QOpenGLEngineShaderManager::setMaskType(MaskType type) -{ - if (maskType == type) - return; - - maskType = type; - shaderProgNeedsChanging = true; //### -} - -void QOpenGLEngineShaderManager::setCompositionMode(QPainter::CompositionMode mode) -{ - if (compositionMode == mode) - return; - - bool wasAdvanced = compositionMode > QPainter::CompositionMode_Plus; - bool isAdvanced = mode > QPainter::CompositionMode_Plus; - - compositionMode = mode; - shaderProgNeedsChanging = shaderProgNeedsChanging || wasAdvanced || isAdvanced; -} - -void QOpenGLEngineShaderManager::setCustomStage(QOpenGLCustomShaderStage* stage) -{ - if (customSrcStage) - removeCustomStage(); - customSrcStage = stage; - shaderProgNeedsChanging = true; -} - -void QOpenGLEngineShaderManager::removeCustomStage() -{ - if (customSrcStage) - customSrcStage->setInactive(); - customSrcStage = nullptr; - shaderProgNeedsChanging = true; -} - -QOpenGLShaderProgram* QOpenGLEngineShaderManager::currentProgram() -{ - if (currentShaderProg) - return currentShaderProg->program; - else - return sharedShaders->simpleProgram(); -} - -void QOpenGLEngineShaderManager::useSimpleProgram() -{ - sharedShaders->simpleProgram()->bind(); - QOpenGLContextPrivate* ctx_d = ctx->d_func(); - Q_UNUSED(ctx_d); - - QOpenGL2PaintEngineEx *active_engine = static_cast<QOpenGL2PaintEngineEx *>(ctx_d->active_engine); - - active_engine->d_func()->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true); - active_engine->d_func()->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, false); - active_engine->d_func()->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false); - - shaderProgNeedsChanging = true; -} - -void QOpenGLEngineShaderManager::useBlitProgram() -{ - sharedShaders->blitProgram()->bind(); - QOpenGLContextPrivate* ctx_d = ctx->d_func(); - QOpenGL2PaintEngineEx *active_engine = static_cast<QOpenGL2PaintEngineEx *>(ctx_d->active_engine); - active_engine->d_func()->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true); - active_engine->d_func()->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, true); - active_engine->d_func()->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false); - shaderProgNeedsChanging = true; -} - -QOpenGLShaderProgram* QOpenGLEngineShaderManager::simpleProgram() -{ - return sharedShaders->simpleProgram(); -} - -QOpenGLShaderProgram* QOpenGLEngineShaderManager::blitProgram() -{ - return sharedShaders->blitProgram(); -} - - - -// Select & use the correct shader program using the current state. -// Returns \c true if program needed changing. -bool QOpenGLEngineShaderManager::useCorrectShaderProg() -{ - if (!shaderProgNeedsChanging) - return false; - - bool useCustomSrc = customSrcStage != nullptr; - if (useCustomSrc && srcPixelType != QOpenGLEngineShaderManager::ImageSrc && srcPixelType != Qt::TexturePattern) { - useCustomSrc = false; - qWarning("QOpenGLEngineShaderManager - Ignoring custom shader stage for non image src"); - } - - QOpenGLEngineShaderProg requiredProgram; - - bool texCoords = false; - - // Choose vertex shader shader position function (which typically also sets - // varyings) and the source pixel (srcPixel) fragment shader function: - requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::InvalidSnippetName; - requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::InvalidSnippetName; - bool isAffine = brushTransform.isAffine(); - if ( (srcPixelType >= Qt::Dense1Pattern) && (srcPixelType <= Qt::DiagCrossPattern) ) { - if (isAffine) - requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::AffinePositionWithPatternBrushVertexShader; - else - requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionWithPatternBrushVertexShader; - - requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::PatternBrushSrcFragmentShader; - } - else switch (srcPixelType) { - default: - case Qt::NoBrush: - qFatal("QOpenGLEngineShaderManager::useCorrectShaderProg() - Qt::NoBrush style is set"); - break; - case QOpenGLEngineShaderManager::ImageSrc: - requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::ImageSrcFragmentShader; - requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionOnlyVertexShader; - texCoords = true; - break; - case QOpenGLEngineShaderManager::NonPremultipliedImageSrc: - requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::NonPremultipliedImageSrcFragmentShader; - requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionOnlyVertexShader; - texCoords = true; - break; - case QOpenGLEngineShaderManager::GrayscaleImageSrc: - requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::GrayscaleImageSrcFragmentShader; - requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionOnlyVertexShader; - texCoords = true; - break; - case QOpenGLEngineShaderManager::AlphaImageSrc: - requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::AlphaImageSrcFragmentShader; - requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionOnlyVertexShader; - texCoords = true; - break; - case QOpenGLEngineShaderManager::PatternSrc: - requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::ImageSrcWithPatternFragmentShader; - requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionOnlyVertexShader; - texCoords = true; - break; - case QOpenGLEngineShaderManager::TextureSrcWithPattern: - requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::TextureBrushSrcWithPatternFragmentShader; - requiredProgram.positionVertexShader = isAffine ? QOpenGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader - : QOpenGLEngineSharedShaders::PositionWithTextureBrushVertexShader; - break; - case Qt::SolidPattern: - requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::SolidBrushSrcFragmentShader; - requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::PositionOnlyVertexShader; - break; - case Qt::LinearGradientPattern: - requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::LinearGradientBrushSrcFragmentShader; - requiredProgram.positionVertexShader = isAffine ? QOpenGLEngineSharedShaders::AffinePositionWithLinearGradientBrushVertexShader - : QOpenGLEngineSharedShaders::PositionWithLinearGradientBrushVertexShader; - break; - case Qt::ConicalGradientPattern: - requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::ConicalGradientBrushSrcFragmentShader; - requiredProgram.positionVertexShader = isAffine ? QOpenGLEngineSharedShaders::AffinePositionWithConicalGradientBrushVertexShader - : QOpenGLEngineSharedShaders::PositionWithConicalGradientBrushVertexShader; - break; - case Qt::RadialGradientPattern: - requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::RadialGradientBrushSrcFragmentShader; - requiredProgram.positionVertexShader = isAffine ? QOpenGLEngineSharedShaders::AffinePositionWithRadialGradientBrushVertexShader - : QOpenGLEngineSharedShaders::PositionWithRadialGradientBrushVertexShader; - break; - case Qt::TexturePattern: - requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::TextureBrushSrcFragmentShader; - requiredProgram.positionVertexShader = isAffine ? QOpenGLEngineSharedShaders::AffinePositionWithTextureBrushVertexShader - : QOpenGLEngineSharedShaders::PositionWithTextureBrushVertexShader; - break; - }; - - if (useCustomSrc) { - requiredProgram.srcPixelFragShader = QOpenGLEngineSharedShaders::CustomImageSrcFragmentShader; - requiredProgram.customStageSource = customSrcStage->source(); - } - - const bool hasCompose = compositionMode > QPainter::CompositionMode_Plus; - const bool hasMask = maskType != QOpenGLEngineShaderManager::NoMask; - - // Choose fragment shader main function: - if (opacityMode == AttributeOpacity) { - Q_ASSERT(!hasCompose && !hasMask); - requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_ImageArrays; - } else { - bool useGlobalOpacity = (opacityMode == UniformOpacity); - if (hasMask && useGlobalOpacity) - requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_MO; - if (hasMask && !useGlobalOpacity) - requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_M; - if (!hasMask && useGlobalOpacity) - requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader_O; - if (!hasMask && !useGlobalOpacity) - requiredProgram.mainFragShader = QOpenGLEngineSharedShaders::MainFragmentShader; - } - - if (hasMask) { - if (maskType == PixelMask) { - requiredProgram.maskFragShader = QOpenGLEngineSharedShaders::MaskFragmentShader; - texCoords = true; - } else if (maskType == SubPixelMaskPass1) { - requiredProgram.maskFragShader = QOpenGLEngineSharedShaders::RgbMaskFragmentShaderPass1; - texCoords = true; - } else if (maskType == SubPixelMaskPass2) { - requiredProgram.maskFragShader = QOpenGLEngineSharedShaders::RgbMaskFragmentShaderPass2; - texCoords = true; - } else if (maskType == SubPixelWithGammaMask) { - requiredProgram.maskFragShader = QOpenGLEngineSharedShaders::RgbMaskWithGammaFragmentShader; - texCoords = true; - } else { - qCritical("QOpenGLEngineShaderManager::useCorrectShaderProg() - Unknown mask type"); - } - } else { - requiredProgram.maskFragShader = QOpenGLEngineSharedShaders::NoMaskFragmentShader; - } - - if (hasCompose) { - switch (compositionMode) { - case QPainter::CompositionMode_Multiply: - requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::MultiplyCompositionModeFragmentShader; - break; - case QPainter::CompositionMode_Screen: - requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::ScreenCompositionModeFragmentShader; - break; - case QPainter::CompositionMode_Overlay: - requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::OverlayCompositionModeFragmentShader; - break; - case QPainter::CompositionMode_Darken: - requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::DarkenCompositionModeFragmentShader; - break; - case QPainter::CompositionMode_Lighten: - requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::LightenCompositionModeFragmentShader; - break; - case QPainter::CompositionMode_ColorDodge: - requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::ColorDodgeCompositionModeFragmentShader; - break; - case QPainter::CompositionMode_ColorBurn: - requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::ColorBurnCompositionModeFragmentShader; - break; - case QPainter::CompositionMode_HardLight: - requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::HardLightCompositionModeFragmentShader; - break; - case QPainter::CompositionMode_SoftLight: - requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::SoftLightCompositionModeFragmentShader; - break; - case QPainter::CompositionMode_Difference: - requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::DifferenceCompositionModeFragmentShader; - break; - case QPainter::CompositionMode_Exclusion: - requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::ExclusionCompositionModeFragmentShader; - break; - default: - qWarning("QOpenGLEngineShaderManager::useCorrectShaderProg() - Unsupported composition mode"); - } - } else { - requiredProgram.compositionFragShader = QOpenGLEngineSharedShaders::NoCompositionModeFragmentShader; - } - - // Choose vertex shader main function - if (opacityMode == AttributeOpacity) { - Q_ASSERT(texCoords); - requiredProgram.mainVertexShader = QOpenGLEngineSharedShaders::MainWithTexCoordsAndOpacityVertexShader; - } else if (texCoords) { - requiredProgram.mainVertexShader = QOpenGLEngineSharedShaders::MainWithTexCoordsVertexShader; - } else { - requiredProgram.mainVertexShader = QOpenGLEngineSharedShaders::MainVertexShader; - } - requiredProgram.useTextureCoords = texCoords; - requiredProgram.useOpacityAttribute = (opacityMode == AttributeOpacity); - if (complexGeometry && srcPixelType == Qt::SolidPattern) { - requiredProgram.positionVertexShader = QOpenGLEngineSharedShaders::ComplexGeometryPositionOnlyVertexShader; - requiredProgram.usePmvMatrixAttribute = false; - } else { - requiredProgram.usePmvMatrixAttribute = true; - - // Force complexGeometry off, since we currently don't support that mode for - // non-solid brushes - complexGeometry = false; - } - - // At this point, requiredProgram is fully populated so try to find the program in the cache - currentShaderProg = sharedShaders->findProgramInCache(requiredProgram); - - if (currentShaderProg && useCustomSrc) { - customSrcStage->setUniforms(currentShaderProg->program); - } - - // Make sure all the vertex attribute arrays the program uses are enabled (and the ones it - // doesn't use are disabled) - QOpenGLContextPrivate* ctx_d = ctx->d_func(); - QOpenGL2PaintEngineEx *active_engine = static_cast<QOpenGL2PaintEngineEx *>(ctx_d->active_engine); - active_engine->d_func()->setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true); - active_engine->d_func()->setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, currentShaderProg && currentShaderProg->useTextureCoords); - active_engine->d_func()->setVertexAttribArrayEnabled(QT_OPACITY_ATTR, currentShaderProg && currentShaderProg->useOpacityAttribute); - - shaderProgNeedsChanging = false; - return true; -} - -QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglengineshadermanager_p.h b/src/gui/opengl/qopenglengineshadermanager_p.h deleted file mode 100644 index 14c79f5de3..0000000000 --- a/src/gui/opengl/qopenglengineshadermanager_p.h +++ /dev/null @@ -1,507 +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$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -/* - VERTEX SHADERS - ============== - - Vertex shaders are specified as multiple (partial) shaders. On desktop, - this works fine. On ES, QOpenGLShader & QOpenGLShaderProgram will make partial - shaders work by concatenating the source in each QOpenGLShader and compiling - it as a single shader. This is abstracted nicely by QOpenGLShaderProgram and - the GL2 engine doesn't need to worry about it. - - Generally, there's two vertex shader objects. The position shaders are - the ones which set gl_Position. There's also two "main" vertex shaders, - one which just calls the position shader and another which also passes - through some texture coordinates from a vertex attribute array to a - varying. These texture coordinates are used for mask position in text - rendering and for the source coordinates in drawImage/drawPixmap. There's - also a "Simple" vertex shader for rendering a solid colour (used to render - into the stencil buffer where the actual colour value is discarded). - - The position shaders for brushes look scary. This is because many of the - calculations which logically belong in the fragment shader have been moved - into the vertex shader to improve performance. This is why the position - calculation is in a separate shader. Not only does it calculate the - position, but it also calculates some data to be passed to the fragment - shader as a varying. It is optimal to move as much of the calculation as - possible into the vertex shader as this is executed less often. - - The varyings passed to the fragment shaders are interpolated (which is - cheap). Unfortunately, GL will apply perspective correction to the - interpolation calusing errors. To get around this, the vertex shader must - apply perspective correction itself and set the w-value of gl_Position to - zero. That way, GL will be tricked into thinking it doesn't need to apply a - perspective correction and use linear interpolation instead (which is what - we want). Of course, if the brush transform is affeine, no perspective - correction is needed and a simpler vertex shader can be used instead. - - So there are the following "main" vertex shaders: - qopenglslMainVertexShader - qopenglslMainWithTexCoordsVertexShader - - And the following position vertex shaders: - qopenglslPositionOnlyVertexShader - qopenglslPositionWithTextureBrushVertexShader - qopenglslPositionWithPatternBrushVertexShader - qopenglslPositionWithLinearGradientBrushVertexShader - qopenglslPositionWithRadialGradientBrushVertexShader - qopenglslPositionWithConicalGradientBrushVertexShader - qopenglslAffinePositionWithTextureBrushVertexShader - qopenglslAffinePositionWithPatternBrushVertexShader - qopenglslAffinePositionWithLinearGradientBrushVertexShader - qopenglslAffinePositionWithRadialGradientBrushVertexShader - qopenglslAffinePositionWithConicalGradientBrushVertexShader - - Leading to 23 possible vertex shaders - - - FRAGMENT SHADERS - ================ - - Fragment shaders are also specified as multiple (partial) shaders. The - different fragment shaders represent the different stages in Qt's fragment - pipeline. There are 1-3 stages in this pipeline: First stage is to get the - fragment's colour value. The next stage is to get the fragment's mask value - (coverage value for anti-aliasing) and the final stage is to blend the - incoming fragment with the background (for composition modes not supported - by GL). - - Of these, the first stage will always be present. If Qt doesn't need to - apply anti-aliasing (because it's off or handled by multisampling) then - the coverage value doesn't need to be applied. (Note: There are two types - of mask, one for regular anti-aliasing and one for sub-pixel anti- - aliasing.) If the composition mode is one which GL supports natively then - the blending stage doesn't need to be applied. - - As eash stage can have multiple implementations, they are abstracted as - GLSL function calls with the following signatures: - - Brushes & image drawing are implementations of "qcolorp vec4 srcPixel()": - qopenglslImageSrcFragShader - qopenglslImageSrcWithPatternFragShader - qopenglslNonPremultipliedImageSrcFragShader - qopenglslSolidBrushSrcFragShader - qopenglslTextureBrushSrcFragShader - qopenglslTextureBrushWithPatternFragShader - qopenglslPatternBrushSrcFragShader - qopenglslLinearGradientBrushSrcFragShader - qopenglslRadialGradientBrushSrcFragShader - qopenglslConicalGradientBrushSrcFragShader - NOTE: It is assumed the colour returned by srcPixel() is pre-multiplied - - Masks are implementations of "qcolorp vec4 applyMask(qcolorp vec4 src)": - qopenglslMaskFragmentShader - qopenglslRgbMaskFragmentShaderPass1 - qopenglslRgbMaskFragmentShaderPass2 - qopenglslRgbMaskWithGammaFragmentShader - - Composition modes are "qcolorp vec4 compose(qcolorp vec4 src)": - qopenglslColorBurnCompositionModeFragmentShader - qopenglslColorDodgeCompositionModeFragmentShader - qopenglslDarkenCompositionModeFragmentShader - qopenglslDifferenceCompositionModeFragmentShader - qopenglslExclusionCompositionModeFragmentShader - qopenglslHardLightCompositionModeFragmentShader - qopenglslLightenCompositionModeFragmentShader - qopenglslMultiplyCompositionModeFragmentShader - qopenglslOverlayCompositionModeFragmentShader - qopenglslScreenCompositionModeFragmentShader - qopenglslSoftLightCompositionModeFragmentShader - - - Note: In the future, some GLSL compilers will support an extension allowing - a new 'color' precision specifier. To support this, qcolorp is used for - all color components so it can be defined to colorp or lowp depending upon - the implementation. - - So there are differnt frament shader main functions, depending on the - number & type of pipelines the fragment needs to go through. - - The choice of which main() fragment shader string to use depends on: - - Use of global opacity - - Brush style (some brushes apply opacity themselves) - - Use & type of mask (TODO: Need to support high quality anti-aliasing & text) - - Use of non-GL Composition mode - - Leading to the following fragment shader main functions: - gl_FragColor = compose(applyMask(srcPixel()*globalOpacity)); - gl_FragColor = compose(applyMask(srcPixel())); - gl_FragColor = applyMask(srcPixel()*globalOpacity); - gl_FragColor = applyMask(srcPixel()); - gl_FragColor = compose(srcPixel()*globalOpacity); - gl_FragColor = compose(srcPixel()); - gl_FragColor = srcPixel()*globalOpacity; - gl_FragColor = srcPixel(); - - Called: - qopenglslMainFragmentShader_CMO - qopenglslMainFragmentShader_CM - qopenglslMainFragmentShader_MO - qopenglslMainFragmentShader_M - qopenglslMainFragmentShader_CO - qopenglslMainFragmentShader_C - qopenglslMainFragmentShader_O - qopenglslMainFragmentShader - - Where: - M = Mask - C = Composition - O = Global Opacity - - - CUSTOM SHADER CODE - ================== - - The use of custom shader code is supported by the engine for drawImage and - drawPixmap calls. This is implemented via hooks in the fragment pipeline. - - The custom shader is passed to the engine as a partial fragment shader - (QOpenGLCustomShaderStage). The shader will implement a pre-defined method name - which Qt's fragment pipeline will call: - - lowp vec4 customShader(lowp sampler2d imageTexture, highp vec2 textureCoords) - - The provided src and srcCoords parameters can be used to sample from the - source image. - - Transformations, clipping, opacity, and composition modes set using QPainter - will be respected when using the custom shader hook. -*/ - -#ifndef QOPENGLENGINE_SHADER_MANAGER_H -#define QOPENGLENGINE_SHADER_MANAGER_H - -#include <QtGui/private/qtguiglobal_p.h> -#include <QOpenGLShader> -#include <QOpenGLShaderProgram> -#include <QPainter> -#include <private/qopenglcontext_p.h> -#include <private/qopenglcustomshaderstage_p.h> - -QT_BEGIN_NAMESPACE - - - -/* -struct QOpenGLEngineCachedShaderProg -{ - QOpenGLEngineCachedShaderProg(QOpenGLEngineShaderManager::ShaderName vertexMain, - QOpenGLEngineShaderManager::ShaderName vertexPosition, - QOpenGLEngineShaderManager::ShaderName fragMain, - QOpenGLEngineShaderManager::ShaderName pixelSrc, - QOpenGLEngineShaderManager::ShaderName mask, - QOpenGLEngineShaderManager::ShaderName composition); - - int cacheKey; - QOpenGLShaderProgram* program; -} -*/ - -static const GLuint QT_VERTEX_COORDS_ATTR = 0; -static const GLuint QT_TEXTURE_COORDS_ATTR = 1; -static const GLuint QT_OPACITY_ATTR = 2; -static const GLuint QT_PMV_MATRIX_1_ATTR = 3; -static const GLuint QT_PMV_MATRIX_2_ATTR = 4; -static const GLuint QT_PMV_MATRIX_3_ATTR = 5; - -class QOpenGLEngineShaderProg; - -class Q_GUI_EXPORT QOpenGLEngineSharedShaders -{ - Q_GADGET -public: - - enum SnippetName { - MainVertexShader, - MainWithTexCoordsVertexShader, - MainWithTexCoordsAndOpacityVertexShader, - - // UntransformedPositionVertexShader must be first in the list: - UntransformedPositionVertexShader, - PositionOnlyVertexShader, - ComplexGeometryPositionOnlyVertexShader, - PositionWithPatternBrushVertexShader, - PositionWithLinearGradientBrushVertexShader, - PositionWithConicalGradientBrushVertexShader, - PositionWithRadialGradientBrushVertexShader, - PositionWithTextureBrushVertexShader, - AffinePositionWithPatternBrushVertexShader, - AffinePositionWithLinearGradientBrushVertexShader, - AffinePositionWithConicalGradientBrushVertexShader, - AffinePositionWithRadialGradientBrushVertexShader, - AffinePositionWithTextureBrushVertexShader, - - // MainFragmentShader_CMO must be first in the list: - MainFragmentShader_MO, - MainFragmentShader_M, - MainFragmentShader_O, - MainFragmentShader, - MainFragmentShader_ImageArrays, - - // ImageSrcFragmentShader must be first in the list:: - ImageSrcFragmentShader, - ImageSrcWithPatternFragmentShader, - NonPremultipliedImageSrcFragmentShader, - GrayscaleImageSrcFragmentShader, - AlphaImageSrcFragmentShader, - CustomImageSrcFragmentShader, - SolidBrushSrcFragmentShader, - TextureBrushSrcFragmentShader, - TextureBrushSrcWithPatternFragmentShader, - PatternBrushSrcFragmentShader, - LinearGradientBrushSrcFragmentShader, - RadialGradientBrushSrcFragmentShader, - ConicalGradientBrushSrcFragmentShader, - ShockingPinkSrcFragmentShader, - - // NoMaskFragmentShader must be first in the list: - NoMaskFragmentShader, - MaskFragmentShader, - RgbMaskFragmentShaderPass1, - RgbMaskFragmentShaderPass2, - RgbMaskWithGammaFragmentShader, - - // NoCompositionModeFragmentShader must be first in the list: - NoCompositionModeFragmentShader, - MultiplyCompositionModeFragmentShader, - ScreenCompositionModeFragmentShader, - OverlayCompositionModeFragmentShader, - DarkenCompositionModeFragmentShader, - LightenCompositionModeFragmentShader, - ColorDodgeCompositionModeFragmentShader, - ColorBurnCompositionModeFragmentShader, - HardLightCompositionModeFragmentShader, - SoftLightCompositionModeFragmentShader, - DifferenceCompositionModeFragmentShader, - ExclusionCompositionModeFragmentShader, - - TotalSnippetCount, InvalidSnippetName - }; -#if defined (QT_DEBUG) - Q_ENUM(SnippetName) - static QByteArray snippetNameStr(SnippetName snippetName); -#endif - -/* - // These allow the ShaderName enum to be used as a cache key - const int mainVertexOffset = 0; - const int positionVertexOffset = (1<<2) - PositionOnlyVertexShader; - const int mainFragOffset = (1<<6) - MainFragmentShader_CMO; - const int srcPixelOffset = (1<<10) - ImageSrcFragmentShader; - const int maskOffset = (1<<14) - NoMaskShader; - const int compositionOffset = (1 << 16) - MultiplyCompositionModeFragmentShader; -*/ - - QOpenGLEngineSharedShaders(QOpenGLContext *context); - ~QOpenGLEngineSharedShaders(); - - QOpenGLShaderProgram *simpleProgram() { return simpleShaderProg; } - QOpenGLShaderProgram *blitProgram() { return blitShaderProg; } - // Compile the program if it's not already in the cache, return the item in the cache. - QOpenGLEngineShaderProg *findProgramInCache(const QOpenGLEngineShaderProg &prog); - // Compile the custom shader if it's not already in the cache, return the item in the cache. - - static QOpenGLEngineSharedShaders *shadersForContext(QOpenGLContext *context); - - // Ideally, this would be static and cleanup all programs in all contexts which - // contain the custom code. Currently it is just a hint and we rely on deleted - // custom shaders being cleaned up by being kicked out of the cache when it's - // full. - void cleanupCustomStage(QOpenGLCustomShaderStage* stage); - -private: - QOpenGLShaderProgram *blitShaderProg; - QOpenGLShaderProgram *simpleShaderProg; - QList<QOpenGLEngineShaderProg*> cachedPrograms; - - static const char* qShaderSnippets[TotalSnippetCount]; -}; - - -class QOpenGLEngineShaderProg -{ -public: - QOpenGLEngineShaderProg() : program(nullptr) {} - - ~QOpenGLEngineShaderProg() { - if (program) - delete program; - } - - QOpenGLEngineSharedShaders::SnippetName mainVertexShader; - QOpenGLEngineSharedShaders::SnippetName positionVertexShader; - QOpenGLEngineSharedShaders::SnippetName mainFragShader; - QOpenGLEngineSharedShaders::SnippetName srcPixelFragShader; - QOpenGLEngineSharedShaders::SnippetName maskFragShader; - QOpenGLEngineSharedShaders::SnippetName compositionFragShader; - - QByteArray customStageSource; //TODO: Decent cache key for custom stages - QOpenGLShaderProgram* program; - - QVector<uint> uniformLocations; - - bool useTextureCoords; - bool useOpacityAttribute; - bool usePmvMatrixAttribute; - - bool operator==(const QOpenGLEngineShaderProg& other) const { - // We don't care about the program - return ( mainVertexShader == other.mainVertexShader && - positionVertexShader == other.positionVertexShader && - mainFragShader == other.mainFragShader && - srcPixelFragShader == other.srcPixelFragShader && - maskFragShader == other.maskFragShader && - compositionFragShader == other.compositionFragShader && - customStageSource == other.customStageSource - ); - } -}; - -class Q_GUI_EXPORT QOpenGLEngineShaderManager : public QObject -{ - Q_OBJECT -public: - QOpenGLEngineShaderManager(QOpenGLContext* context); - ~QOpenGLEngineShaderManager(); - - enum MaskType {NoMask, PixelMask, SubPixelMaskPass1, SubPixelMaskPass2, SubPixelWithGammaMask}; - enum PixelSrcType { - ImageSrc = Qt::TexturePattern+1, - NonPremultipliedImageSrc = Qt::TexturePattern+2, - PatternSrc = Qt::TexturePattern+3, - TextureSrcWithPattern = Qt::TexturePattern+4, - GrayscaleImageSrc = Qt::TexturePattern+5, - AlphaImageSrc = Qt::TexturePattern+6, - }; - - enum Uniform { - ImageTexture, - PatternColor, - GlobalOpacity, - Depth, - MaskTexture, - FragmentColor, - LinearData, - Angle, - HalfViewportSize, - Fmp, - Fmp2MRadius2, - Inverse2Fmp2MRadius2, - SqrFr, - BRadius, - InvertedTextureSize, - BrushTransform, - BrushTexture, - Matrix, - NumUniforms - }; - - enum OpacityMode { - NoOpacity, - UniformOpacity, - AttributeOpacity - }; - - // There are optimizations we can do, depending on the brush transform: - // 1) May not have to apply perspective-correction - // 2) Can use lower precision for matrix - void optimiseForBrushTransform(QTransform::TransformationType transformType); - void setSrcPixelType(Qt::BrushStyle); - void setSrcPixelType(PixelSrcType); // For non-brush sources, like pixmaps & images - void setOpacityMode(OpacityMode); - void setMaskType(MaskType); - void setCompositionMode(QPainter::CompositionMode); - void setCustomStage(QOpenGLCustomShaderStage* stage); - void removeCustomStage(); - - GLuint getUniformLocation(Uniform id); - - void setDirty(); // someone has manually changed the current shader program - bool useCorrectShaderProg(); // returns true if the shader program needed to be changed - - void useSimpleProgram(); - void useBlitProgram(); - void setHasComplexGeometry(bool hasComplexGeometry) - { - complexGeometry = hasComplexGeometry; - shaderProgNeedsChanging = true; - } - bool hasComplexGeometry() const - { - return complexGeometry; - } - - QOpenGLShaderProgram* currentProgram(); // Returns pointer to the shader the manager has chosen - QOpenGLShaderProgram* simpleProgram(); // Used to draw into e.g. stencil buffers - QOpenGLShaderProgram* blitProgram(); // Used to blit a texture into the framebuffer - - QOpenGLEngineSharedShaders* sharedShaders; - -private: - QOpenGLContext* ctx; - bool shaderProgNeedsChanging; - bool complexGeometry; - - // Current state variables which influence the choice of shader: - QTransform brushTransform; - int srcPixelType; - OpacityMode opacityMode; - MaskType maskType; - QPainter::CompositionMode compositionMode; - QOpenGLCustomShaderStage* customSrcStage; - - QOpenGLEngineShaderProg* currentShaderProg; -}; - -QT_END_NAMESPACE - -#endif //QOPENGLENGINE_SHADER_MANAGER_H diff --git a/src/gui/opengl/qopenglengineshadersource_p.h b/src/gui/opengl/qopenglengineshadersource_p.h deleted file mode 100644 index 3ac599b6c2..0000000000 --- a/src/gui/opengl/qopenglengineshadersource_p.h +++ /dev/null @@ -1,970 +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$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - - -#ifndef QOPENGL_ENGINE_SHADER_SOURCE_H -#define QOPENGL_ENGINE_SHADER_SOURCE_H - -#include <QtGui/private/qtguiglobal_p.h> -#include "qopenglengineshadermanager_p.h" - -QT_BEGIN_NAMESPACE - - -static const char* const qopenglslMainVertexShader = "\n\ - void setPosition(); \n\ - void main(void) \n\ - { \n\ - setPosition(); \n\ - }\n"; - -static const char* const qopenglslMainWithTexCoordsVertexShader = "\n\ - attribute highp vec2 textureCoordArray; \n\ - varying highp vec2 textureCoords; \n\ - void setPosition(); \n\ - void main(void) \n\ - { \n\ - setPosition(); \n\ - textureCoords = textureCoordArray; \n\ - }\n"; - -static const char* const qopenglslMainWithTexCoordsAndOpacityVertexShader = "\n\ - attribute highp vec2 textureCoordArray; \n\ - attribute lowp float opacityArray; \n\ - varying highp vec2 textureCoords; \n\ - varying lowp float opacity; \n\ - void setPosition(); \n\ - void main(void) \n\ - { \n\ - setPosition(); \n\ - textureCoords = textureCoordArray; \n\ - opacity = opacityArray; \n\ - }\n"; - -// NOTE: We let GL do the perspective correction so texture lookups in the fragment -// shader are also perspective corrected. -static const char* const qopenglslPositionOnlyVertexShader = "\n\ - attribute highp vec2 vertexCoordsArray; \n\ - attribute highp vec3 pmvMatrix1; \n\ - attribute highp vec3 pmvMatrix2; \n\ - attribute highp vec3 pmvMatrix3; \n\ - void setPosition(void) \n\ - { \n\ - highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\ - vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\ - gl_Position = vec4(transformedPos.xy, 0.0, transformedPos.z); \n\ - }\n"; - -static const char* const qopenglslComplexGeometryPositionOnlyVertexShader = "\n\ - uniform highp mat3 matrix; \n\ - attribute highp vec2 vertexCoordsArray; \n\ - void setPosition(void) \n\ - { \n\ - gl_Position = vec4(matrix * vec3(vertexCoordsArray, 1), 1);\n\ - } \n"; - -static const char* const qopenglslUntransformedPositionVertexShader = "\n\ - attribute highp vec4 vertexCoordsArray; \n\ - void setPosition(void) \n\ - { \n\ - gl_Position = vertexCoordsArray; \n\ - }\n"; - -// Pattern Brush - This assumes the texture size is 8x8 and thus, the inverted size is 0.125 -static const char* const qopenglslPositionWithPatternBrushVertexShader = "\n\ - attribute highp vec2 vertexCoordsArray; \n\ - attribute highp vec3 pmvMatrix1; \n\ - attribute highp vec3 pmvMatrix2; \n\ - attribute highp vec3 pmvMatrix3; \n\ - uniform mediump vec2 halfViewportSize; \n\ - uniform highp vec2 invertedTextureSize; \n\ - uniform highp mat3 brushTransform; \n\ - varying highp vec2 patternTexCoords; \n\ - void setPosition(void) \n\ - { \n\ - highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\ - vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\ - gl_Position.xy = transformedPos.xy / transformedPos.z; \n\ - mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\ - mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1.0); \n\ - mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\ - gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\ - patternTexCoords.xy = (hTexCoords.xy * 0.125) * invertedHTexCoordsZ; \n\ - }\n"; - -static const char* const qopenglslAffinePositionWithPatternBrushVertexShader - = qopenglslPositionWithPatternBrushVertexShader; - -static const char* const qopenglslPatternBrushSrcFragmentShader = "\n\ - uniform sampler2D brushTexture; \n\ - uniform lowp vec4 patternColor; \n\ - varying highp vec2 patternTexCoords;\n\ - lowp vec4 srcPixel() \n\ - { \n\ - return patternColor * (1.0 - texture2D(brushTexture, patternTexCoords).r); \n\ - }\n"; - - -// Linear Gradient Brush -static const char* const qopenglslPositionWithLinearGradientBrushVertexShader = "\n\ - attribute highp vec2 vertexCoordsArray; \n\ - attribute highp vec3 pmvMatrix1; \n\ - attribute highp vec3 pmvMatrix2; \n\ - attribute highp vec3 pmvMatrix3; \n\ - uniform mediump vec2 halfViewportSize; \n\ - uniform highp vec3 linearData; \n\ - uniform highp mat3 brushTransform; \n\ - varying mediump float index; \n\ - void setPosition() \n\ - { \n\ - highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\ - vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\ - gl_Position.xy = transformedPos.xy / transformedPos.z; \n\ - mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\ - mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\ - mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\ - gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\ - index = (dot(linearData.xy, hTexCoords.xy) * linearData.z) * invertedHTexCoordsZ; \n\ - }\n"; - -static const char* const qopenglslAffinePositionWithLinearGradientBrushVertexShader - = qopenglslPositionWithLinearGradientBrushVertexShader; - -static const char* const qopenglslLinearGradientBrushSrcFragmentShader = "\n\ - uniform sampler2D brushTexture; \n\ - varying mediump float index; \n\ - lowp vec4 srcPixel() \n\ - { \n\ - mediump vec2 val = vec2(index, 0.5); \n\ - return texture2D(brushTexture, val); \n\ - }\n"; - - -// Conical Gradient Brush -static const char* const qopenglslPositionWithConicalGradientBrushVertexShader = "\n\ - attribute highp vec2 vertexCoordsArray; \n\ - attribute highp vec3 pmvMatrix1; \n\ - attribute highp vec3 pmvMatrix2; \n\ - attribute highp vec3 pmvMatrix3; \n\ - uniform mediump vec2 halfViewportSize; \n\ - uniform highp mat3 brushTransform; \n\ - varying highp vec2 A; \n\ - void setPosition(void) \n\ - { \n\ - highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\ - vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\ - gl_Position.xy = transformedPos.xy / transformedPos.z; \n\ - mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\ - mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\ - mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\ - gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\ - A = hTexCoords.xy * invertedHTexCoordsZ; \n\ - }\n"; - -static const char* const qopenglslAffinePositionWithConicalGradientBrushVertexShader - = qopenglslPositionWithConicalGradientBrushVertexShader; - -static const char* const qopenglslConicalGradientBrushSrcFragmentShader = "\n\ - #define INVERSE_2PI 0.1591549430918953358 \n\ - uniform sampler2D brushTexture; \n\ - uniform mediump float angle; \n\ - varying highp vec2 A; \n\ - lowp vec4 srcPixel() \n\ - { \n\ - highp float t; \n\ - if (abs(A.y) == abs(A.x)) \n\ - t = (atan(-A.y + 0.002, A.x) + angle) * INVERSE_2PI; \n\ - else \n\ - t = (atan(-A.y, A.x) + angle) * INVERSE_2PI; \n\ - return texture2D(brushTexture, vec2(t - floor(t), 0.5)); \n\ - }\n"; - - -// Radial Gradient Brush -static const char* const qopenglslPositionWithRadialGradientBrushVertexShader = "\n\ - attribute highp vec2 vertexCoordsArray;\n\ - attribute highp vec3 pmvMatrix1; \n\ - attribute highp vec3 pmvMatrix2; \n\ - attribute highp vec3 pmvMatrix3; \n\ - uniform mediump vec2 halfViewportSize; \n\ - uniform highp mat3 brushTransform; \n\ - uniform highp vec2 fmp; \n\ - uniform mediump vec3 bradius; \n\ - varying highp float b; \n\ - varying highp vec2 A; \n\ - void setPosition(void) \n\ - {\n\ - highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\ - vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\ - gl_Position.xy = transformedPos.xy / transformedPos.z; \n\ - mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\ - mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\ - mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\ - gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\ - A = hTexCoords.xy * invertedHTexCoordsZ; \n\ - b = bradius.x + 2.0 * dot(A, fmp); \n\ - }\n"; - -static const char* const qopenglslAffinePositionWithRadialGradientBrushVertexShader - = qopenglslPositionWithRadialGradientBrushVertexShader; - -static const char* const qopenglslRadialGradientBrushSrcFragmentShader = "\n\ - uniform sampler2D brushTexture; \n\ - uniform highp float fmp2_m_radius2; \n\ - uniform highp float inverse_2_fmp2_m_radius2; \n\ - uniform highp float sqrfr; \n\ - varying highp float b; \n\ - varying highp vec2 A; \n\ - uniform mediump vec3 bradius; \n\ - lowp vec4 srcPixel() \n\ - { \n\ - highp float c = sqrfr-dot(A, A); \n\ - highp float det = b*b - 4.0*fmp2_m_radius2*c; \n\ - lowp vec4 result = vec4(0.0); \n\ - if (det >= 0.0) { \n\ - highp float detSqrt = sqrt(det); \n\ - highp float w = max((-b - detSqrt) * inverse_2_fmp2_m_radius2, (-b + detSqrt) * inverse_2_fmp2_m_radius2); \n\ - if (bradius.y + w * bradius.z >= 0.0) \n\ - result = texture2D(brushTexture, vec2(w, 0.5)); \n\ - } \n\ - return result; \n\ - }\n"; - - -// Texture Brush -static const char* const qopenglslPositionWithTextureBrushVertexShader = "\n\ - attribute highp vec2 vertexCoordsArray; \n\ - attribute highp vec3 pmvMatrix1; \n\ - attribute highp vec3 pmvMatrix2; \n\ - attribute highp vec3 pmvMatrix3; \n\ - uniform mediump vec2 halfViewportSize; \n\ - uniform highp vec2 invertedTextureSize; \n\ - uniform highp mat3 brushTransform; \n\ - varying highp vec2 brushTextureCoords; \n\ - void setPosition(void) \n\ - { \n\ - highp mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\ - vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\ - gl_Position.xy = transformedPos.xy / transformedPos.z; \n\ - mediump vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\ - mediump vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\ - mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\ - gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\ - brushTextureCoords.xy = (hTexCoords.xy * invertedTextureSize) * gl_Position.w; \n\ - }\n"; - -static const char* const qopenglslAffinePositionWithTextureBrushVertexShader - = qopenglslPositionWithTextureBrushVertexShader; - -static const char* const qopenglslTextureBrushSrcFragmentShader = "\n\ - varying highp vec2 brushTextureCoords; \n\ - uniform sampler2D brushTexture; \n\ - lowp vec4 srcPixel() \n\ - { \n\ - return texture2D(brushTexture, brushTextureCoords); \n\ - }\n"; - -static const char* const qopenglslTextureBrushSrcWithPatternFragmentShader = "\n\ - varying highp vec2 brushTextureCoords; \n\ - uniform lowp vec4 patternColor; \n\ - uniform sampler2D brushTexture; \n\ - lowp vec4 srcPixel() \n\ - { \n\ - return patternColor * (1.0 - texture2D(brushTexture, brushTextureCoords).r); \n\ - }\n"; - -// Solid Fill Brush -static const char* const qopenglslSolidBrushSrcFragmentShader = "\n\ - uniform lowp vec4 fragmentColor; \n\ - lowp vec4 srcPixel() \n\ - { \n\ - return fragmentColor; \n\ - }\n"; - -static const char* const qopenglslImageSrcFragmentShader = "\n\ - varying highp vec2 textureCoords; \n\ - uniform sampler2D imageTexture; \n\ - lowp vec4 srcPixel() \n\ - { \n" - "return texture2D(imageTexture, textureCoords); \n" - "}\n"; - -static const char* const qopenglslCustomSrcFragmentShader = "\n\ - varying highp vec2 textureCoords; \n\ - uniform sampler2D imageTexture; \n\ - lowp vec4 srcPixel() \n\ - { \n\ - return customShader(imageTexture, textureCoords); \n\ - }\n"; - -static const char* const qopenglslImageSrcWithPatternFragmentShader = "\n\ - varying highp vec2 textureCoords; \n\ - uniform lowp vec4 patternColor; \n\ - uniform sampler2D imageTexture; \n\ - lowp vec4 srcPixel() \n\ - { \n\ - return patternColor * (1.0 - texture2D(imageTexture, textureCoords).r); \n\ - }\n"; - -static const char* const qopenglslNonPremultipliedImageSrcFragmentShader = "\n\ - varying highp vec2 textureCoords; \n\ - uniform sampler2D imageTexture; \n\ - lowp vec4 srcPixel() \n\ - { \n\ - lowp vec4 sample = texture2D(imageTexture, textureCoords); \n\ - sample.rgb = sample.rgb * sample.a; \n\ - return sample; \n\ - }\n"; - -static const char* const qopenglslGrayscaleImageSrcFragmentShader = "\n\ - varying highp vec2 textureCoords; \n\ - uniform sampler2D imageTexture; \n\ - lowp vec4 srcPixel() \n\ - { \n\ - return texture2D(imageTexture, textureCoords).rrra; \n\ - }\n"; - -static const char* const qopenglslAlphaImageSrcFragmentShader = "\n\ - varying highp vec2 textureCoords; \n\ - uniform sampler2D imageTexture; \n\ - lowp vec4 srcPixel() \n\ - { \n\ - return vec4(0, 0, 0, texture2D(imageTexture, textureCoords).r); \n\ - }\n"; - -static const char* const qopenglslShockingPinkSrcFragmentShader = "\n\ - lowp vec4 srcPixel() \n\ - { \n\ - return vec4(0.98, 0.06, 0.75, 1.0); \n\ - }\n"; - -static const char* const qopenglslMainFragmentShader_ImageArrays = "\n\ - varying lowp float opacity; \n\ - lowp vec4 srcPixel(); \n\ - void main() \n\ - { \n\ - gl_FragColor = srcPixel() * opacity; \n\ - }\n"; - -static const char* const qopenglslMainFragmentShader_MO = "\n\ - uniform lowp float globalOpacity; \n\ - lowp vec4 srcPixel(); \n\ - lowp vec4 applyMask(lowp vec4); \n\ - void main() \n\ - { \n\ - gl_FragColor = applyMask(srcPixel()*globalOpacity); \n\ - }\n"; - -static const char* const qopenglslMainFragmentShader_M = "\n\ - lowp vec4 srcPixel(); \n\ - lowp vec4 applyMask(lowp vec4); \n\ - void main() \n\ - { \n\ - gl_FragColor = applyMask(srcPixel()); \n\ - }\n"; - -static const char* const qopenglslMainFragmentShader_O = "\n\ - uniform lowp float globalOpacity; \n\ - lowp vec4 srcPixel(); \n\ - void main() \n\ - { \n\ - gl_FragColor = srcPixel()*globalOpacity; \n\ - }\n"; - -static const char* const qopenglslMainFragmentShader = "\n\ - lowp vec4 srcPixel(); \n\ - void main() \n\ - { \n\ - gl_FragColor = srcPixel(); \n\ - }\n"; - -static const char* const qopenglslMaskFragmentShader = "\n\ - varying highp vec2 textureCoords;\n\ - uniform sampler2D maskTexture;\n\ - lowp vec4 applyMask(lowp vec4 src) \n\ - {\n\ - lowp vec4 mask = texture2D(maskTexture, textureCoords); \n\ - return src * mask.a; \n\ - }\n"; - -// For source over with subpixel antialiasing, the final color is calculated per component as follows -// (.a is alpha component, .c is red, green or blue component): -// alpha = src.a * mask.c * opacity -// dest.c = dest.c * (1 - alpha) + src.c * alpha -// -// In the first pass, calculate: dest.c = dest.c * (1 - alpha) with blend funcs: zero, 1 - source color -// In the second pass, calculate: dest.c = dest.c + src.c * alpha with blend funcs: one, one -// -// If source is a solid color (src is constant), only the first pass is needed, with blend funcs: constant, 1 - source color - -// For source composition with subpixel antialiasing, the final color is calculated per component as follows: -// alpha = src.a * mask.c * opacity -// dest.c = dest.c * (1 - mask.c) + src.c * alpha -// - -static const char* const qopenglslRgbMaskFragmentShaderPass1 = "\n\ - varying highp vec2 textureCoords;\n\ - uniform sampler2D maskTexture;\n\ - lowp vec4 applyMask(lowp vec4 src) \n\ - { \n\ - lowp vec4 mask = texture2D(maskTexture, textureCoords); \n\ - return src.a * mask; \n\ - }\n"; - -static const char* const qopenglslRgbMaskFragmentShaderPass2 = "\n\ - varying highp vec2 textureCoords;\n\ - uniform sampler2D maskTexture;\n\ - lowp vec4 applyMask(lowp vec4 src) \n\ - { \n\ - lowp vec4 mask = texture2D(maskTexture, textureCoords); \n\ - return src * mask; \n\ - }\n"; - -static const char* const qopenglslMultiplyCompositionModeFragmentShader = "\n\ - #ifdef GL_KHR_blend_equation_advanced\n\ - layout(blend_support_multiply) out;\n\ - #endif\n"; - -static const char* const qopenglslScreenCompositionModeFragmentShader = "\n\ - #ifdef GL_KHR_blend_equation_advanced\n\ - layout(blend_support_screen) out;\n\ - #endif\n"; - -static const char* const qopenglslOverlayCompositionModeFragmentShader = "\n\ - #ifdef GL_KHR_blend_equation_advanced\n\ - layout(blend_support_overlay) out;\n\ - #endif\n"; - -static const char* const qopenglslDarkenCompositionModeFragmentShader = "\n\ - #ifdef GL_KHR_blend_equation_advanced\n\ - layout(blend_support_darken) out;\n\ - #endif\n"; - -static const char* const qopenglslLightenCompositionModeFragmentShader = "\n\ - #ifdef GL_KHR_blend_equation_advanced\n\ - layout(blend_support_lighten) out;\n\ - #endif\n"; - -static const char* const qopenglslColorDodgeCompositionModeFragmentShader = "\n\ - #ifdef GL_KHR_blend_equation_advanced\n\ - layout(blend_support_colordodge) out;\n\ - #endif\n"; - -static const char* const qopenglslColorBurnCompositionModeFragmentShader = "\n\ - #ifdef GL_KHR_blend_equation_advanced\n\ - layout(blend_support_colorburn) out;\n\ - #endif\n"; - -static const char* const qopenglslHardLightCompositionModeFragmentShader = "\n\ - #ifdef GL_KHR_blend_equation_advanced\n\ - layout(blend_support_hardlight) out;\n\ - #endif\n"; - -static const char* const qopenglslSoftLightCompositionModeFragmentShader = "\n\ - #ifdef GL_KHR_blend_equation_advanced\n\ - layout(blend_support_softlight) out;\n\ - #endif\n"; - -static const char* const qopenglslDifferenceCompositionModeFragmentShader = "\n\ - #ifdef GL_KHR_blend_equation_advanced\n\ - layout(blend_support_difference) out;\n\ - #endif\n"; - -static const char* const qopenglslExclusionCompositionModeFragmentShader = "\n\ - #ifdef GL_KHR_blend_equation_advanced\n\ - layout(blend_support_exclusion) out;\n\ - #endif\n"; - -/* - Left to implement: - RgbMaskFragmentShader, - RgbMaskWithGammaFragmentShader, -*/ - -/* - OpenGL 3.2+ Core Profile shaders - The following shader snippets are copies of the snippets above - but use the modern GLSL 1.5 keywords. New shaders should make - a snippet for both profiles and add them appropriately in the - shader manager. -*/ -static const char* const qopenglslMainVertexShader_core = - "#version 150 core\n\ - void setPosition(); \n\ - void main(void) \n\ - { \n\ - setPosition(); \n\ - }\n"; - -static const char* const qopenglslMainWithTexCoordsVertexShader_core = - "#version 150 core\n\ - in vec2 textureCoordArray; \n\ - out vec2 textureCoords; \n\ - void setPosition(); \n\ - void main(void) \n\ - { \n\ - setPosition(); \n\ - textureCoords = textureCoordArray; \n\ - }\n"; - -static const char* const qopenglslMainWithTexCoordsAndOpacityVertexShader_core = - "#version 150 core\n\ - in vec2 textureCoordArray; \n\ - in float opacityArray; \n\ - out vec2 textureCoords; \n\ - out float opacity; \n\ - void setPosition(); \n\ - void main(void) \n\ - { \n\ - setPosition(); \n\ - textureCoords = textureCoordArray; \n\ - opacity = opacityArray; \n\ - }\n"; - -// NOTE: We let GL do the perspective correction so texture lookups in the fragment -// shader are also perspective corrected. -static const char* const qopenglslPositionOnlyVertexShader_core = "\n\ - in vec2 vertexCoordsArray; \n\ - in vec3 pmvMatrix1; \n\ - in vec3 pmvMatrix2; \n\ - in vec3 pmvMatrix3; \n\ - void setPosition(void) \n\ - { \n\ - mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\ - vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\ - gl_Position = vec4(transformedPos.xy, 0.0, transformedPos.z); \n\ - }\n"; - -static const char* const qopenglslComplexGeometryPositionOnlyVertexShader_core = "\n\ - in vec2 vertexCoordsArray; \n\ - uniform mat3 matrix; \n\ - void setPosition(void) \n\ - { \n\ - gl_Position = vec4(matrix * vec3(vertexCoordsArray, 1), 1);\n\ - } \n"; - -static const char* const qopenglslUntransformedPositionVertexShader_core = "\n\ - in vec4 vertexCoordsArray; \n\ - void setPosition(void) \n\ - { \n\ - gl_Position = vertexCoordsArray; \n\ - }\n"; - -// Pattern Brush - This assumes the texture size is 8x8 and thus, the inverted size is 0.125 -static const char* const qopenglslPositionWithPatternBrushVertexShader_core = "\n\ - in vec2 vertexCoordsArray; \n\ - in vec3 pmvMatrix1; \n\ - in vec3 pmvMatrix2; \n\ - in vec3 pmvMatrix3; \n\ - out vec2 patternTexCoords; \n\ - uniform vec2 halfViewportSize; \n\ - uniform vec2 invertedTextureSize; \n\ - uniform mat3 brushTransform; \n\ - void setPosition(void) \n\ - { \n\ - mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\ - vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\ - gl_Position.xy = transformedPos.xy / transformedPos.z; \n\ - vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\ - vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1.0); \n\ - float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\ - gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\ - patternTexCoords.xy = (hTexCoords.xy * 0.125) * invertedHTexCoordsZ; \n\ - }\n"; - -static const char* const qopenglslAffinePositionWithPatternBrushVertexShader_core - = qopenglslPositionWithPatternBrushVertexShader_core; - -static const char* const qopenglslPatternBrushSrcFragmentShader_core = "\n\ - in vec2 patternTexCoords;\n\ - uniform sampler2D brushTexture; \n\ - uniform vec4 patternColor; \n\ - vec4 srcPixel() \n\ - { \n\ - return patternColor * (1.0 - texture(brushTexture, patternTexCoords).r); \n\ - }\n"; - - -// Linear Gradient Brush -static const char* const qopenglslPositionWithLinearGradientBrushVertexShader_core = "\n\ - in vec2 vertexCoordsArray; \n\ - in vec3 pmvMatrix1; \n\ - in vec3 pmvMatrix2; \n\ - in vec3 pmvMatrix3; \n\ - out float index; \n\ - uniform vec2 halfViewportSize; \n\ - uniform vec3 linearData; \n\ - uniform mat3 brushTransform; \n\ - void setPosition() \n\ - { \n\ - mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\ - vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\ - gl_Position.xy = transformedPos.xy / transformedPos.z; \n\ - vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\ - vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\ - float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\ - gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\ - index = (dot(linearData.xy, hTexCoords.xy) * linearData.z) * invertedHTexCoordsZ; \n\ - }\n"; - -static const char* const qopenglslAffinePositionWithLinearGradientBrushVertexShader_core - = qopenglslPositionWithLinearGradientBrushVertexShader_core; - -static const char* const qopenglslLinearGradientBrushSrcFragmentShader_core = "\n\ - uniform sampler2D brushTexture; \n\ - in float index; \n\ - vec4 srcPixel() \n\ - { \n\ - vec2 val = vec2(index, 0.5); \n\ - return texture(brushTexture, val); \n\ - }\n"; - - -// Conical Gradient Brush -static const char* const qopenglslPositionWithConicalGradientBrushVertexShader_core = "\n\ - in vec2 vertexCoordsArray; \n\ - in vec3 pmvMatrix1; \n\ - in vec3 pmvMatrix2; \n\ - in vec3 pmvMatrix3; \n\ - out vec2 A; \n\ - uniform vec2 halfViewportSize; \n\ - uniform mat3 brushTransform; \n\ - void setPosition(void) \n\ - { \n\ - mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\ - vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\ - gl_Position.xy = transformedPos.xy / transformedPos.z; \n\ - vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\ - vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\ - float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\ - gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\ - A = hTexCoords.xy * invertedHTexCoordsZ; \n\ - }\n"; - -static const char* const qopenglslAffinePositionWithConicalGradientBrushVertexShader_core - = qopenglslPositionWithConicalGradientBrushVertexShader_core; - -static const char* const qopenglslConicalGradientBrushSrcFragmentShader_core = "\n\ - #define INVERSE_2PI 0.1591549430918953358 \n\ - in vec2 A; \n\ - uniform sampler2D brushTexture; \n\ - uniform float angle; \n\ - vec4 srcPixel() \n\ - { \n\ - float t; \n\ - if (abs(A.y) == abs(A.x)) \n\ - t = (atan(-A.y + 0.002, A.x) + angle) * INVERSE_2PI; \n\ - else \n\ - t = (atan(-A.y, A.x) + angle) * INVERSE_2PI; \n\ - return texture(brushTexture, vec2(t - floor(t), 0.5)); \n\ - }\n"; - - -// Radial Gradient Brush -static const char* const qopenglslPositionWithRadialGradientBrushVertexShader_core = "\n\ - in vec2 vertexCoordsArray;\n\ - in vec3 pmvMatrix1; \n\ - in vec3 pmvMatrix2; \n\ - in vec3 pmvMatrix3; \n\ - out float b; \n\ - out vec2 A; \n\ - uniform vec2 halfViewportSize; \n\ - uniform mat3 brushTransform; \n\ - uniform vec2 fmp; \n\ - uniform vec3 bradius; \n\ - void setPosition(void) \n\ - {\n\ - mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\ - vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\ - gl_Position.xy = transformedPos.xy / transformedPos.z; \n\ - vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\ - vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\ - float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\ - gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\ - A = hTexCoords.xy * invertedHTexCoordsZ; \n\ - b = bradius.x + 2.0 * dot(A, fmp); \n\ - }\n"; - -static const char* const qopenglslAffinePositionWithRadialGradientBrushVertexShader_core - = qopenglslPositionWithRadialGradientBrushVertexShader_core; - -static const char* const qopenglslRadialGradientBrushSrcFragmentShader_core = "\n\ - in float b; \n\ - in vec2 A; \n\ - uniform sampler2D brushTexture; \n\ - uniform float fmp2_m_radius2; \n\ - uniform float inverse_2_fmp2_m_radius2; \n\ - uniform float sqrfr; \n\ - uniform vec3 bradius; \n\ - \n\ - vec4 srcPixel() \n\ - { \n\ - float c = sqrfr-dot(A, A); \n\ - float det = b*b - 4.0*fmp2_m_radius2*c; \n\ - vec4 result = vec4(0.0); \n\ - if (det >= 0.0) { \n\ - float detSqrt = sqrt(det); \n\ - float w = max((-b - detSqrt) * inverse_2_fmp2_m_radius2, (-b + detSqrt) * inverse_2_fmp2_m_radius2); \n\ - if (bradius.y + w * bradius.z >= 0.0) \n\ - result = texture(brushTexture, vec2(w, 0.5)); \n\ - } \n\ - return result; \n\ - }\n"; - - -// Texture Brush -static const char* const qopenglslPositionWithTextureBrushVertexShader_core = "\n\ - in vec2 vertexCoordsArray; \n\ - in vec3 pmvMatrix1; \n\ - in vec3 pmvMatrix2; \n\ - in vec3 pmvMatrix3; \n\ - out vec2 brushTextureCoords; \n\ - uniform vec2 halfViewportSize; \n\ - uniform vec2 invertedTextureSize; \n\ - uniform mat3 brushTransform; \n\ - \n\ - void setPosition(void) \n\ - { \n\ - mat3 pmvMatrix = mat3(pmvMatrix1, pmvMatrix2, pmvMatrix3); \n\ - vec3 transformedPos = pmvMatrix * vec3(vertexCoordsArray.xy, 1.0); \n\ - gl_Position.xy = transformedPos.xy / transformedPos.z; \n\ - vec2 viewportCoords = (gl_Position.xy + 1.0) * halfViewportSize; \n\ - vec3 hTexCoords = brushTransform * vec3(viewportCoords, 1); \n\ - float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\ - gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\ - brushTextureCoords.xy = (hTexCoords.xy * invertedTextureSize) * gl_Position.w; \n\ - }\n"; - -static const char* const qopenglslAffinePositionWithTextureBrushVertexShader_core - = qopenglslPositionWithTextureBrushVertexShader_core; - -static const char* const qopenglslTextureBrushSrcFragmentShader_core = "\n\ - in vec2 brushTextureCoords; \n\ - uniform sampler2D brushTexture; \n\ - vec4 srcPixel() \n\ - { \n\ - return texture(brushTexture, brushTextureCoords); \n\ - }\n"; - -static const char* const qopenglslTextureBrushSrcWithPatternFragmentShader_core = "\n\ - in vec2 brushTextureCoords; \n\ - uniform vec4 patternColor; \n\ - uniform sampler2D brushTexture; \n\ - vec4 srcPixel() \n\ - { \n\ - return patternColor * (1.0 - texture(brushTexture, brushTextureCoords).r); \n\ - }\n"; - -// Solid Fill Brush -static const char* const qopenglslSolidBrushSrcFragmentShader_core = "\n\ - uniform vec4 fragmentColor; \n\ - vec4 srcPixel() \n\ - { \n\ - return fragmentColor; \n\ - }\n"; - -static const char* const qopenglslImageSrcFragmentShader_core = "\n\ - in vec2 textureCoords; \n\ - uniform sampler2D imageTexture; \n\ - vec4 srcPixel() \n\ - { \n\ - return texture(imageTexture, textureCoords); \n\ - }\n"; - -static const char* const qopenglslCustomSrcFragmentShader_core = "\n\ - in vec2 textureCoords; \n\ - uniform sampler2D imageTexture; \n\ - vec4 srcPixel() \n\ - { \n\ - return customShader(imageTexture, textureCoords); \n\ - }\n"; - -static const char* const qopenglslImageSrcWithPatternFragmentShader_core = "\n\ - in vec2 textureCoords; \n\ - uniform vec4 patternColor; \n\ - uniform sampler2D imageTexture; \n\ - vec4 srcPixel() \n\ - { \n\ - return patternColor * (1.0 - texture(imageTexture, textureCoords).r); \n\ - }\n"; - -static const char* const qopenglslNonPremultipliedImageSrcFragmentShader_core = "\n\ - in vec2 textureCoords; \n\ - uniform sampler2D imageTexture; \n\ - vec4 srcPixel() \n\ - { \n\ - vec4 sample = texture(imageTexture, textureCoords); \n\ - sample.rgb = sample.rgb * sample.a; \n\ - return sample; \n\ - }\n"; - -static const char* const qopenglslGrayscaleImageSrcFragmentShader_core = "\n\ - in vec2 textureCoords; \n\ - uniform sampler2D imageTexture; \n\ - vec4 srcPixel() \n\ - { \n\ - return texture(imageTexture, textureCoords).rrra; \n\ - }\n"; - -static const char* const qopenglslAlphaImageSrcFragmentShader_core = "\n\ - in vec2 textureCoords; \n\ - uniform sampler2D imageTexture; \n\ - vec4 srcPixel() \n\ - { \n\ - return vec4(0, 0, 0, texture(imageTexture, textureCoords).r); \n\ - }\n"; - -static const char* const qopenglslShockingPinkSrcFragmentShader_core = "\n\ - vec4 srcPixel() \n\ - { \n\ - return vec4(0.98, 0.06, 0.75, 1.0); \n\ - }\n"; - -static const char* const qopenglslMainFragmentShader_ImageArrays_core = - "#version 150 core\n\ - in float opacity; \n\ - out vec4 fragColor; \n\ - vec4 srcPixel(); \n\ - void main() \n\ - { \n\ - fragColor = srcPixel() * opacity; \n\ - }\n"; - -static const char* const qopenglslMainFragmentShader_MO_core = - "#version 150 core\n\ - out vec4 fragColor; \n\ - uniform float globalOpacity; \n\ - vec4 srcPixel(); \n\ - vec4 applyMask(vec4); \n\ - void main() \n\ - { \n\ - fragColor = applyMask(srcPixel()*globalOpacity); \n\ - }\n"; - -static const char* const qopenglslMainFragmentShader_M_core = - "#version 150 core\n\ - out vec4 fragColor; \n\ - vec4 srcPixel(); \n\ - vec4 applyMask(vec4); \n\ - void main() \n\ - { \n\ - fragColor = applyMask(srcPixel()); \n\ - }\n"; - -static const char* const qopenglslMainFragmentShader_O_core = - "#version 150 core\n\ - out vec4 fragColor; \n\ - uniform float globalOpacity; \n\ - vec4 srcPixel(); \n\ - void main() \n\ - { \n\ - fragColor = srcPixel()*globalOpacity; \n\ - }\n"; - -static const char* const qopenglslMainFragmentShader_core = - "#version 150 core\n\ - out vec4 fragColor; \n\ - vec4 srcPixel(); \n\ - void main() \n\ - { \n\ - fragColor = srcPixel(); \n\ - }\n"; - -static const char* const qopenglslMaskFragmentShader_core = "\n\ - in vec2 textureCoords;\n\ - uniform sampler2D maskTexture;\n\ - vec4 applyMask(vec4 src) \n\ - {\n\ - vec4 mask = texture(maskTexture, textureCoords); \n\ - return src * mask.r; \n\ - }\n"; - -// For source over with subpixel antialiasing, the final color is calculated per component as follows -// (.a is alpha component, .c is red, green or blue component): -// alpha = src.a * mask.c * opacity -// dest.c = dest.c * (1 - alpha) + src.c * alpha -// -// In the first pass, calculate: dest.c = dest.c * (1 - alpha) with blend funcs: zero, 1 - source color -// In the second pass, calculate: dest.c = dest.c + src.c * alpha with blend funcs: one, one -// -// If source is a solid color (src is constant), only the first pass is needed, with blend funcs: constant, 1 - source color - -// For source composition with subpixel antialiasing, the final color is calculated per component as follows: -// alpha = src.a * mask.c * opacity -// dest.c = dest.c * (1 - mask.c) + src.c * alpha -// - -static const char* const qopenglslRgbMaskFragmentShaderPass1_core = "\n\ - in vec2 textureCoords;\n\ - uniform sampler2D maskTexture;\n\ - vec4 applyMask(vec4 src) \n\ - { \n\ - vec4 mask = texture(maskTexture, textureCoords); \n\ - return src.a * mask; \n\ - }\n"; - -static const char* const qopenglslRgbMaskFragmentShaderPass2_core = "\n\ - in vec2 textureCoords;\n\ - uniform sampler2D maskTexture;\n\ - vec4 applyMask(vec4 src) \n\ - { \n\ - vec4 mask = texture(maskTexture, textureCoords); \n\ - return src * mask; \n\ - }\n"; - -/* - Left to implement: - RgbMaskFragmentShader_core, - RgbMaskWithGammaFragmentShader_core, -*/ - -QT_END_NAMESPACE - -#endif // GLGC_SHADER_SOURCE_H diff --git a/src/gui/opengl/qopenglframebufferobject.cpp b/src/gui/opengl/qopenglframebufferobject.cpp deleted file mode 100644 index d7a6d32218..0000000000 --- a/src/gui/opengl/qopenglframebufferobject.cpp +++ /dev/null @@ -1,1857 +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 "qopenglframebufferobject.h" -#include "qopenglframebufferobject_p.h" - -#include <qdebug.h> -#include <private/qopengl_p.h> -#include <private/qopenglcontext_p.h> -#include <private/qopenglextensions_p.h> -#include <private/qfont_p.h> - -#include <qwindow.h> -#include <qimage.h> -#include <QtCore/qbytearray.h> - -QT_BEGIN_NAMESPACE - -#ifndef QT_NO_DEBUG -#define QT_RESET_GLERROR() \ -{ \ - while (true) {\ - GLenum error = QOpenGLContext::currentContext()->functions()->glGetError(); \ - if (error == GL_NO_ERROR || error == GL_CONTEXT_LOST) \ - break; \ - } \ -} -#define QT_CHECK_GLERROR() \ -{ \ - GLenum err = QOpenGLContext::currentContext()->functions()->glGetError(); \ - if (err != GL_NO_ERROR && err != GL_CONTEXT_LOST) { \ - qDebug("[%s line %d] OpenGL Error: %d", \ - __FILE__, __LINE__, (int)err); \ - } \ -} -#else -#define QT_RESET_GLERROR() {} -#define QT_CHECK_GLERROR() {} -#endif - -#ifndef GL_MAX_SAMPLES -#define GL_MAX_SAMPLES 0x8D57 -#endif - -#ifndef GL_RENDERBUFFER_SAMPLES -#define GL_RENDERBUFFER_SAMPLES 0x8CAB -#endif - -#ifndef GL_DEPTH24_STENCIL8 -#define GL_DEPTH24_STENCIL8 0x88F0 -#endif - -#ifndef GL_DEPTH_COMPONENT24 -#define GL_DEPTH_COMPONENT24 0x81A6 -#endif - -#ifndef GL_DEPTH_COMPONENT24_OES -#define GL_DEPTH_COMPONENT24_OES 0x81A6 -#endif - -#ifndef GL_READ_FRAMEBUFFER -#define GL_READ_FRAMEBUFFER 0x8CA8 -#endif - -#ifndef GL_DRAW_FRAMEBUFFER -#define GL_DRAW_FRAMEBUFFER 0x8CA9 -#endif - -#ifndef GL_RGB8 -#define GL_RGB8 0x8051 -#endif - -#ifndef GL_RGB10 -#define GL_RGB10 0x8052 -#endif - -#ifndef GL_RGB16 -#define GL_RGB16 0x8054 -#endif - -#ifndef GL_RGBA8 -#define GL_RGBA8 0x8058 -#endif - -#ifndef GL_RGB10_A2 -#define GL_RGB10_A2 0x8059 -#endif - -#ifndef GL_RGBA16 -#define GL_RGBA16 0x805B -#endif - -#ifndef GL_BGRA -#define GL_BGRA 0x80E1 -#endif - -#ifndef GL_UNSIGNED_INT_8_8_8_8_REV -#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 -#endif - -#ifndef GL_UNSIGNED_INT_2_10_10_10_REV -#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 -#endif - -#ifndef GL_CONTEXT_LOST -#define GL_CONTEXT_LOST 0x0507 -#endif - -#ifndef GL_DEPTH_STENCIL_ATTACHMENT -#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A -#endif - -#ifndef GL_DEPTH_STENCIL -#define GL_DEPTH_STENCIL 0x84F9 -#endif - - - -/*! - \class QOpenGLFramebufferObjectFormat - \brief The QOpenGLFramebufferObjectFormat class specifies the format of an OpenGL - framebuffer object. - \inmodule QtGui - - \since 5.0 - - \ingroup painting-3D - - A framebuffer object has several characteristics: - \list - \li \l{setSamples()}{Number of samples per pixels.} - \li \l{setAttachment()}{Depth and/or stencil attachments.} - \li \l{setTextureTarget()}{Texture target.} - \li \l{setInternalTextureFormat()}{Internal texture format.} - \endlist - - Note that the desired attachments or number of samples per pixels might not - be supported by the hardware driver. Call QOpenGLFramebufferObject::format() - after creating a QOpenGLFramebufferObject to find the exact format that was - used to create the frame buffer object. - - \sa QOpenGLFramebufferObject -*/ - -/*! - \internal -*/ -void QOpenGLFramebufferObjectFormat::detach() -{ - if (d->ref.loadRelaxed() != 1) { - QOpenGLFramebufferObjectFormatPrivate *newd - = new QOpenGLFramebufferObjectFormatPrivate(d); - if (!d->ref.deref()) - delete d; - d = newd; - } -} - -/*! - Creates a QOpenGLFramebufferObjectFormat object for specifying - the format of an OpenGL framebuffer object. - - By default the format specifies a non-multisample framebuffer object with no - depth/stencil attachments, texture target \c GL_TEXTURE_2D, and internal format \c GL_RGBA8. - On OpenGL/ES systems, the default internal format is \c GL_RGBA. - - \sa samples(), attachment(), internalTextureFormat() -*/ - -QOpenGLFramebufferObjectFormat::QOpenGLFramebufferObjectFormat() -{ - d = new QOpenGLFramebufferObjectFormatPrivate; -} - -/*! - Constructs a copy of \a other. -*/ - -QOpenGLFramebufferObjectFormat::QOpenGLFramebufferObjectFormat(const QOpenGLFramebufferObjectFormat &other) -{ - d = other.d; - d->ref.ref(); -} - -/*! - Assigns \a other to this object. -*/ - -QOpenGLFramebufferObjectFormat &QOpenGLFramebufferObjectFormat::operator=(const QOpenGLFramebufferObjectFormat &other) -{ - if (d != other.d) { - other.d->ref.ref(); - if (!d->ref.deref()) - delete d; - d = other.d; - } - return *this; -} - -/*! - Destroys the QOpenGLFramebufferObjectFormat. -*/ -QOpenGLFramebufferObjectFormat::~QOpenGLFramebufferObjectFormat() -{ - if (!d->ref.deref()) - delete d; -} - -/*! - Sets the number of samples per pixel for a multisample framebuffer object - to \a samples. The default sample count of 0 represents a regular - non-multisample framebuffer object. - - If the desired amount of samples per pixel is not supported by the hardware - then the maximum number of samples per pixel will be used. Note that - multisample framebuffer objects cannot be bound as textures. Also, the - \c{GL_EXT_framebuffer_multisample} extension is required to create a - framebuffer with more than one sample per pixel. - - \sa samples() -*/ -void QOpenGLFramebufferObjectFormat::setSamples(int samples) -{ - detach(); - d->samples = samples; -} - -/*! - Returns the number of samples per pixel if a framebuffer object - is a multisample framebuffer object. Otherwise, returns 0. - The default value is 0. - - \sa setSamples() -*/ -int QOpenGLFramebufferObjectFormat::samples() const -{ - return d->samples; -} - -/*! - Enables mipmapping if \a enabled is true; otherwise disables it. - - Mipmapping is disabled by default. - - If mipmapping is enabled, additional memory will be allocated for - the mipmap levels. The mipmap levels can be updated by binding the - texture and calling glGenerateMipmap(). Mipmapping cannot be enabled - for multisampled framebuffer objects. - - \sa mipmap(), QOpenGLFramebufferObject::texture() -*/ -void QOpenGLFramebufferObjectFormat::setMipmap(bool enabled) -{ - detach(); - d->mipmap = enabled; -} - -/*! - Returns \c true if mipmapping is enabled. - - \sa setMipmap() -*/ -bool QOpenGLFramebufferObjectFormat::mipmap() const -{ - return d->mipmap; -} - -/*! - Sets the attachment configuration of a framebuffer object to \a attachment. - - \sa attachment() -*/ -void QOpenGLFramebufferObjectFormat::setAttachment(QOpenGLFramebufferObject::Attachment attachment) -{ - detach(); - d->attachment = attachment; -} - -/*! - Returns the configuration of the depth and stencil buffers attached to - a framebuffer object. The default is QOpenGLFramebufferObject::NoAttachment. - - \sa setAttachment() -*/ -QOpenGLFramebufferObject::Attachment QOpenGLFramebufferObjectFormat::attachment() const -{ - return d->attachment; -} - -/*! - Sets the texture target of the texture attached to a framebuffer object to - \a target. Ignored for multisample framebuffer objects. - - \sa textureTarget(), samples() -*/ -void QOpenGLFramebufferObjectFormat::setTextureTarget(GLenum target) -{ - detach(); - d->target = target; -} - -/*! - Returns the texture target of the texture attached to a framebuffer object. - Ignored for multisample framebuffer objects. The default is - \c GL_TEXTURE_2D. - - \sa setTextureTarget(), samples() -*/ -GLenum QOpenGLFramebufferObjectFormat::textureTarget() const -{ - return d->target; -} - -/*! - Sets the internal format of a framebuffer object's texture or - multisample framebuffer object's color buffer to - \a internalTextureFormat. - - \sa internalTextureFormat() -*/ -void QOpenGLFramebufferObjectFormat::setInternalTextureFormat(GLenum internalTextureFormat) -{ - detach(); - d->internal_format = internalTextureFormat; -} - -/*! - Returns the internal format of a framebuffer object's texture or - multisample framebuffer object's color buffer. The default is - \c GL_RGBA8 on desktop OpenGL systems, and \c GL_RGBA on - OpenGL/ES systems. - - \sa setInternalTextureFormat() -*/ -GLenum QOpenGLFramebufferObjectFormat::internalTextureFormat() const -{ - return d->internal_format; -} - -/*! - Returns \c true if all the options of this framebuffer object format - are the same as \a other; otherwise returns \c false. -*/ -bool QOpenGLFramebufferObjectFormat::operator==(const QOpenGLFramebufferObjectFormat& other) const -{ - if (d == other.d) - return true; - else - return d->equals(other.d); -} - -/*! - Returns \c false if all the options of this framebuffer object format - are the same as \a other; otherwise returns \c true. -*/ -bool QOpenGLFramebufferObjectFormat::operator!=(const QOpenGLFramebufferObjectFormat& other) const -{ - return !(*this == other); -} - -bool QOpenGLFramebufferObjectPrivate::checkFramebufferStatus(QOpenGLContext *ctx) const -{ - if (!ctx) - return false; // Context no longer exists. - GLenum status = ctx->functions()->glCheckFramebufferStatus(GL_FRAMEBUFFER); - switch(status) { - case GL_NO_ERROR: - case GL_FRAMEBUFFER_COMPLETE: - return true; - case GL_FRAMEBUFFER_UNSUPPORTED: - qDebug("QOpenGLFramebufferObject: Unsupported framebuffer format."); - break; - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - qDebug("QOpenGLFramebufferObject: Framebuffer incomplete attachment."); - break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: - qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, missing attachment."); - break; -#ifdef GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT - case GL_FRAMEBUFFER_INCOMPLETE_DUPLICATE_ATTACHMENT: - qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, duplicate attachment."); - break; -#endif -#ifdef GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS - case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: - qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, attached images must have same dimensions."); - break; -#endif -#ifdef GL_FRAMEBUFFER_INCOMPLETE_FORMATS - case GL_FRAMEBUFFER_INCOMPLETE_FORMATS: - qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, attached images must have same format."); - break; -#endif -#ifdef GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: - qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, missing draw buffer."); - break; -#endif -#ifdef GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: - qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, missing read buffer."); - break; -#endif -#ifdef GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE - case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: - qDebug("QOpenGLFramebufferObject: Framebuffer incomplete, attachments must have same number of samples per pixel."); - break; -#endif - default: - qDebug() <<"QOpenGLFramebufferObject: An undefined error has occurred: "<< status; - break; - } - return false; -} - -namespace -{ - void freeFramebufferFunc(QOpenGLFunctions *funcs, GLuint id) - { - funcs->glDeleteFramebuffers(1, &id); - } - - void freeRenderbufferFunc(QOpenGLFunctions *funcs, GLuint id) - { - funcs->glDeleteRenderbuffers(1, &id); - } - - void freeTextureFunc(QOpenGLFunctions *funcs, GLuint id) - { - funcs->glDeleteTextures(1, &id); - } -} - -void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSize &size, - QOpenGLFramebufferObject::Attachment attachment, - GLenum texture_target, GLenum internal_format, - GLint samples, bool mipmap) -{ - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - - funcs.initializeOpenGLFunctions(); - - if (!funcs.hasOpenGLFeature(QOpenGLFunctions::Framebuffers)) - return; - - // Fall back to using a normal non-msaa FBO if we don't have support for MSAA - if (!funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample) - || !funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit)) { - samples = 0; - } else if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) { - GLint maxSamples; - funcs.glGetIntegerv(GL_MAX_SAMPLES, &maxSamples); - samples = qBound(0, int(samples), int(maxSamples)); - } - - colorAttachments.append(ColorAttachment(size, internal_format)); - - dsSize = size; - - samples = qMax(0, samples); - requestedSamples = samples; - - target = texture_target; - - QT_RESET_GLERROR(); // reset error state - GLuint fbo = 0; - - funcs.glGenFramebuffers(1, &fbo); - funcs.glBindFramebuffer(GL_FRAMEBUFFER, fbo); - - QOpenGLContextPrivate::get(ctx)->qgl_current_fbo_invalid = true; - - QT_CHECK_GLERROR(); - - format.setTextureTarget(target); - format.setInternalTextureFormat(internal_format); - format.setMipmap(mipmap); - - if (samples == 0) - initTexture(0); - else - initColorBuffer(0, &samples); - - format.setSamples(int(samples)); - - initDepthStencilAttachments(ctx, attachment); - - if (valid) - fbo_guard = new QOpenGLSharedResourceGuard(ctx, fbo, freeFramebufferFunc); - else - funcs.glDeleteFramebuffers(1, &fbo); - - QT_CHECK_GLERROR(); -} - -void QOpenGLFramebufferObjectPrivate::initTexture(int idx) -{ - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - GLuint texture = 0; - - funcs.glGenTextures(1, &texture); - funcs.glBindTexture(target, texture); - - funcs.glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - funcs.glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - funcs.glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - funcs.glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - ColorAttachment &color(colorAttachments[idx]); - - GLuint pixelType = GL_UNSIGNED_BYTE; - if (color.internalFormat == GL_RGB10_A2 || color.internalFormat == GL_RGB10) - pixelType = GL_UNSIGNED_INT_2_10_10_10_REV; - else if (color.internalFormat == GL_RGB16 || color.internalFormat == GL_RGBA16) - pixelType = GL_UNSIGNED_SHORT; - - funcs.glTexImage2D(target, 0, color.internalFormat, color.size.width(), color.size.height(), 0, - GL_RGBA, pixelType, nullptr); - if (format.mipmap()) { - int width = color.size.width(); - int height = color.size.height(); - int level = 0; - while (width > 1 || height > 1) { - width = qMax(1, width >> 1); - height = qMax(1, height >> 1); - ++level; - funcs.glTexImage2D(target, level, color.internalFormat, width, height, 0, - GL_RGBA, pixelType, nullptr); - } - } - funcs.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + idx, - target, texture, 0); - - QT_CHECK_GLERROR(); - funcs.glBindTexture(target, 0); - valid = checkFramebufferStatus(ctx); - if (valid) { - color.guard = new QOpenGLSharedResourceGuard(ctx, texture, freeTextureFunc); - } else { - funcs.glDeleteTextures(1, &texture); - } -} - -void QOpenGLFramebufferObjectPrivate::initColorBuffer(int idx, GLint *samples) -{ - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - GLuint color_buffer = 0; - - ColorAttachment &color(colorAttachments[idx]); - - GLenum storageFormat = color.internalFormat; - // ES requires a sized format. The older desktop extension does not. Correct the format on ES. - if (ctx->isOpenGLES()) { - if (color.internalFormat == GL_RGBA) { - if (funcs.hasOpenGLExtension(QOpenGLExtensions::Sized8Formats)) - storageFormat = GL_RGBA8; - else - storageFormat = GL_RGBA4; - } else if (color.internalFormat == GL_RGB10) { - // GL_RGB10 is not allowed in ES for glRenderbufferStorage. - storageFormat = GL_RGB10_A2; - } - } - - funcs.glGenRenderbuffers(1, &color_buffer); - funcs.glBindRenderbuffer(GL_RENDERBUFFER, color_buffer); - funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, *samples, storageFormat, color.size.width(), color.size.height()); - funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + idx, - GL_RENDERBUFFER, color_buffer); - - QT_CHECK_GLERROR(); - valid = checkFramebufferStatus(ctx); - if (valid) { - // Query the actual number of samples. This can be greater than the requested - // value since the typically supported values are 0, 4, 8, ..., and the - // requests are mapped to the next supported value. - funcs.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, samples); - color.guard = new QOpenGLSharedResourceGuard(ctx, color_buffer, freeRenderbufferFunc); - } else { - funcs.glDeleteRenderbuffers(1, &color_buffer); - } -} - -void QOpenGLFramebufferObjectPrivate::initDepthStencilAttachments(QOpenGLContext *ctx, - QOpenGLFramebufferObject::Attachment attachment) -{ - // Use the same sample count for all attachments. format.samples() already contains - // the actual number of samples for the color attachment and is not suitable. Use - // requestedSamples instead. - const int samples = requestedSamples; - - // free existing attachments - if (depth_buffer_guard) { -#ifdef Q_OS_WASM - funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0); -#else - funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); -#endif - depth_buffer_guard->free(); - } - if (stencil_buffer_guard) { - funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0); - if (stencil_buffer_guard != depth_buffer_guard) - stencil_buffer_guard->free(); - } - - depth_buffer_guard = nullptr; - stencil_buffer_guard = nullptr; - - GLuint depth_buffer = 0; - GLuint stencil_buffer = 0; - - // In practice, a combined depth-stencil buffer is supported by all desktop platforms, while a - // separate stencil buffer is not. On embedded devices however, a combined depth-stencil buffer - // might not be supported while separate buffers are, according to QTBUG-12861. -#ifdef Q_OS_WASM - // WebGL doesn't allow separately attach buffers to - // STENCIL_ATTACHMENT and DEPTH_ATTACHMENT - // QTBUG-69913 - if (attachment == QOpenGLFramebufferObject::CombinedDepthStencil) { - funcs.glGenRenderbuffers(1, &depth_buffer); - funcs.glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer); - Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer)); - - if (samples != 0 ) { - funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, - GL_DEPTH24_STENCIL8, dsSize.width(), dsSize.height()); - } else { - funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_STENCIL, - dsSize.width(), dsSize.height()); - } - - funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, depth_buffer); - - valid = checkFramebufferStatus(ctx); - if (!valid) { - funcs.glDeleteRenderbuffers(1, &depth_buffer); - depth_buffer = 0; - } - } -#else - if (attachment == QOpenGLFramebufferObject::CombinedDepthStencil - && funcs.hasOpenGLExtension(QOpenGLExtensions::PackedDepthStencil)) - { - // depth and stencil buffer needs another extension - funcs.glGenRenderbuffers(1, &depth_buffer); - funcs.glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer); - Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer)); - if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) - funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, - GL_DEPTH24_STENCIL8, dsSize.width(), dsSize.height()); - else - funcs.glRenderbufferStorage(GL_RENDERBUFFER, - GL_DEPTH24_STENCIL8, dsSize.width(), dsSize.height()); - - stencil_buffer = depth_buffer; - funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - GL_RENDERBUFFER, depth_buffer); - funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, stencil_buffer); - - valid = checkFramebufferStatus(ctx); - if (!valid) { - funcs.glDeleteRenderbuffers(1, &depth_buffer); - stencil_buffer = depth_buffer = 0; - } - } - - if (depth_buffer == 0 && (attachment == QOpenGLFramebufferObject::CombinedDepthStencil - || (attachment == QOpenGLFramebufferObject::Depth))) - { - funcs.glGenRenderbuffers(1, &depth_buffer); - funcs.glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer); - Q_ASSERT(funcs.glIsRenderbuffer(depth_buffer)); - if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) { - if (ctx->isOpenGLES()) { - if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) - funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, - GL_DEPTH_COMPONENT24, dsSize.width(), dsSize.height()); - else - funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, - GL_DEPTH_COMPONENT16, dsSize.width(), dsSize.height()); - } else { - funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, - GL_DEPTH_COMPONENT, dsSize.width(), dsSize.height()); - } - } else { - if (ctx->isOpenGLES()) { - if (funcs.hasOpenGLExtension(QOpenGLExtensions::Depth24)) { - funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, - dsSize.width(), dsSize.height()); - } else { - funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, - dsSize.width(), dsSize.height()); - } - } else { - funcs.glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, dsSize.width(), dsSize.height()); - } - } - funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - GL_RENDERBUFFER, depth_buffer); - valid = checkFramebufferStatus(ctx); - if (!valid) { - funcs.glDeleteRenderbuffers(1, &depth_buffer); - depth_buffer = 0; - } - } - - if (stencil_buffer == 0 && (attachment == QOpenGLFramebufferObject::CombinedDepthStencil)) { - funcs.glGenRenderbuffers(1, &stencil_buffer); - funcs.glBindRenderbuffer(GL_RENDERBUFFER, stencil_buffer); - Q_ASSERT(funcs.glIsRenderbuffer(stencil_buffer)); - -#ifdef QT_OPENGL_ES - GLenum storage = GL_STENCIL_INDEX8; -#else - GLenum storage = ctx->isOpenGLES() ? GL_STENCIL_INDEX8 : GL_STENCIL_INDEX; -#endif - - if (samples != 0 && funcs.hasOpenGLExtension(QOpenGLExtensions::FramebufferMultisample)) - funcs.glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, storage, dsSize.width(), dsSize.height()); - else - funcs.glRenderbufferStorage(GL_RENDERBUFFER, storage, dsSize.width(), dsSize.height()); - - funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, - GL_RENDERBUFFER, stencil_buffer); - valid = checkFramebufferStatus(ctx); - if (!valid) { - funcs.glDeleteRenderbuffers(1, &stencil_buffer); - stencil_buffer = 0; - } - } -#endif //Q_OS_WASM - - // The FBO might have become valid after removing the depth or stencil buffer. - valid = checkFramebufferStatus(ctx); - -#ifdef Q_OS_WASM - if (depth_buffer) { -#else - if (depth_buffer && stencil_buffer) { -#endif - fbo_attachment = QOpenGLFramebufferObject::CombinedDepthStencil; - } else if (depth_buffer) { - fbo_attachment = QOpenGLFramebufferObject::Depth; - } else { - fbo_attachment = QOpenGLFramebufferObject::NoAttachment; - } - - if (valid) { - if (depth_buffer) - depth_buffer_guard = new QOpenGLSharedResourceGuard(ctx, depth_buffer, freeRenderbufferFunc); - if (stencil_buffer) { - if (stencil_buffer == depth_buffer) - stencil_buffer_guard = depth_buffer_guard; - else - stencil_buffer_guard = new QOpenGLSharedResourceGuard(ctx, stencil_buffer, freeRenderbufferFunc); - } - } else { - if (depth_buffer) - funcs.glDeleteRenderbuffers(1, &depth_buffer); - if (stencil_buffer && depth_buffer != stencil_buffer) - funcs.glDeleteRenderbuffers(1, &stencil_buffer); - } - QT_CHECK_GLERROR(); - - format.setAttachment(fbo_attachment); -} - -/*! - \class QOpenGLFramebufferObject - \brief The QOpenGLFramebufferObject class encapsulates an OpenGL framebuffer object. - \since 5.0 - \inmodule QtGui - - \ingroup painting-3D - - The QOpenGLFramebufferObject class encapsulates an OpenGL framebuffer - object, defined by the \c{GL_EXT_framebuffer_object} extension. It provides - a rendering surface that can be painted on with a QPainter with the help of - QOpenGLPaintDevice, or rendered to using native OpenGL calls. This surface - can be bound and used as a regular texture in your own OpenGL drawing code. - By default, the QOpenGLFramebufferObject class generates a 2D OpenGL - texture (using the \c{GL_TEXTURE_2D} target), which is used as the internal - rendering target. - - \b{It is important to have a current OpenGL context when creating a - QOpenGLFramebufferObject, otherwise initialization will fail.} - - Create the QOpenGLFrameBufferObject instance with the CombinedDepthStencil - attachment if you want QPainter to render correctly. Note that you need to - create a QOpenGLFramebufferObject with more than one sample per pixel for - primitives to be antialiased when drawing using a QPainter. To create a - multisample framebuffer object you should use one of the constructors that - take a QOpenGLFramebufferObjectFormat parameter, and set the - QOpenGLFramebufferObjectFormat::samples() property to a non-zero value. - - For multisample framebuffer objects a color render buffer is created, - otherwise a texture with the specified texture target is created. - The color render buffer or texture will have the specified internal - format, and will be bound to the \c GL_COLOR_ATTACHMENT0 - attachment in the framebuffer object. - - Multiple render targets are also supported, in case the OpenGL - implementation supports this. Here there will be multiple textures (or, in - case of multisampling, renderbuffers) present and each of them will get - attached to \c GL_COLOR_ATTACHMENT0, \c 1, \c 2, ... - - If you want to use a framebuffer object with multisampling enabled - as a texture, you first need to copy from it to a regular framebuffer - object using QOpenGLContext::blitFramebuffer(). - - It is possible to draw into a QOpenGLFramebufferObject using QPainter and - QOpenGLPaintDevice in a separate thread. -*/ - - -/*! - \enum QOpenGLFramebufferObject::Attachment - - This enum type is used to configure the depth and stencil buffers - attached to the framebuffer object when it is created. - - \value NoAttachment No attachment is added to the framebuffer object. Note that the - OpenGL depth and stencil tests won't work when rendering to a - framebuffer object without any depth or stencil buffers. - This is the default value. - - \value CombinedDepthStencil If the \c GL_EXT_packed_depth_stencil extension is present, - a combined depth and stencil buffer is attached. - If the extension is not present, only a depth buffer is attached. - - \value Depth A depth buffer is attached to the framebuffer object. - - \sa attachment() -*/ - -static inline GLenum effectiveInternalFormat(GLenum internalFormat) -{ - if (!internalFormat) -#ifdef QT_OPENGL_ES_2 - internalFormat = GL_RGBA; -#else - internalFormat = QOpenGLContext::currentContext()->isOpenGLES() ? GL_RGBA : GL_RGBA8; -#endif - return internalFormat; -} - -/*! - - Constructs an OpenGL framebuffer object and binds a 2D OpenGL texture - to the buffer of the size \a size. The texture is bound to the - \c GL_COLOR_ATTACHMENT0 target in the framebuffer object. - - The \a target parameter is used to specify the OpenGL texture - target. The default target is \c GL_TEXTURE_2D. Keep in mind that - \c GL_TEXTURE_2D textures must have a power of 2 width and height - (e.g. 256x512), unless you are using OpenGL 2.0 or higher. - - By default, no depth and stencil buffers are attached. This behavior - can be toggled using one of the overloaded constructors. - - The default internal texture format is \c GL_RGBA8 for desktop - OpenGL, and \c GL_RGBA for OpenGL/ES. - - It is important that you have a current OpenGL context set when - creating the QOpenGLFramebufferObject, otherwise the initialization - will fail. - - \sa size(), texture(), attachment() -*/ - -QOpenGLFramebufferObject::QOpenGLFramebufferObject(const QSize &size, GLenum target) - : d_ptr(new QOpenGLFramebufferObjectPrivate) -{ - Q_D(QOpenGLFramebufferObject); - d->init(this, size, NoAttachment, target, effectiveInternalFormat(0)); -} - -/*! - - Constructs an OpenGL framebuffer object and binds a 2D OpenGL texture - to the buffer of the given \a width and \a height. - - \sa size(), texture() -*/ -QOpenGLFramebufferObject::QOpenGLFramebufferObject(int width, int height, GLenum target) - : QOpenGLFramebufferObject(QSize(width, height), target) -{ -} - -/*! - - Constructs an OpenGL framebuffer object of the given \a size based on the - supplied \a format. -*/ - -QOpenGLFramebufferObject::QOpenGLFramebufferObject(const QSize &size, const QOpenGLFramebufferObjectFormat &format) - : d_ptr(new QOpenGLFramebufferObjectPrivate) -{ - Q_D(QOpenGLFramebufferObject); - d->init(this, size, format.attachment(), format.textureTarget(), format.internalTextureFormat(), - format.samples(), format.mipmap()); -} - -/*! - - Constructs an OpenGL framebuffer object of the given \a width and \a height - based on the supplied \a format. -*/ - -QOpenGLFramebufferObject::QOpenGLFramebufferObject(int width, int height, const QOpenGLFramebufferObjectFormat &format) - : QOpenGLFramebufferObject(QSize(width, height), format) -{ -} - -/*! - - Constructs an OpenGL framebuffer object and binds a texture to the - buffer of the given \a width and \a height. - - The \a attachment parameter describes the depth/stencil buffer - configuration, \a target the texture target and \a internalFormat - the internal texture format. The default texture target is \c - GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8 - for desktop OpenGL and \c GL_RGBA for OpenGL/ES. - - \sa size(), texture(), attachment() -*/ -QOpenGLFramebufferObject::QOpenGLFramebufferObject(int width, int height, Attachment attachment, - GLenum target, GLenum internalFormat) - : d_ptr(new QOpenGLFramebufferObjectPrivate) -{ - Q_D(QOpenGLFramebufferObject); - d->init(this, QSize(width, height), attachment, target, effectiveInternalFormat(internalFormat)); -} - -/*! - - Constructs an OpenGL framebuffer object and binds a texture to the - buffer of the given \a size. - - The \a attachment parameter describes the depth/stencil buffer - configuration, \a target the texture target and \a internalFormat - the internal texture format. The default texture target is \c - GL_TEXTURE_2D, while the default internal format is \c GL_RGBA8 - for desktop OpenGL and \c GL_RGBA for OpenGL/ES. - - \sa size(), texture(), attachment() -*/ -QOpenGLFramebufferObject::QOpenGLFramebufferObject(const QSize &size, Attachment attachment, - GLenum target, GLenum internalFormat) - : d_ptr(new QOpenGLFramebufferObjectPrivate) -{ - Q_D(QOpenGLFramebufferObject); - d->init(this, size, attachment, target, effectiveInternalFormat(internalFormat)); -} - -/*! - - Destroys the framebuffer object and frees any allocated resources. -*/ -QOpenGLFramebufferObject::~QOpenGLFramebufferObject() -{ - Q_D(QOpenGLFramebufferObject); - if (isBound()) - release(); - - for (const auto &color : qAsConst(d->colorAttachments)) { - if (color.guard) - color.guard->free(); - } - d->colorAttachments.clear(); - - if (d->depth_buffer_guard) - d->depth_buffer_guard->free(); - if (d->stencil_buffer_guard && d->stencil_buffer_guard != d->depth_buffer_guard) - d->stencil_buffer_guard->free(); - if (d->fbo_guard) - d->fbo_guard->free(); - - QOpenGLContextPrivate *contextPrv = QOpenGLContextPrivate::get(QOpenGLContext::currentContext()); - if (contextPrv && contextPrv->qgl_current_fbo == this) { - contextPrv->qgl_current_fbo_invalid = true; - contextPrv->qgl_current_fbo = nullptr; - } -} - -/*! - Creates and attaches an additional texture or renderbuffer of \a size width - and height. - - There is always an attachment at GL_COLOR_ATTACHMENT0. Call this function - to set up additional attachments at GL_COLOR_ATTACHMENT1, - GL_COLOR_ATTACHMENT2, ... - - When \a internalFormat is not \c 0, it specifies the internal format of the - texture or renderbuffer. Otherwise a default of GL_RGBA or GL_RGBA8 is - used. - - \note This is only functional when multiple render targets are supported by - the OpenGL implementation. When that is not the case, the function will not - add any additional color attachments. Call - QOpenGLFunctions::hasOpenGLFeature() with - QOpenGLFunctions::MultipleRenderTargets at runtime to check if MRT is - supported. - - \note The internal format of the color attachments may differ but there may - be limitations on the supported combinations, depending on the drivers. - - \note The size of the color attachments may differ but rendering is limited - to the area that fits all the attachments, according to the OpenGL - specification. Some drivers may not be fully conformant in this respect, - however. - - \since 5.6 - */ -void QOpenGLFramebufferObject::addColorAttachment(const QSize &size, GLenum internalFormat) -{ - Q_D(QOpenGLFramebufferObject); - - if (!QOpenGLContext::currentContext()->functions()->hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets)) { - qWarning("Multiple render targets not supported, ignoring extra color attachment request"); - return; - } - - QOpenGLFramebufferObjectPrivate::ColorAttachment color(size, effectiveInternalFormat(internalFormat)); - d->colorAttachments.append(color); - const int idx = d->colorAttachments.count() - 1; - - if (d->requestedSamples == 0) { - d->initTexture(idx); - } else { - GLint samples = d->requestedSamples; - d->initColorBuffer(idx, &samples); - } -} - -/*! \overload - - Creates and attaches an additional texture or renderbuffer of size \a width and \a height. - - When \a internalFormat is not \c 0, it specifies the internal format of the texture or - renderbuffer. Otherwise a default of GL_RGBA or GL_RGBA8 is used. - - \since 5.6 - */ -void QOpenGLFramebufferObject::addColorAttachment(int width, int height, GLenum internalFormat) -{ - addColorAttachment(QSize(width, height), internalFormat); -} - -/*! - \fn bool QOpenGLFramebufferObject::isValid() const - - Returns \c true if the framebuffer object is valid. - - The framebuffer can become invalid if the initialization process - fails, the user attaches an invalid buffer to the framebuffer - object, or a non-power of two width/height is specified as the - texture size if the texture target is \c{GL_TEXTURE_2D}. - The non-power of two limitation does not apply if the OpenGL version - is 2.0 or higher, or if the GL_ARB_texture_non_power_of_two extension - is present. - - The framebuffer can also become invalid if the QOpenGLContext that - the framebuffer was created within is destroyed and there are - no other shared contexts that can take over ownership of the - framebuffer. -*/ -bool QOpenGLFramebufferObject::isValid() const -{ - Q_D(const QOpenGLFramebufferObject); - return d->valid && d->fbo_guard && d->fbo_guard->id(); -} - -/*! - \fn bool QOpenGLFramebufferObject::bind() - - Switches rendering from the default, windowing system provided - framebuffer to this framebuffer object. - Returns \c true upon success, false otherwise. - - \note If takeTexture() was called, a new texture is created and associated - with the framebuffer object. This is potentially expensive and changes the - context state (the currently bound texture). - - \sa release() -*/ -bool QOpenGLFramebufferObject::bind() -{ - if (!isValid()) - return false; - Q_D(QOpenGLFramebufferObject); - QOpenGLContext *current = QOpenGLContext::currentContext(); - if (!current) - return false; -#ifdef QT_DEBUG - if (current->shareGroup() != d->fbo_guard->group()) - qWarning("QOpenGLFramebufferObject::bind() called from incompatible context"); -#endif - - d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, d->fbo()); - - QOpenGLContextPrivate::get(current)->qgl_current_fbo_invalid = true; - QOpenGLContextPrivate::get(current)->qgl_current_fbo = this; - - if (d->format.samples() == 0) { - // Create new textures to replace the ones stolen via takeTexture(). - for (int i = 0; i < d->colorAttachments.count(); ++i) { - if (!d->colorAttachments.at(i).guard) - d->initTexture(i); - } - } - - return d->valid; -} - -/*! - \fn bool QOpenGLFramebufferObject::release() - - Switches rendering back to the default, windowing system provided - framebuffer. - Returns \c true upon success, false otherwise. - - \sa bind() -*/ -bool QOpenGLFramebufferObject::release() -{ - if (!isValid()) - return false; - - QOpenGLContext *current = QOpenGLContext::currentContext(); - if (!current) - return false; - - Q_D(QOpenGLFramebufferObject); -#ifdef QT_DEBUG - if (current->shareGroup() != d->fbo_guard->group()) - qWarning("QOpenGLFramebufferObject::release() called from incompatible context"); -#endif - - if (current) { - d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, current->defaultFramebufferObject()); - - QOpenGLContextPrivate *contextPrv = QOpenGLContextPrivate::get(current); - contextPrv->qgl_current_fbo_invalid = true; - contextPrv->qgl_current_fbo = nullptr; - } - - return true; -} - -/*! - \fn GLuint QOpenGLFramebufferObject::texture() const - - Returns the texture id for the texture attached as the default - rendering target in this framebuffer object. This texture id can - be bound as a normal texture in your own OpenGL code. - - If a multisample framebuffer object is used then the value returned - from this function will be invalid. - - When multiple textures are attached, the return value is the ID of - the first one. - - \sa takeTexture(), textures() -*/ -GLuint QOpenGLFramebufferObject::texture() const -{ - Q_D(const QOpenGLFramebufferObject); - return d->colorAttachments[0].guard ? d->colorAttachments[0].guard->id() : 0; -} - -/*! - Returns the texture id for all attached textures. - - If a multisample framebuffer object is used, then an empty vector is returned. - - \since 5.6 - - \sa takeTexture(), texture() -*/ -QVector<GLuint> QOpenGLFramebufferObject::textures() const -{ - Q_D(const QOpenGLFramebufferObject); - QVector<GLuint> ids; - if (d->format.samples() != 0) - return ids; - ids.reserve(d->colorAttachments.count()); - for (const auto &color : d->colorAttachments) - ids.append(color.guard ? color.guard->id() : 0); - return ids; -} - -/*! - \fn GLuint QOpenGLFramebufferObject::takeTexture() - - Returns the texture id for the texture attached to this framebuffer - object. The ownership of the texture is transferred to the caller. - - If the framebuffer object is currently bound, an implicit release() - will be done. During the next call to bind() a new texture will be - created. - - If a multisample framebuffer object is used, then there is no - texture and the return value from this function will be invalid. - Similarly, incomplete framebuffer objects will also return 0. - - \since 5.3 - - \sa texture(), bind(), release() - */ -GLuint QOpenGLFramebufferObject::takeTexture() -{ - return takeTexture(0); -} - -/*! \overload - - Returns the texture id for the texture attached to the color attachment of - index \a colorAttachmentIndex of this framebuffer object. The ownership of - the texture is transferred to the caller. - - When \a colorAttachmentIndex is \c 0, the behavior is identical to the - parameter-less variant of this function. - - If the framebuffer object is currently bound, an implicit release() - will be done. During the next call to bind() a new texture will be - created. - - If a multisample framebuffer object is used, then there is no - texture and the return value from this function will be invalid. - Similarly, incomplete framebuffer objects will also return 0. - - \since 5.6 - */ -GLuint QOpenGLFramebufferObject::takeTexture(int colorAttachmentIndex) -{ - Q_D(QOpenGLFramebufferObject); - GLuint id = 0; - if (isValid() && d->format.samples() == 0 && d->colorAttachments.count() > colorAttachmentIndex) { - QOpenGLContext *current = QOpenGLContext::currentContext(); - if (current && current->shareGroup() == d->fbo_guard->group() && isBound()) - release(); - auto &guard = d->colorAttachments[colorAttachmentIndex].guard; - id = guard ? guard->id() : 0; - // Do not call free() on texture_guard, just null it out. - // This way the texture will not be deleted when the guard is destroyed. - guard = nullptr; - } - return id; -} - -/*! - \return the size of the color and depth/stencil attachments attached to - this framebuffer object. -*/ -QSize QOpenGLFramebufferObject::size() const -{ - Q_D(const QOpenGLFramebufferObject); - return d->dsSize; -} - -/*! - \return the sizes of all color attachments attached to this framebuffer - object. - - \since 5.6 -*/ -QVector<QSize> QOpenGLFramebufferObject::sizes() const -{ - Q_D(const QOpenGLFramebufferObject); - QVector<QSize> sz; - sz.reserve(d->colorAttachments.size()); - for (const auto &color : d->colorAttachments) - sz.append(color.size); - return sz; -} - -/*! - \fn int QOpenGLFramebufferObject::width() const - - Returns the width of the framebuffer object attachments. -*/ - -/*! - \fn int QOpenGLFramebufferObject::height() const - - Returns the height of the framebuffer object attachments. -*/ - -/*! - Returns the format of this framebuffer object. -*/ -QOpenGLFramebufferObjectFormat QOpenGLFramebufferObject::format() const -{ - Q_D(const QOpenGLFramebufferObject); - return d->format; -} - -static inline QImage qt_gl_read_framebuffer_rgba8(const QSize &size, bool include_alpha, QOpenGLContext *context) -{ - QOpenGLFunctions *funcs = context->functions(); - const int w = size.width(); - const int h = size.height(); - bool isOpenGL12orBetter = !context->isOpenGLES() && (context->format().majorVersion() >= 2 || context->format().minorVersion() >= 2); - if (isOpenGL12orBetter) { - QImage img(size, include_alpha ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32); - funcs->glReadPixels(0, 0, w, h, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, img.bits()); - return img; - } - - // For OpenGL ES stick with the byte ordered format / RGBA readback format - // since that is the only spec mandated way. (also, skip the - // GL_IMPLEMENTATION_COLOR_READ_FORMAT mess since there is nothing saying a - // BGRA capable impl would return BGRA from there) - - QImage rgbaImage(size, include_alpha ? QImage::Format_RGBA8888_Premultiplied : QImage::Format_RGBX8888); - funcs->glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, rgbaImage.bits()); - return rgbaImage; -} - -static inline QImage qt_gl_read_framebuffer_rgb10a2(const QSize &size, bool include_alpha, QOpenGLContext *context) -{ - // We assume OpenGL 1.2+ or ES 3.0+ here. - QImage img(size, include_alpha ? QImage::Format_A2BGR30_Premultiplied : QImage::Format_BGR30); - context->functions()->glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, img.bits()); - return img; -} - -static inline QImage qt_gl_read_framebuffer_rgba16(const QSize &size, bool include_alpha, QOpenGLContext *context) -{ - // We assume OpenGL 1.2+ or ES 3.0+ here. - QImage img(size, include_alpha ? QImage::Format_RGBA64_Premultiplied : QImage::Format_RGBX64); - context->functions()->glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_UNSIGNED_SHORT, img.bits()); - return img; -} - -static QImage qt_gl_read_framebuffer(const QSize &size, GLenum internal_format, bool include_alpha, bool flip) -{ - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - QOpenGLFunctions *funcs = ctx->functions(); - while (true) { - GLenum error = funcs->glGetError(); - if (error == GL_NO_ERROR || error == GL_CONTEXT_LOST) - break; - } - switch (internal_format) { - case GL_RGB: - case GL_RGB8: - return qt_gl_read_framebuffer_rgba8(size, false, ctx).mirrored(false, flip); - case GL_RGB10: - return qt_gl_read_framebuffer_rgb10a2(size, false, ctx).mirrored(false, flip); - case GL_RGB10_A2: - return qt_gl_read_framebuffer_rgb10a2(size, include_alpha, ctx).mirrored(false, flip); - case GL_RGB16: - return qt_gl_read_framebuffer_rgba16(size, false, ctx).mirrored(false, flip); - case GL_RGBA16: - return qt_gl_read_framebuffer_rgba16(size, include_alpha, ctx).mirrored(false, flip); - case GL_RGBA: - case GL_RGBA8: - default: - return qt_gl_read_framebuffer_rgba8(size, include_alpha, ctx).mirrored(false, flip); - } - - Q_UNREACHABLE(); - return QImage(); -} - -Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha) -{ - return qt_gl_read_framebuffer(size, alpha_format ? GL_RGBA : GL_RGB, include_alpha, true); -} - -/*! - \fn QImage QOpenGLFramebufferObject::toImage(bool flipped) const - - Returns the contents of this framebuffer object as a QImage. - - If \a flipped is true the image is flipped from OpenGL coordinates to raster coordinates. - If used together with QOpenGLPaintDevice, \a flipped should be the opposite of the value - of QOpenGLPaintDevice::paintFlipped(). - - The returned image has a format of premultiplied ARGB32 or RGB32. The latter - is used only when internalTextureFormat() is set to \c GL_RGB. Since Qt 5.2 - the function will fall back to premultiplied RGBA8888 or RGBx8888 when - reading to (A)RGB32 is not supported, and this includes OpenGL ES. Since Qt - 5.4 an A2BGR30 image is returned if the internal format is RGB10_A2, and since - Qt 5.12 a RGBA64 image is return if the internal format is RGBA16. - - If the rendering in the framebuffer was not done with premultiplied alpha in mind, - create a wrapper QImage with a non-premultiplied format. This is necessary before - performing operations like QImage::save() because otherwise the image data would get - unpremultiplied, even though it was not premultiplied in the first place. To create - such a wrapper without performing a copy of the pixel data, do the following: - - \code - QImage fboImage(fbo.toImage()); - QImage image(fboImage.constBits(), fboImage.width(), fboImage.height(), QImage::Format_ARGB32); - \endcode - - For multisampled framebuffer objects the samples are resolved using the - \c{GL_EXT_framebuffer_blit} extension. If the extension is not available, the contents - of the returned image is undefined. - - For singlesampled framebuffers the contents is retrieved via \c glReadPixels. This is - a potentially expensive and inefficient operation. Therefore it is recommended that - this function is used as seldom as possible. - - \sa QOpenGLPaintDevice::paintFlipped() -*/ - -QImage QOpenGLFramebufferObject::toImage(bool flipped) const -{ - return toImage(flipped, 0); -} - -/*! - \fn QImage QOpenGLFramebufferObject::toImage() const - \overload - - Returns the contents of this framebuffer object as a QImage. This method flips - the image from OpenGL coordinates to raster coordinates. -*/ -// ### Qt 6: Remove this method and make it a default argument instead. -QImage QOpenGLFramebufferObject::toImage() const -{ - return toImage(true, 0); -} - -/*! \overload - - Returns the contents of the color attachment of index \a - colorAttachmentIndex of this framebuffer object as a QImage. This method - flips the image from OpenGL coordinates to raster coordinates when \a - flipped is set to \c true. - - \note This overload is only fully functional when multiple render targets are - supported by the OpenGL implementation. When that is not the case, only one - color attachment will be set up. - - \since 5.6 -*/ -QImage QOpenGLFramebufferObject::toImage(bool flipped, int colorAttachmentIndex) const -{ - Q_D(const QOpenGLFramebufferObject); - if (!d->valid) - return QImage(); - - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - if (!ctx) { - qWarning("QOpenGLFramebufferObject::toImage() called without a current context"); - return QImage(); - } - - if (d->colorAttachments.count() <= colorAttachmentIndex) { - qWarning("QOpenGLFramebufferObject::toImage() called for missing color attachment"); - return QImage(); - } - - GLuint prevFbo = 0; - ctx->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &prevFbo); - - if (prevFbo != d->fbo()) - const_cast<QOpenGLFramebufferObject *>(this)->bind(); - - QImage image; - QOpenGLExtraFunctions *extraFuncs = ctx->extraFunctions(); - // qt_gl_read_framebuffer doesn't work on a multisample FBO - if (format().samples() != 0) { - QRect rect(QPoint(0, 0), size()); - QOpenGLFramebufferObjectFormat fmt; - if (extraFuncs->hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets)) { - fmt.setInternalTextureFormat(d->colorAttachments[colorAttachmentIndex].internalFormat); - QOpenGLFramebufferObject temp(d->colorAttachments[colorAttachmentIndex].size, fmt); - blitFramebuffer(&temp, rect, const_cast<QOpenGLFramebufferObject *>(this), rect, - GL_COLOR_BUFFER_BIT, GL_NEAREST, - colorAttachmentIndex, 0); - image = temp.toImage(flipped); - } else { - fmt.setInternalTextureFormat(d->colorAttachments[0].internalFormat); - QOpenGLFramebufferObject temp(size(), fmt); - blitFramebuffer(&temp, rect, const_cast<QOpenGLFramebufferObject *>(this), rect); - image = temp.toImage(flipped); - } - } else { - if (extraFuncs->hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets)) { - extraFuncs->glReadBuffer(GL_COLOR_ATTACHMENT0 + colorAttachmentIndex); - image = qt_gl_read_framebuffer(d->colorAttachments[colorAttachmentIndex].size, - d->colorAttachments[colorAttachmentIndex].internalFormat, - true, flipped); - extraFuncs->glReadBuffer(GL_COLOR_ATTACHMENT0); - } else { - image = qt_gl_read_framebuffer(d->colorAttachments[0].size, - d->colorAttachments[0].internalFormat, - true, flipped); - } - } - - if (prevFbo != d->fbo()) - ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, prevFbo); - - return image; -} - -/*! - \fn bool QOpenGLFramebufferObject::bindDefault() - - Switches rendering back to the default, windowing system provided - framebuffer. - Returns \c true upon success, false otherwise. - - \sa bind(), release() -*/ -bool QOpenGLFramebufferObject::bindDefault() -{ - QOpenGLContext *ctx = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext()); - - if (ctx) { - ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject()); - QOpenGLContextPrivate::get(ctx)->qgl_current_fbo_invalid = true; - QOpenGLContextPrivate::get(ctx)->qgl_current_fbo = nullptr; - } -#ifdef QT_DEBUG - else - qWarning("QOpenGLFramebufferObject::bindDefault() called without current context."); -#endif - - return ctx != nullptr; -} - -/*! - \fn bool QOpenGLFramebufferObject::hasOpenGLFramebufferObjects() - - Returns \c true if the OpenGL \c{GL_EXT_framebuffer_object} extension - is present on this system; otherwise returns \c false. -*/ -bool QOpenGLFramebufferObject::hasOpenGLFramebufferObjects() -{ - return QOpenGLContext::currentContext()->functions()->hasOpenGLFeature(QOpenGLFunctions::Framebuffers); -} - -/*! - \fn GLuint QOpenGLFramebufferObject::handle() const - - Returns the OpenGL framebuffer object handle for this framebuffer - object (returned by the \c{glGenFrameBuffersEXT()} function). This - handle can be used to attach new images or buffers to the - framebuffer. The user is responsible for cleaning up and - destroying these objects. -*/ -GLuint QOpenGLFramebufferObject::handle() const -{ - Q_D(const QOpenGLFramebufferObject); - return d->fbo(); -} - -/*! - Returns the status of the depth and stencil buffers attached to - this framebuffer object. -*/ - -QOpenGLFramebufferObject::Attachment QOpenGLFramebufferObject::attachment() const -{ - Q_D(const QOpenGLFramebufferObject); - if (d->valid) - return d->fbo_attachment; - return NoAttachment; -} - -/*! - Sets the attachments of the framebuffer object to \a attachment. - - This can be used to free or reattach the depth and stencil buffer - attachments as needed. - - \note This function alters the current framebuffer binding. - */ -void QOpenGLFramebufferObject::setAttachment(QOpenGLFramebufferObject::Attachment attachment) -{ - Q_D(QOpenGLFramebufferObject); - if (attachment == d->fbo_attachment || !isValid()) - return; - QOpenGLContext *current = QOpenGLContext::currentContext(); - if (!current) - return; -#ifdef QT_DEBUG - if (current->shareGroup() != d->fbo_guard->group()) - qWarning("QOpenGLFramebufferObject::setAttachment() called from incompatible context"); -#endif - d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, d->fbo()); - QOpenGLContextPrivate::get(current)->qgl_current_fbo_invalid = true; - d->initDepthStencilAttachments(current, attachment); -} - -/*! - Returns \c true if the framebuffer object is currently bound to the current context, - otherwise false is returned. -*/ -bool QOpenGLFramebufferObject::isBound() const -{ - Q_D(const QOpenGLFramebufferObject); - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - if (!ctx) - return false; - GLint fbo = 0; - ctx->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo); - return GLuint(fbo) == d->fbo(); -} - -/*! - \fn bool QOpenGLFramebufferObject::hasOpenGLFramebufferBlit() - - Returns \c true if the OpenGL \c{GL_EXT_framebuffer_blit} extension - is present on this system; otherwise returns \c false. - - \sa blitFramebuffer() -*/ -bool QOpenGLFramebufferObject::hasOpenGLFramebufferBlit() -{ - return QOpenGLExtensions(QOpenGLContext::currentContext()).hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit); -} - - -/*! - \overload - - Convenience overload to blit between two framebuffer objects. -*/ -void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target, - QOpenGLFramebufferObject *source, - GLbitfield buffers, GLenum filter) -{ - if (!target && !source) - return; - - QSize targetSize; - QSize sourceSize; - - if (target) - targetSize = target->size(); - if (source) - sourceSize = source->size(); - - if (targetSize.isEmpty()) - targetSize = sourceSize; - else if (sourceSize.isEmpty()) - sourceSize = targetSize; - - blitFramebuffer(target, QRect(QPoint(0, 0), targetSize), - source, QRect(QPoint(0, 0), sourceSize), - buffers, filter); -} - -/*! \overload - * - Convenience overload to blit between two framebuffer objects. -*/ -void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target, const QRect &targetRect, - QOpenGLFramebufferObject *source, const QRect &sourceRect, - GLbitfield buffers, - GLenum filter) -{ - blitFramebuffer(target, targetRect, source, sourceRect, buffers, filter, 0, 0); -} - -/*! - \enum QOpenGLFramebufferObject::FramebufferRestorePolicy - \since 5.7 - - This enum type is used to configure the behavior related to restoring - framebuffer bindings when calling blitFramebuffer(). - - \value DontRestoreFramebufferBinding Do not restore the previous framebuffer binding. - The caller is responsible for tracking and setting - the framebuffer binding as needed. - - \value RestoreFramebufferBindingToDefault After the blit operation, bind the default - framebuffer. - - \value RestoreFrameBufferBinding Restore the previously bound framebuffer. This is - potentially expensive because of the need to - query the currently bound framebuffer. - - \sa blitFramebuffer() -*/ - -/*! - \since 5.7 - - Blits from the \a sourceRect rectangle in the \a source framebuffer - object to the \a targetRect rectangle in the \a target framebuffer object. - - If \a source or \a target is 0, the default framebuffer will be used - instead of a framebuffer object as source or target respectively. - - This function will have no effect unless hasOpenGLFramebufferBlit() returns - true. - - The \a buffers parameter should be a mask consisting of any combination of - \c GL_COLOR_BUFFER_BIT, \c GL_DEPTH_BUFFER_BIT, and - \c GL_STENCIL_BUFFER_BIT. Any buffer type that is not present both - in the source and target buffers is ignored. - - The \a sourceRect and \a targetRect rectangles may have different sizes; - in this case \a buffers should not contain \c GL_DEPTH_BUFFER_BIT or - \c GL_STENCIL_BUFFER_BIT. The \a filter parameter should be set to - \c GL_LINEAR or \c GL_NEAREST, and specifies whether linear or nearest - interpolation should be used when scaling is performed. - - If \a source equals \a target a copy is performed within the same buffer. - Results are undefined if the source and target rectangles overlap and - have different sizes. The sizes must also be the same if any of the - framebuffer objects are multisample framebuffers. - - \note The scissor test will restrict the blit area if enabled. - - When multiple render targets are in use, \a readColorAttachmentIndex and \a - drawColorAttachmentIndex specify the index of the color attachments in the - source and destination framebuffers. - - The \a restorePolicy determines if the framebuffer that was bound prior to - calling this function should be restored, or if the default framebuffer - should be bound before returning, of if the caller is responsible for - tracking and setting the bound framebuffer. Restoring the previous - framebuffer can be relatively expensive due to the call to \c{glGetIntegerv} - which on some OpenGL drivers may imply a pipeline stall. - - \sa hasOpenGLFramebufferBlit() -*/ -void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target, const QRect &targetRect, - QOpenGLFramebufferObject *source, const QRect &sourceRect, - GLbitfield buffers, - GLenum filter, - int readColorAttachmentIndex, - int drawColorAttachmentIndex, - QOpenGLFramebufferObject::FramebufferRestorePolicy restorePolicy) -{ - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - if (!ctx) - return; - - QOpenGLExtensions extensions(ctx); - if (!extensions.hasOpenGLExtension(QOpenGLExtensions::FramebufferBlit)) - return; - - GLuint prevFbo = 0; - if (restorePolicy == RestoreFrameBufferBinding) - ctx->functions()->glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint *) &prevFbo); - - const int sx0 = sourceRect.left(); - const int sx1 = sourceRect.left() + sourceRect.width(); - const int sy0 = sourceRect.top(); - const int sy1 = sourceRect.top() + sourceRect.height(); - - const int tx0 = targetRect.left(); - const int tx1 = targetRect.left() + targetRect.width(); - const int ty0 = targetRect.top(); - const int ty1 = targetRect.top() + targetRect.height(); - - const GLuint defaultFboId = ctx->defaultFramebufferObject(); - - extensions.glBindFramebuffer(GL_READ_FRAMEBUFFER, source ? source->handle() : defaultFboId); - extensions.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target ? target->handle() : defaultFboId); - - const bool supportsMRT = extensions.hasOpenGLFeature(QOpenGLFunctions::MultipleRenderTargets); - if (supportsMRT) { - extensions.glReadBuffer(GL_COLOR_ATTACHMENT0 + readColorAttachmentIndex); - if (target) { - GLenum drawBuf = GL_COLOR_ATTACHMENT0 + drawColorAttachmentIndex; - extensions.glDrawBuffers(1, &drawBuf); - } - } - - extensions.glBlitFramebuffer(sx0, sy0, sx1, sy1, - tx0, ty0, tx1, ty1, - buffers, filter); - - if (supportsMRT) - extensions.glReadBuffer(GL_COLOR_ATTACHMENT0); - - switch (restorePolicy) { - case RestoreFrameBufferBinding: - ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, prevFbo); // sets both READ and DRAW - break; - - case RestoreFramebufferBindingToDefault: - ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, ctx->defaultFramebufferObject()); // sets both READ and DRAW - break; - - case DontRestoreFramebufferBinding: - break; - } -} - -/*! - \overload - - Convenience overload to blit between two framebuffer objects and - to restore the previous framebuffer binding. Equivalent to calling - blitFramebuffer(target, targetRect, source, sourceRect, buffers, filter, - readColorAttachmentIndex, drawColorAttachmentIndex, - RestoreFrameBufferBinding). -*/ -void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target, const QRect &targetRect, - QOpenGLFramebufferObject *source, const QRect &sourceRect, - GLbitfield buffers, - GLenum filter, - int readColorAttachmentIndex, - int drawColorAttachmentIndex) -{ - blitFramebuffer(target, targetRect, source, sourceRect, - buffers, filter, - readColorAttachmentIndex, - drawColorAttachmentIndex, - RestoreFrameBufferBinding); -} - -QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglframebufferobject.h b/src/gui/opengl/qopenglframebufferobject.h deleted file mode 100644 index 161054d1bf..0000000000 --- a/src/gui/opengl/qopenglframebufferobject.h +++ /dev/null @@ -1,200 +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 QOPENGLFRAMEBUFFEROBJECT_H -#define QOPENGLFRAMEBUFFEROBJECT_H - -#include <QtGui/qtguiglobal.h> - -#ifndef QT_NO_OPENGL - -#include <QtGui/qopengl.h> -#include <QtGui/qpaintdevice.h> - -#include <QtCore/qscopedpointer.h> - -#if defined(Q_CLANG_QDOC) -#undef GLuint -typedef unsigned int GLuint; -#undef GLenum -typedef unsigned int GLenum; -#undef GL_TEXTURE_2D -#define GL_TEXTURE_2D 0x0DE1 -#undef GLbitfield -typedef unsigned int GLbitfield; -#endif - -QT_BEGIN_NAMESPACE - -class QOpenGLFramebufferObjectPrivate; -class QOpenGLFramebufferObjectFormat; - -class Q_GUI_EXPORT QOpenGLFramebufferObject -{ - Q_DECLARE_PRIVATE(QOpenGLFramebufferObject) -public: - enum Attachment { - NoAttachment, - CombinedDepthStencil, - Depth - }; - - explicit QOpenGLFramebufferObject(const QSize &size, GLenum target = GL_TEXTURE_2D); - QOpenGLFramebufferObject(int width, int height, GLenum target = GL_TEXTURE_2D); - - QOpenGLFramebufferObject(const QSize &size, Attachment attachment, - GLenum target = GL_TEXTURE_2D, GLenum internalFormat = 0); - QOpenGLFramebufferObject(int width, int height, Attachment attachment, - GLenum target = GL_TEXTURE_2D, GLenum internalFormat = 0); - - QOpenGLFramebufferObject(const QSize &size, const QOpenGLFramebufferObjectFormat &format); - QOpenGLFramebufferObject(int width, int height, const QOpenGLFramebufferObjectFormat &format); - - virtual ~QOpenGLFramebufferObject(); - - void addColorAttachment(const QSize &size, GLenum internalFormat = 0); - void addColorAttachment(int width, int height, GLenum internalFormat = 0); - - QOpenGLFramebufferObjectFormat format() const; - - bool isValid() const; - bool isBound() const; - bool bind(); - bool release(); - - int width() const { return size().width(); } - int height() const { return size().height(); } - - GLuint texture() const; - QVector<GLuint> textures() const; - - GLuint takeTexture(); - GLuint takeTexture(int colorAttachmentIndex); - - QSize size() const; - QVector<QSize> sizes() const; - - QImage toImage() const; - QImage toImage(bool flipped) const; - QImage toImage(bool flipped, int colorAttachmentIndex) const; - - Attachment attachment() const; - void setAttachment(Attachment attachment); - - GLuint handle() const; - - static bool bindDefault(); - - static bool hasOpenGLFramebufferObjects(); - - static bool hasOpenGLFramebufferBlit(); - - enum FramebufferRestorePolicy { - DontRestoreFramebufferBinding, - RestoreFramebufferBindingToDefault, - RestoreFrameBufferBinding - }; - - static void blitFramebuffer(QOpenGLFramebufferObject *target, const QRect &targetRect, - QOpenGLFramebufferObject *source, const QRect &sourceRect, - GLbitfield buffers, - GLenum filter, - int readColorAttachmentIndex, - int drawColorAttachmentIndex, - FramebufferRestorePolicy restorePolicy); - static void blitFramebuffer(QOpenGLFramebufferObject *target, const QRect &targetRect, - QOpenGLFramebufferObject *source, const QRect &sourceRect, - GLbitfield buffers, - GLenum filter, - int readColorAttachmentIndex, - int drawColorAttachmentIndex); - static void blitFramebuffer(QOpenGLFramebufferObject *target, const QRect &targetRect, - QOpenGLFramebufferObject *source, const QRect &sourceRect, - GLbitfield buffers = GL_COLOR_BUFFER_BIT, - GLenum filter = GL_NEAREST); - static void blitFramebuffer(QOpenGLFramebufferObject *target, - QOpenGLFramebufferObject *source, - GLbitfield buffers = GL_COLOR_BUFFER_BIT, - GLenum filter = GL_NEAREST); - -private: - Q_DISABLE_COPY(QOpenGLFramebufferObject) - QScopedPointer<QOpenGLFramebufferObjectPrivate> d_ptr; - friend class QOpenGLPaintDevice; - friend class QOpenGLFBOGLPaintDevice; -}; - -class QOpenGLFramebufferObjectFormatPrivate; -class Q_GUI_EXPORT QOpenGLFramebufferObjectFormat -{ -public: - QOpenGLFramebufferObjectFormat(); - QOpenGLFramebufferObjectFormat(const QOpenGLFramebufferObjectFormat &other); - QOpenGLFramebufferObjectFormat &operator=(const QOpenGLFramebufferObjectFormat &other); - ~QOpenGLFramebufferObjectFormat(); - - void setSamples(int samples); - int samples() const; - - void setMipmap(bool enabled); - bool mipmap() const; - - void setAttachment(QOpenGLFramebufferObject::Attachment attachment); - QOpenGLFramebufferObject::Attachment attachment() const; - - void setTextureTarget(GLenum target); - GLenum textureTarget() const; - - void setInternalTextureFormat(GLenum internalTextureFormat); - GLenum internalTextureFormat() const; - - bool operator==(const QOpenGLFramebufferObjectFormat& other) const; - bool operator!=(const QOpenGLFramebufferObjectFormat& other) const; - -private: - QOpenGLFramebufferObjectFormatPrivate *d; - - void detach(); -}; - -QT_END_NAMESPACE - -#endif // QT_NO_OPENGL - -#endif // QOPENGLFRAMEBUFFEROBJECT_H diff --git a/src/gui/opengl/qopenglframebufferobject_p.h b/src/gui/opengl/qopenglframebufferobject_p.h deleted file mode 100644 index 644bb6c59b..0000000000 --- a/src/gui/opengl/qopenglframebufferobject_p.h +++ /dev/null @@ -1,153 +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 QOPENGLFRAMEBUFFEROBJECT_P_H -#define QOPENGLFRAMEBUFFEROBJECT_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtGui/private/qtguiglobal_p.h> -#include <qopenglframebufferobject.h> -#include <private/qopenglcontext_p.h> -#include <private/qopenglextensions_p.h> - -QT_BEGIN_NAMESPACE - -class QOpenGLFramebufferObjectFormatPrivate -{ -public: - QOpenGLFramebufferObjectFormatPrivate() - : ref(1), - samples(0), - attachment(QOpenGLFramebufferObject::NoAttachment), - target(GL_TEXTURE_2D), - mipmap(false) - { -#ifndef QT_OPENGL_ES_2 - // There is nothing that says QOpenGLFramebufferObjectFormat needs a current - // context, so we need a fallback just to be safe, even though in pratice there - // will usually be a context current. - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - const bool isES = ctx ? ctx->isOpenGLES() : QOpenGLContext::openGLModuleType() != QOpenGLContext::LibGL; - internal_format = isES ? GL_RGBA : GL_RGBA8; -#else - internal_format = GL_RGBA; -#endif - } - QOpenGLFramebufferObjectFormatPrivate - (const QOpenGLFramebufferObjectFormatPrivate *other) - : ref(1), - samples(other->samples), - attachment(other->attachment), - target(other->target), - internal_format(other->internal_format), - mipmap(other->mipmap) - { - } - bool equals(const QOpenGLFramebufferObjectFormatPrivate *other) - { - return samples == other->samples && - attachment == other->attachment && - target == other->target && - internal_format == other->internal_format && - mipmap == other->mipmap; - } - - QAtomicInt ref; - int samples; - QOpenGLFramebufferObject::Attachment attachment; - GLenum target; - GLenum internal_format; - uint mipmap : 1; -}; - -class QOpenGLFramebufferObjectPrivate -{ -public: - QOpenGLFramebufferObjectPrivate() : fbo_guard(nullptr), depth_buffer_guard(nullptr) - , stencil_buffer_guard(nullptr) - , valid(false) {} - ~QOpenGLFramebufferObjectPrivate() {} - - void init(QOpenGLFramebufferObject *q, const QSize &size, - QOpenGLFramebufferObject::Attachment attachment, - GLenum texture_target, GLenum internal_format, - GLint samples = 0, bool mipmap = false); - void initTexture(int idx); - void initColorBuffer(int idx, GLint *samples); - void initDepthStencilAttachments(QOpenGLContext *ctx, QOpenGLFramebufferObject::Attachment attachment); - - bool checkFramebufferStatus(QOpenGLContext *ctx) const; - QOpenGLSharedResourceGuard *fbo_guard; - QOpenGLSharedResourceGuard *depth_buffer_guard; - QOpenGLSharedResourceGuard *stencil_buffer_guard; - GLenum target; - QSize dsSize; - QOpenGLFramebufferObjectFormat format; - int requestedSamples; - uint valid : 1; - QOpenGLFramebufferObject::Attachment fbo_attachment; - QOpenGLExtensions funcs; - - struct ColorAttachment { - ColorAttachment() : internalFormat(0), guard(nullptr) { } - ColorAttachment(const QSize &size, GLenum internalFormat) - : size(size), internalFormat(internalFormat), guard(nullptr) { } - QSize size; - GLenum internalFormat; - QOpenGLSharedResourceGuard *guard; - }; - QVector<ColorAttachment> colorAttachments; - - inline GLuint fbo() const { return fbo_guard ? fbo_guard->id() : 0; } -}; - - -QT_END_NAMESPACE - -#endif // QOPENGLFRAMEBUFFEROBJECT_P_H diff --git a/src/gui/opengl/qopenglgradientcache.cpp b/src/gui/opengl/qopenglgradientcache.cpp deleted file mode 100644 index 3aa4c0d2e6..0000000000 --- a/src/gui/opengl/qopenglgradientcache.cpp +++ /dev/null @@ -1,276 +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 "qopenglgradientcache_p.h" -#include <private/qdrawhelper_p.h> -#include <private/qopenglcontext_p.h> -#include <private/qrgba64_p.h> -#include <QtCore/qmutex.h> -#include <QtCore/qrandom.h> -#include "qopenglfunctions.h" -#include "qopenglextensions_p.h" - -#ifndef GL_RGBA16 -#define GL_RGBA16 0x805B -#endif - -QT_BEGIN_NAMESPACE - -class QOpenGL2GradientCacheWrapper -{ -public: - QOpenGL2GradientCache *cacheForContext(QOpenGLContext *context) { - QMutexLocker lock(&m_mutex); - return m_resource.value<QOpenGL2GradientCache>(context); - } - -private: - QOpenGLMultiGroupSharedResource m_resource; - QMutex m_mutex; -}; - -Q_GLOBAL_STATIC(QOpenGL2GradientCacheWrapper, qt_gradient_caches) - -QOpenGL2GradientCache::QOpenGL2GradientCache(QOpenGLContext *ctx) - : QOpenGLSharedResource(ctx->shareGroup()) -{ -} - -QOpenGL2GradientCache::~QOpenGL2GradientCache() -{ - cache.clear(); -} - -QOpenGL2GradientCache *QOpenGL2GradientCache::cacheForContext(QOpenGLContext *context) -{ - return qt_gradient_caches()->cacheForContext(context); -} - -void QOpenGL2GradientCache::invalidateResource() -{ - QMutexLocker lock(&m_mutex); - cache.clear(); -} - -void QOpenGL2GradientCache::freeResource(QOpenGLContext *) -{ - cleanCache(); -} - -void QOpenGL2GradientCache::cleanCache() -{ - QMutexLocker lock(&m_mutex); - QOpenGLGradientColorTableHash::const_iterator it = cache.constBegin(); - QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); - for (; it != cache.constEnd(); ++it) { - const CacheInfo &cache_info = it.value(); - funcs->glDeleteTextures(1, &cache_info.texId); - } - cache.clear(); -} - -GLuint QOpenGL2GradientCache::getBuffer(const QGradient &gradient, qreal opacity) -{ - quint64 hash_val = 0; - - const QGradientStops stops = gradient.stops(); - for (int i = 0; i < stops.size() && i <= 2; i++) - hash_val += stops[i].second.rgba(); - - const QMutexLocker lock(&m_mutex); - QOpenGLGradientColorTableHash::const_iterator it = cache.constFind(hash_val); - - if (it == cache.constEnd()) - return addCacheElement(hash_val, gradient, opacity); - else { - do { - const CacheInfo &cache_info = it.value(); - if (cache_info.stops == stops && cache_info.opacity == opacity - && cache_info.interpolationMode == gradient.interpolationMode()) - { - return cache_info.texId; - } - ++it; - } while (it != cache.constEnd() && it.key() == hash_val); - // an exact match for these stops and opacity was not found, create new cache - return addCacheElement(hash_val, gradient, opacity); - } -} - - -GLuint QOpenGL2GradientCache::addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity) -{ - QOpenGLFunctions *funcs = QOpenGLContext::currentContext()->functions(); - if (cache.size() == maxCacheSize()) { - int elem_to_remove = QRandomGenerator::global()->bounded(maxCacheSize()); - quint64 key = cache.keys()[elem_to_remove]; - - // need to call glDeleteTextures on each removed cache entry: - QOpenGLGradientColorTableHash::const_iterator it = cache.constFind(key); - do { - funcs->glDeleteTextures(1, &it.value().texId); - } while (++it != cache.constEnd() && it.key() == key); - cache.remove(key); // may remove more than 1, but OK - } - - CacheInfo cache_entry(gradient.stops(), opacity, gradient.interpolationMode()); - funcs->glGenTextures(1, &cache_entry.texId); - funcs->glBindTexture(GL_TEXTURE_2D, cache_entry.texId); - if (static_cast<QOpenGLExtensions *>(funcs)->hasOpenGLExtension(QOpenGLExtensions::Sized16Formats)) { - QRgba64 buffer[1024]; - generateGradientColorTable(gradient, buffer, paletteSize(), opacity); - funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16, paletteSize(), 1, - 0, GL_RGBA, GL_UNSIGNED_SHORT, buffer); - } else { - uint buffer[1024]; - generateGradientColorTable(gradient, buffer, paletteSize(), opacity); - funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, paletteSize(), 1, - 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer); - } - return cache.insert(hash_val, cache_entry).value().texId; -} - - -//TODO: Let GL generate the texture using an FBO -void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient, QRgba64 *colorTable, int size, qreal opacity) const -{ - int pos = 0; - const QGradientStops s = gradient.stops(); - - bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation); - - uint alpha = qRound(opacity * 256); - QRgba64 current_color = combineAlpha256(s[0].second.rgba64(), alpha); - qreal incr = 1.0 / qreal(size); - qreal fpos = 1.5 * incr; - colorTable[pos++] = qPremultiply(current_color); - - while (fpos <= s.first().first) { - colorTable[pos] = colorTable[pos - 1]; - pos++; - fpos += incr; - } - - if (colorInterpolation) - current_color = qPremultiply(current_color); - - const int sLast = s.size() - 1; - for (int i = 0; i < sLast; ++i) { - qreal delta = 1/(s[i+1].first - s[i].first); - QRgba64 next_color = combineAlpha256(s[i + 1].second.rgba64(), alpha); - if (colorInterpolation) - next_color = qPremultiply(next_color); - - while (fpos < s[i+1].first && pos < size) { - int dist = int(256 * ((fpos - s[i].first) * delta)); - int idist = 256 - dist; - if (colorInterpolation) - colorTable[pos] = interpolate256(current_color, idist, next_color, dist); - else - colorTable[pos] = qPremultiply(interpolate256(current_color, idist, next_color, dist)); - ++pos; - fpos += incr; - } - current_color = next_color; - } - - Q_ASSERT(s.size() > 0); - - QRgba64 last_color = qPremultiply(combineAlpha256(s[sLast].second.rgba64(), alpha)); - for (;pos < size; ++pos) - colorTable[pos] = last_color; - - // Make sure the last color stop is represented at the end of the table - colorTable[size-1] = last_color; -} - -void QOpenGL2GradientCache::generateGradientColorTable(const QGradient& gradient, uint *colorTable, int size, qreal opacity) const -{ - int pos = 0; - const QGradientStops s = gradient.stops(); - - bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation); - - uint alpha = qRound(opacity * 256); - // Qt LIES! It returns ARGB (on little-endian AND on big-endian) - uint current_color = ARGB_COMBINE_ALPHA(s[0].second.rgba(), alpha); - qreal incr = 1.0 / qreal(size); - qreal fpos = 1.5 * incr; - colorTable[pos++] = ARGB2RGBA(qPremultiply(current_color)); - - while (fpos <= s.first().first) { - colorTable[pos] = colorTable[pos - 1]; - pos++; - fpos += incr; - } - - if (colorInterpolation) - current_color = qPremultiply(current_color); - - const int sLast = s.size() - 1; - for (int i = 0; i < sLast; ++i) { - qreal delta = 1/(s[i+1].first - s[i].first); - uint next_color = ARGB_COMBINE_ALPHA(s[i + 1].second.rgba(), alpha); - if (colorInterpolation) - next_color = qPremultiply(next_color); - - while (fpos < s[i+1].first && pos < size) { - int dist = int(256 * ((fpos - s[i].first) * delta)); - int idist = 256 - dist; - if (colorInterpolation) - colorTable[pos] = ARGB2RGBA(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)); - else - colorTable[pos] = ARGB2RGBA(qPremultiply(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist))); - ++pos; - fpos += incr; - } - current_color = next_color; - } - - Q_ASSERT(s.size() > 0); - - uint last_color = ARGB2RGBA(qPremultiply(ARGB_COMBINE_ALPHA(s[sLast].second.rgba(), alpha))); - for (;pos < size; ++pos) - colorTable[pos] = last_color; - - // Make sure the last color stop is represented at the end of the table - colorTable[size-1] = last_color; -} - -QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglgradientcache_p.h b/src/gui/opengl/qopenglgradientcache_p.h deleted file mode 100644 index 1d34223bdd..0000000000 --- a/src/gui/opengl/qopenglgradientcache_p.h +++ /dev/null @@ -1,108 +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 QOPENGLGRADIENTCACHE_P_H -#define QOPENGLGRADIENTCACHE_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtGui/private/qtguiglobal_p.h> -#include <QMultiHash> -#include <QObject> -#include <private/qopenglcontext_p.h> -#include <QtCore/qmutex.h> -#include <QGradient> -#include <qrgba64.h> - -QT_BEGIN_NAMESPACE - -class QOpenGL2GradientCache : public QOpenGLSharedResource -{ - struct CacheInfo - { - inline CacheInfo(QGradientStops s, qreal op, QGradient::InterpolationMode mode) : - stops(std::move(s)), opacity(op), interpolationMode(mode) {} - - GLuint texId; - QGradientStops stops; - qreal opacity; - QGradient::InterpolationMode interpolationMode; - }; - - typedef QMultiHash<quint64, CacheInfo> QOpenGLGradientColorTableHash; - -public: - static QOpenGL2GradientCache *cacheForContext(QOpenGLContext *context); - - QOpenGL2GradientCache(QOpenGLContext *); - ~QOpenGL2GradientCache(); - - GLuint getBuffer(const QGradient &gradient, qreal opacity); - inline int paletteSize() const { return 1024; } - - void invalidateResource() override; - void freeResource(QOpenGLContext *ctx) override; - -private: - inline int maxCacheSize() const { return 60; } - inline void generateGradientColorTable(const QGradient& gradient, - QRgba64 *colorTable, - int size, qreal opacity) const; - inline void generateGradientColorTable(const QGradient& gradient, - uint *colorTable, - int size, qreal opacity) const; - GLuint addCacheElement(quint64 hash_val, const QGradient &gradient, qreal opacity); - void cleanCache(); - - QOpenGLGradientColorTableHash cache; - QMutex m_mutex; -}; - -QT_END_NAMESPACE - -#endif // QOPENGLGRADIENTCACHE_P_H diff --git a/src/gui/opengl/qopenglpaintdevice.cpp b/src/gui/opengl/qopenglpaintdevice.cpp deleted file mode 100644 index 3920a10467..0000000000 --- a/src/gui/opengl/qopenglpaintdevice.cpp +++ /dev/null @@ -1,372 +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 <qopenglpaintdevice.h> -#include <qpaintengine.h> -#include <qthreadstorage.h> - -#include <private/qopenglpaintdevice_p.h> -#include <private/qobject_p.h> -#include <private/qopenglcontext_p.h> -#include <private/qopenglframebufferobject_p.h> -#include <private/qopenglpaintengine_p.h> - -// for qt_defaultDpiX/Y -#include <private/qfont_p.h> - -#include <qopenglfunctions.h> - -QT_BEGIN_NAMESPACE - -/*! - \class QOpenGLPaintDevice - \brief The QOpenGLPaintDevice class enables painting to an OpenGL context using QPainter. - \since 5.0 - \inmodule QtGui - - \ingroup painting-3D - - The QOpenGLPaintDevice uses the \b current QOpenGL context to render - QPainter draw commands. The context is captured upon construction. It - requires support for OpenGL (ES) 2.0 or higher. - - \section1 Performance - - The QOpenGLPaintDevice is almost always hardware accelerated and - has the potential of being much faster than software - rasterization. However, it is more sensitive to state changes, and - therefore requires the drawing commands to be carefully ordered to - achieve optimal performance. - - \section1 Antialiasing and Quality - - Antialiasing in the OpenGL paint engine is done using - multisampling. Most hardware require significantly more memory to - do multisampling and the resulting quality is not on par with the - quality of the software paint engine. The OpenGL paint engine's - strength lies in its performance, not its visual rendering - quality. - - \section1 State Changes - - When painting to a QOpenGLPaintDevice using QPainter, the state of - the current OpenGL context will be altered by the paint engine to - reflect its needs. Applications should not rely upon the OpenGL - state being reset to its original conditions, particularly the - current shader program, OpenGL viewport, texture units, and - drawing modes. - - \section1 Mixing QPainter and OpenGL - - When intermixing QPainter and OpenGL, it is important to notify - QPainter that the OpenGL state may have been cluttered so it can - restore its internal state. This is achieved by calling \l - QPainter::beginNativePainting() before starting the OpenGL - rendering and calling \l QPainter::endNativePainting() after - finishing. - - \sa {OpenGL Window Example} - -*/ - -/*! - Constructs a QOpenGLPaintDevice. - - The QOpenGLPaintDevice is only valid for the current context. - - \sa QOpenGLContext::currentContext() -*/ -QOpenGLPaintDevice::QOpenGLPaintDevice() - : d_ptr(new QOpenGLPaintDevicePrivate(QSize())) -{ -} - -/*! - Constructs a QOpenGLPaintDevice with the given \a size. - - The QOpenGLPaintDevice is only valid for the current context. - - \sa QOpenGLContext::currentContext() -*/ -QOpenGLPaintDevice::QOpenGLPaintDevice(const QSize &size) - : d_ptr(new QOpenGLPaintDevicePrivate(size)) -{ -} - -/*! - Constructs a QOpenGLPaintDevice with the given \a width and \a height. - - The QOpenGLPaintDevice is only valid for the current context. - - \sa QOpenGLContext::currentContext() -*/ -QOpenGLPaintDevice::QOpenGLPaintDevice(int width, int height) - : QOpenGLPaintDevice(QSize(width, height)) -{ -} - -/*! - \internal - */ -QOpenGLPaintDevice::QOpenGLPaintDevice(QOpenGLPaintDevicePrivate &dd) - : d_ptr(&dd) -{ -} - -/*! - Destroys the QOpenGLPaintDevice. -*/ - -QOpenGLPaintDevice::~QOpenGLPaintDevice() -{ - delete d_ptr->engine; -} - -/*! - \fn int QOpenGLPaintDevice::devType() const - \internal - \reimp -*/ - -QOpenGLPaintDevicePrivate::QOpenGLPaintDevicePrivate(const QSize &sz) - : size(sz) - , ctx(QOpenGLContext::currentContext()) - , dpmx(qt_defaultDpiX() * 100. / 2.54) - , dpmy(qt_defaultDpiY() * 100. / 2.54) - , devicePixelRatio(1.0) - , flipped(false) - , engine(nullptr) -{ -} - -QOpenGLPaintDevicePrivate::~QOpenGLPaintDevicePrivate() -{ -} - -class QOpenGLEngineThreadStorage -{ -public: - QPaintEngine *engine() { - QPaintEngine *&localEngine = storage.localData(); - if (!localEngine) - localEngine = new QOpenGL2PaintEngineEx; - return localEngine; - } - -private: - QThreadStorage<QPaintEngine *> storage; -}; - -Q_GLOBAL_STATIC(QOpenGLEngineThreadStorage, qt_opengl_engine) - -/*! - \reimp -*/ - -QPaintEngine *QOpenGLPaintDevice::paintEngine() const -{ - if (d_ptr->engine) - return d_ptr->engine; - - QPaintEngine *engine = qt_opengl_engine()->engine(); - if (engine->isActive() && engine->paintDevice() != this) { - d_ptr->engine = new QOpenGL2PaintEngineEx; - return d_ptr->engine; - } - - return engine; -} - -/*! - Returns the OpenGL context associated with the paint device. -*/ - -QOpenGLContext *QOpenGLPaintDevice::context() const -{ - return d_ptr->ctx; -} - -/*! - Returns the pixel size of the paint device. - - \sa setSize() -*/ - -QSize QOpenGLPaintDevice::size() const -{ - return d_ptr->size; -} - -/*! - Sets the pixel size of the paint device to \a size. - - \sa size() -*/ - -void QOpenGLPaintDevice::setSize(const QSize &size) -{ - d_ptr->size = size; -} - -/*! - Sets the device pixel ratio for the paint device to \a devicePixelRatio. -*/ -void QOpenGLPaintDevice::setDevicePixelRatio(qreal devicePixelRatio) -{ - d_ptr->devicePixelRatio = devicePixelRatio; -} - -/*! - \reimp -*/ - -int QOpenGLPaintDevice::metric(QPaintDevice::PaintDeviceMetric metric) const -{ - switch (metric) { - case PdmWidth: - return d_ptr->size.width(); - case PdmHeight: - return d_ptr->size.height(); - case PdmDepth: - return 32; - case PdmWidthMM: - return qRound(d_ptr->size.width() * 1000 / d_ptr->dpmx); - case PdmHeightMM: - return qRound(d_ptr->size.height() * 1000 / d_ptr->dpmy); - case PdmNumColors: - return 0; - case PdmDpiX: - return qRound(d_ptr->dpmx * 0.0254); - case PdmDpiY: - return qRound(d_ptr->dpmy * 0.0254); - case PdmPhysicalDpiX: - return qRound(d_ptr->dpmx * 0.0254); - case PdmPhysicalDpiY: - return qRound(d_ptr->dpmy * 0.0254); - case PdmDevicePixelRatio: - return d_ptr->devicePixelRatio; - case PdmDevicePixelRatioScaled: - return d_ptr->devicePixelRatio * QPaintDevice::devicePixelRatioFScale(); - - default: - qWarning("QOpenGLPaintDevice::metric() - metric %d not known", metric); - return 0; - } -} - -/*! - Returns the number of pixels per meter horizontally. - - \sa setDotsPerMeterX() -*/ - -qreal QOpenGLPaintDevice::dotsPerMeterX() const -{ - return d_ptr->dpmx; -} - -/*! - Returns the number of pixels per meter vertically. - - \sa setDotsPerMeterY() -*/ - -qreal QOpenGLPaintDevice::dotsPerMeterY() const -{ - return d_ptr->dpmy; -} - -/*! - Sets the number of pixels per meter horizontally to \a dpmx. - - \sa dotsPerMeterX() -*/ - -void QOpenGLPaintDevice::setDotsPerMeterX(qreal dpmx) -{ - d_ptr->dpmx = dpmx; -} - -/*! - Sets the number of pixels per meter vertically to \a dpmy. - - \sa dotsPerMeterY() -*/ - -void QOpenGLPaintDevice::setDotsPerMeterY(qreal dpmy) -{ - d_ptr->dpmx = dpmy; -} - -/*! - Sets whether painting should be flipped around the Y-axis or not to \a flipped. - - \sa paintFlipped() -*/ -void QOpenGLPaintDevice::setPaintFlipped(bool flipped) -{ - d_ptr->flipped = flipped; -} - -/*! - Returns \c true if painting is flipped around the Y-axis. - - \sa setPaintFlipped() -*/ - -bool QOpenGLPaintDevice::paintFlipped() const -{ - return d_ptr->flipped; -} - -/*! - This virtual method is provided as a callback to allow re-binding a target - frame buffer object or context when different QOpenGLPaintDevice instances - are issuing draw calls alternately. - - \l{QPainter::beginNativePainting()}{beginNativePainting()} will also trigger - this method. - - The default implementation does nothing. -*/ -void QOpenGLPaintDevice::ensureActiveTarget() -{ -} - -QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglpaintdevice_p.h b/src/gui/opengl/qopenglpaintdevice_p.h deleted file mode 100644 index 3683ebebac..0000000000 --- a/src/gui/opengl/qopenglpaintdevice_p.h +++ /dev/null @@ -1,88 +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 QOPENGL_PAINTDEVICE_P_H -#define QOPENGL_PAINTDEVICE_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of the Qt OpenGL classes. This header file may change from -// version to version without notice, or even be removed. -// -// We mean it. -// - -#include <QtGui/private/qtguiglobal_p.h> -#include <qopenglpaintdevice.h> - -QT_BEGIN_NAMESPACE - -class QOpenGLContext; -class QPaintEngine; - -class Q_GUI_EXPORT QOpenGLPaintDevicePrivate -{ -public: - QOpenGLPaintDevicePrivate(const QSize &size); - virtual ~QOpenGLPaintDevicePrivate(); - - static QOpenGLPaintDevicePrivate *get(QOpenGLPaintDevice *dev) { return dev->d_func(); } - - virtual void beginPaint() { } - virtual void endPaint() { } - -public: - QSize size; - QOpenGLContext *ctx; - - qreal dpmx; - qreal dpmy; - qreal devicePixelRatio; - - bool flipped; - - QPaintEngine *engine; -}; - -QT_END_NAMESPACE - -#endif // QOPENGL_PAINTDEVICE_P_H diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp deleted file mode 100644 index b53c9a3eab..0000000000 --- a/src/gui/opengl/qopenglpaintengine.cpp +++ /dev/null @@ -1,2702 +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$ -** -****************************************************************************/ - -/* - When the active program changes, we need to update it's uniforms. - We could track state for each program and only update stale uniforms - - Could lead to lots of overhead if there's a lot of programs - We could update all the uniforms when the program changes - - Could end up updating lots of uniforms which don't need updating - - Updating uniforms should be cheap, so the overhead of updating up-to-date - uniforms should be minimal. It's also less complex. - - Things which _may_ cause a different program to be used: - - Change in brush/pen style - - Change in painter opacity - - Change in composition mode - - Whenever we set a mode on the shader manager - it needs to tell us if it had - to switch to a different program. - - The shader manager should only switch when we tell it to. E.g. if we set a new - brush style and then switch to transparent painter, we only want it to compile - and use the correct program when we really need it. -*/ - -// #define QT_OPENGL_CACHE_AS_VBOS - -#include "qopenglgradientcache_p.h" -#include "qopengltexturecache_p.h" -#include "qopenglpaintengine_p.h" -#include "qopenglpaintdevice_p.h" - -#include <string.h> //for memcpy -#include <qmath.h> - -#include <private/qopengl_p.h> -#include <private/qopenglcontext_p.h> -#include <private/qopenglextensions_p.h> -#include <private/qpaintengineex_p.h> -#include <QPaintEngine> -#include <private/qpainter_p.h> -#include <private/qfontengine_p.h> -#include <private/qdatabuffer_p.h> -#include <private/qstatictext_p.h> -#include <private/qtriangulator_p.h> - -#include "qopenglengineshadermanager_p.h" -#include "qopengl2pexvertexarray_p.h" -#include "qopengltextureglyphcache_p.h" - -#include <QDebug> - -#ifndef GL_KHR_blend_equation_advanced -#define GL_KHR_blend_equation_advanced 1 -#define GL_MULTIPLY_KHR 0x9294 -#define GL_SCREEN_KHR 0x9295 -#define GL_OVERLAY_KHR 0x9296 -#define GL_DARKEN_KHR 0x9297 -#define GL_LIGHTEN_KHR 0x9298 -#define GL_COLORDODGE_KHR 0x9299 -#define GL_COLORBURN_KHR 0x929A -#define GL_HARDLIGHT_KHR 0x929B -#define GL_SOFTLIGHT_KHR 0x929C -#define GL_DIFFERENCE_KHR 0x929E -#define GL_EXCLUSION_KHR 0x92A0 -#endif /* GL_KHR_blend_equation_advanced */ - -#ifndef GL_KHR_blend_equation_advanced_coherent -#define GL_KHR_blend_equation_advanced_coherent 1 -#define GL_BLEND_ADVANCED_COHERENT_KHR 0x9285 -#endif /* GL_KHR_blend_equation_advanced_coherent */ - -QT_BEGIN_NAMESPACE - - -Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert); - -////////////////////////////////// Private Methods ////////////////////////////////////////// - -QOpenGL2PaintEngineExPrivate::~QOpenGL2PaintEngineExPrivate() -{ - delete shaderManager; - - vertexBuffer.destroy(); - texCoordBuffer.destroy(); - opacityBuffer.destroy(); - indexBuffer.destroy(); - vao.destroy(); - - if (elementIndicesVBOId != 0) { - funcs.glDeleteBuffers(1, &elementIndicesVBOId); - elementIndicesVBOId = 0; - } -} - -inline QColor qt_premultiplyColor(QColor c, GLfloat opacity) -{ - qreal alpha = c.alphaF() * opacity; - c.setAlphaF(alpha); - c.setRedF(c.redF() * alpha); - c.setGreenF(c.greenF() * alpha); - c.setBlueF(c.blueF() * alpha); - return c; -} - - -void QOpenGL2PaintEngineExPrivate::setBrush(const QBrush& brush) -{ - if (qbrush_fast_equals(currentBrush, brush)) - return; - - const Qt::BrushStyle newStyle = qbrush_style(brush); - Q_ASSERT(newStyle != Qt::NoBrush); - - currentBrush = brush; - if (!currentBrushImage.isNull()) - currentBrushImage = QImage(); - brushUniformsDirty = true; // All brushes have at least one uniform - - if (newStyle > Qt::SolidPattern) - brushTextureDirty = true; - - if (currentBrush.style() == Qt::TexturePattern - && qHasPixmapTexture(brush) && brush.texture().isQBitmap()) - { - shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::TextureSrcWithPattern); - } else { - shaderManager->setSrcPixelType(newStyle); - } - shaderManager->optimiseForBrushTransform(currentBrush.transform().type()); -} - - -void QOpenGL2PaintEngineExPrivate::useSimpleShader() -{ - shaderManager->useSimpleProgram(); - - if (matrixDirty) - updateMatrix(); -} - -/* - Single entry-point for activating, binding, and setting properties. - - Allows keeping track of (caching) the latest texture unit and bound - texture in a central place, so that we can skip re-binding unless - needed. - - \note Any code or Qt API that internally activates or binds will - not affect the cache used by this function, which means they will - lead to inconsisent state. QPainter::beginNativePainting() takes - care of resetting the cache, so for user–code this is fine, but - internally in the paint engine care must be taken to not call - functions that may activate or bind under our feet. -*/ -template<typename T> -void QOpenGL2PaintEngineExPrivate::updateTexture(GLenum textureUnit, const T &texture, GLenum wrapMode, GLenum filterMode, TextureUpdateMode updateMode) -{ - static const GLenum target = GL_TEXTURE_2D; - - activateTextureUnit(textureUnit); - - GLuint textureId = bindTexture(texture); - - if (updateMode == UpdateIfNeeded && textureId == lastTextureUsed) - return; - - lastTextureUsed = textureId; - - funcs.glTexParameteri(target, GL_TEXTURE_WRAP_S, wrapMode); - funcs.glTexParameteri(target, GL_TEXTURE_WRAP_T, wrapMode); - - funcs.glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filterMode); - funcs.glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filterMode); -} - -void QOpenGL2PaintEngineExPrivate::activateTextureUnit(GLenum textureUnit) -{ - if (textureUnit != lastTextureUnitUsed) { - funcs.glActiveTexture(GL_TEXTURE0 + textureUnit); - lastTextureUnitUsed = textureUnit; - - // We simplify things by keeping a single cached value of the last - // texture that was bound, instead of one per texture unit. This - // means that switching texture units could potentially mean we - // need a re-bind and corresponding parameter updates. - lastTextureUsed = GLuint(-1); - } -} - -template<> -GLuint QOpenGL2PaintEngineExPrivate::bindTexture(const GLuint &textureId) -{ - if (textureId != lastTextureUsed) - funcs.glBindTexture(GL_TEXTURE_2D, textureId); - - return textureId; -} - -template<> -GLuint QOpenGL2PaintEngineExPrivate::bindTexture(const QImage &image) -{ - return QOpenGLTextureCache::cacheForContext(ctx)->bindTexture(ctx, image); -} - -template<> -GLuint QOpenGL2PaintEngineExPrivate::bindTexture(const QPixmap &pixmap) -{ - return QOpenGLTextureCache::cacheForContext(ctx)->bindTexture(ctx, pixmap); -} - -template<> -GLuint QOpenGL2PaintEngineExPrivate::bindTexture(const QGradient &gradient) -{ - // We apply global opacity in the fragment shaders, so we always pass 1.0 - // for opacity to the cache. - GLuint textureId = QOpenGL2GradientCache::cacheForContext(ctx)->getBuffer(gradient, 1.0); - - // QOpenGL2GradientCache::getBuffer() may bind and generate a new texture if it - // hasn't been cached yet, but will otherwise return an unbound texture id. To - // be sure that the texture is bound, we unfortunately have to bind again, - // which results in the initial generation of the texture doing two binds. - return bindTexture(textureId); -} - -struct ImageWithBindOptions -{ - const QImage ℑ - QOpenGLTextureUploader::BindOptions options; -}; - -template<> -GLuint QOpenGL2PaintEngineExPrivate::bindTexture(const ImageWithBindOptions &imageWithOptions) -{ - return QOpenGLTextureCache::cacheForContext(ctx)->bindTexture(ctx, imageWithOptions.image, imageWithOptions.options); -} - -inline static bool isPowerOfTwo(int x) -{ - // Assumption: x >= 1 - return x == (x & -x); -} - -void QOpenGL2PaintEngineExPrivate::updateBrushTexture() -{ - Q_Q(QOpenGL2PaintEngineEx); -// qDebug("QOpenGL2PaintEngineExPrivate::updateBrushTexture()"); - Qt::BrushStyle style = currentBrush.style(); - - bool smoothPixmapTransform = q->state()->renderHints & QPainter::SmoothPixmapTransform; - GLenum filterMode = smoothPixmapTransform ? GL_LINEAR : GL_NEAREST; - - if ( (style >= Qt::Dense1Pattern) && (style <= Qt::DiagCrossPattern) ) { - // Get the image data for the pattern - QImage textureImage = qt_imageForBrush(style, false); - - updateTexture(QT_BRUSH_TEXTURE_UNIT, textureImage, GL_REPEAT, filterMode, ForceUpdate); - } - else if (style >= Qt::LinearGradientPattern && style <= Qt::ConicalGradientPattern) { - // Gradiant brush: All the gradiants use the same texture - - const QGradient *gradient = currentBrush.gradient(); - - GLenum wrapMode = GL_CLAMP_TO_EDGE; - if (gradient->spread() == QGradient::RepeatSpread || gradient->type() == QGradient::ConicalGradient) - wrapMode = GL_REPEAT; - else if (gradient->spread() == QGradient::ReflectSpread) - wrapMode = GL_MIRRORED_REPEAT; - - updateTexture(QT_BRUSH_TEXTURE_UNIT, *gradient, wrapMode, filterMode, ForceUpdate); - } - else if (style == Qt::TexturePattern) { - currentBrushImage = currentBrush.textureImage(); - - int max_texture_size = ctx->d_func()->maxTextureSize(); - QSize newSize = currentBrushImage.size(); - newSize = newSize.boundedTo(QSize(max_texture_size, max_texture_size)); - if (!QOpenGLContext::currentContext()->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextureRepeat)) { - if (!isPowerOfTwo(newSize.width()) || !isPowerOfTwo(newSize.height())) { - newSize.setHeight(qNextPowerOfTwo(newSize.height() - 1)); - newSize.setWidth(qNextPowerOfTwo(newSize.width() - 1)); - } - } - if (currentBrushImage.size() != newSize) - currentBrushImage = currentBrushImage.scaled(newSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); - - GLuint wrapMode = GL_REPEAT; - - updateTexture(QT_BRUSH_TEXTURE_UNIT, currentBrushImage, wrapMode, filterMode, ForceUpdate); - } - brushTextureDirty = false; -} - - -void QOpenGL2PaintEngineExPrivate::updateBrushUniforms() -{ -// qDebug("QOpenGL2PaintEngineExPrivate::updateBrushUniforms()"); - Qt::BrushStyle style = currentBrush.style(); - - if (style == Qt::NoBrush) - return; - - QTransform brushQTransform = currentBrush.transform(); - - if (style == Qt::SolidPattern) { - QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity); - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::FragmentColor), col); - } - else { - // All other brushes have a transform and thus need the translation point: - QPointF translationPoint; - - if (style <= Qt::DiagCrossPattern) { - QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity); - - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::PatternColor), col); - - QVector2D halfViewportSize(width*0.5, height*0.5); - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::HalfViewportSize), halfViewportSize); - } - else if (style == Qt::LinearGradientPattern) { - const QLinearGradient *g = static_cast<const QLinearGradient *>(currentBrush.gradient()); - - QPointF realStart = g->start(); - QPointF realFinal = g->finalStop(); - translationPoint = realStart; - - QPointF l = realFinal - realStart; - - QVector3D linearData( - l.x(), - l.y(), - 1.0f / (l.x() * l.x() + l.y() * l.y()) - ); - - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::LinearData), linearData); - - QVector2D halfViewportSize(width*0.5, height*0.5); - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::HalfViewportSize), halfViewportSize); - } - else if (style == Qt::ConicalGradientPattern) { - const QConicalGradient *g = static_cast<const QConicalGradient *>(currentBrush.gradient()); - translationPoint = g->center(); - - GLfloat angle = -qDegreesToRadians(g->angle()); - - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::Angle), angle); - - QVector2D halfViewportSize(width*0.5, height*0.5); - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::HalfViewportSize), halfViewportSize); - } - else if (style == Qt::RadialGradientPattern) { - const QRadialGradient *g = static_cast<const QRadialGradient *>(currentBrush.gradient()); - QPointF realCenter = g->center(); - QPointF realFocal = g->focalPoint(); - qreal realRadius = g->centerRadius() - g->focalRadius(); - translationPoint = realFocal; - - QPointF fmp = realCenter - realFocal; - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::Fmp), fmp); - - GLfloat fmp2_m_radius2 = -fmp.x() * fmp.x() - fmp.y() * fmp.y() + realRadius*realRadius; - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::Fmp2MRadius2), fmp2_m_radius2); - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::Inverse2Fmp2MRadius2), - GLfloat(1.0 / (2.0*fmp2_m_radius2))); - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::SqrFr), - GLfloat(g->focalRadius() * g->focalRadius())); - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::BRadius), - GLfloat(2 * (g->centerRadius() - g->focalRadius()) * g->focalRadius()), - g->focalRadius(), - g->centerRadius() - g->focalRadius()); - - QVector2D halfViewportSize(width*0.5, height*0.5); - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::HalfViewportSize), halfViewportSize); - } - else if (style == Qt::TexturePattern) { - const QPixmap& texPixmap = currentBrush.texture(); - - if (qHasPixmapTexture(currentBrush) && currentBrush.texture().isQBitmap()) { - QColor col = qt_premultiplyColor(currentBrush.color(), (GLfloat)q->state()->opacity); - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::PatternColor), col); - } - - QSizeF invertedTextureSize(1.0 / texPixmap.width(), 1.0 / texPixmap.height()); - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::InvertedTextureSize), invertedTextureSize); - - QVector2D halfViewportSize(width*0.5, height*0.5); - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::HalfViewportSize), halfViewportSize); - } - else - qWarning("QOpenGL2PaintEngineEx: Unimplemented fill style"); - - const QPointF &brushOrigin = q->state()->brushOrigin; - QTransform matrix = q->state()->matrix; - matrix.translate(brushOrigin.x(), brushOrigin.y()); - - QTransform translate(1, 0, 0, 1, -translationPoint.x(), -translationPoint.y()); - qreal m22 = -1; - qreal dy = height; - if (device->paintFlipped()) { - m22 = 1; - dy = 0; - } - QTransform gl_to_qt(1, 0, 0, m22, 0, dy); - QTransform inv_matrix = gl_to_qt * (brushQTransform * matrix).inverted() * translate; - - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::BrushTransform), inv_matrix); - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::BrushTexture), QT_BRUSH_TEXTURE_UNIT); - } - brushUniformsDirty = false; -} - - -// This assumes the shader manager has already setup the correct shader program -void QOpenGL2PaintEngineExPrivate::updateMatrix() -{ -// qDebug("QOpenGL2PaintEngineExPrivate::updateMatrix()"); - - const QTransform& transform = q->state()->matrix; - - // The projection matrix converts from Qt's coordinate system to GL's coordinate system - // * GL's viewport is 2x2, Qt's is width x height - // * GL has +y -> -y going from bottom -> top, Qt is the other way round - // * GL has [0,0] in the center, Qt has it in the top-left - // - // This results in the Projection matrix below, which is multiplied by the painter's - // transformation matrix, as shown below: - // - // Projection Matrix Painter Transform - // ------------------------------------------------ ------------------------ - // | 2.0 / width | 0.0 | -1.0 | | m11 | m21 | dx | - // | 0.0 | -2.0 / height | 1.0 | * | m12 | m22 | dy | - // | 0.0 | 0.0 | 1.0 | | m13 | m23 | m33 | - // ------------------------------------------------ ------------------------ - // - // NOTE: The resultant matrix is also transposed, as GL expects column-major matracies - - const GLfloat wfactor = 2.0f / width; - GLfloat hfactor = -2.0f / height; - - GLfloat dx = transform.dx(); - GLfloat dy = transform.dy(); - - if (device->paintFlipped()) { - hfactor *= -1; - dy -= height; - } - - // Non-integer translates can have strange effects for some rendering operations such as - // anti-aliased text rendering. In such cases, we snap the translate to the pixel grid. - if (snapToPixelGrid && transform.type() == QTransform::TxTranslate) { - // 0.50 needs to rounded down to 0.0 for consistency with raster engine: - dx = std::ceil(dx - 0.5f); - dy = std::ceil(dy - 0.5f); - } - pmvMatrix[0][0] = (wfactor * transform.m11()) - transform.m13(); - pmvMatrix[1][0] = (wfactor * transform.m21()) - transform.m23(); - pmvMatrix[2][0] = (wfactor * dx) - transform.m33(); - pmvMatrix[0][1] = (hfactor * transform.m12()) + transform.m13(); - pmvMatrix[1][1] = (hfactor * transform.m22()) + transform.m23(); - pmvMatrix[2][1] = (hfactor * dy) + transform.m33(); - pmvMatrix[0][2] = transform.m13(); - pmvMatrix[1][2] = transform.m23(); - pmvMatrix[2][2] = transform.m33(); - - // 1/10000 == 0.0001, so we have good enough res to cover curves - // that span the entire widget... - inverseScale = qMax(1 / qMax( qMax(qAbs(transform.m11()), qAbs(transform.m22())), - qMax(qAbs(transform.m12()), qAbs(transform.m21())) ), - qreal(0.0001)); - - matrixDirty = false; - matrixUniformDirty = true; - - // Set the PMV matrix attribute. As we use an attributes rather than uniforms, we only - // need to do this once for every matrix change and persists across all shader programs. - funcs.glVertexAttrib3fv(QT_PMV_MATRIX_1_ATTR, pmvMatrix[0]); - funcs.glVertexAttrib3fv(QT_PMV_MATRIX_2_ATTR, pmvMatrix[1]); - funcs.glVertexAttrib3fv(QT_PMV_MATRIX_3_ATTR, pmvMatrix[2]); - - dasher.setInvScale(inverseScale); - stroker.setInvScale(inverseScale); -} - - -void QOpenGL2PaintEngineExPrivate::updateCompositionMode() -{ - // NOTE: The entire paint engine works on pre-multiplied data - which is why some of these - // composition modes look odd. -// qDebug() << "QOpenGL2PaintEngineExPrivate::updateCompositionMode() - Setting GL composition mode for " << q->state()->composition_mode; - if (ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::BlendEquationAdvanced)) { - if (q->state()->composition_mode <= QPainter::CompositionMode_Plus) { - funcs.glDisable(GL_BLEND_ADVANCED_COHERENT_KHR); - funcs.glBlendEquation(GL_FUNC_ADD); - } else { - funcs.glEnable(GL_BLEND_ADVANCED_COHERENT_KHR); - } - shaderManager->setCompositionMode(q->state()->composition_mode); - } else { - if (q->state()->composition_mode > QPainter::CompositionMode_Plus) { - qWarning("Unsupported composition mode"); - compositionModeDirty = false; - return; - } - } - switch(q->state()->composition_mode) { - case QPainter::CompositionMode_SourceOver: - funcs.glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - break; - case QPainter::CompositionMode_DestinationOver: - funcs.glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE); - break; - case QPainter::CompositionMode_Clear: - funcs.glBlendFunc(GL_ZERO, GL_ZERO); - break; - case QPainter::CompositionMode_Source: - funcs.glBlendFunc(GL_ONE, GL_ZERO); - break; - case QPainter::CompositionMode_Destination: - funcs.glBlendFunc(GL_ZERO, GL_ONE); - break; - case QPainter::CompositionMode_SourceIn: - funcs.glBlendFunc(GL_DST_ALPHA, GL_ZERO); - break; - case QPainter::CompositionMode_DestinationIn: - funcs.glBlendFunc(GL_ZERO, GL_SRC_ALPHA); - break; - case QPainter::CompositionMode_SourceOut: - funcs.glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ZERO); - break; - case QPainter::CompositionMode_DestinationOut: - funcs.glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_ALPHA); - break; - case QPainter::CompositionMode_SourceAtop: - funcs.glBlendFunc(GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - break; - case QPainter::CompositionMode_DestinationAtop: - funcs.glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA); - break; - case QPainter::CompositionMode_Xor: - funcs.glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - break; - case QPainter::CompositionMode_Plus: - funcs.glBlendFunc(GL_ONE, GL_ONE); - break; - case QPainter::CompositionMode_Multiply: - funcs.glBlendEquation(GL_MULTIPLY_KHR); - break; - case QPainter::CompositionMode_Screen: - funcs.glBlendEquation(GL_SCREEN_KHR); - break; - case QPainter::CompositionMode_Overlay: - funcs.glBlendEquation(GL_OVERLAY_KHR); - break; - case QPainter::CompositionMode_Darken: - funcs.glBlendEquation(GL_DARKEN_KHR); - break; - case QPainter::CompositionMode_Lighten: - funcs.glBlendEquation(GL_LIGHTEN_KHR); - break; - case QPainter::CompositionMode_ColorDodge: - funcs.glBlendEquation(GL_COLORDODGE_KHR); - break; - case QPainter::CompositionMode_ColorBurn: - funcs.glBlendEquation(GL_COLORBURN_KHR); - break; - case QPainter::CompositionMode_HardLight: - funcs.glBlendEquation(GL_HARDLIGHT_KHR); - break; - case QPainter::CompositionMode_SoftLight: - funcs.glBlendEquation(GL_SOFTLIGHT_KHR); - break; - case QPainter::CompositionMode_Difference: - funcs.glBlendEquation(GL_DIFFERENCE_KHR); - break; - case QPainter::CompositionMode_Exclusion: - funcs.glBlendEquation(GL_EXCLUSION_KHR); - break; - default: - qWarning("Unsupported composition mode"); - break; - } - - compositionModeDirty = false; -} - -static inline void setCoords(GLfloat *coords, const QOpenGLRect &rect) -{ - coords[0] = rect.left; - coords[1] = rect.top; - coords[2] = rect.right; - coords[3] = rect.top; - coords[4] = rect.right; - coords[5] = rect.bottom; - coords[6] = rect.left; - coords[7] = rect.bottom; -} - -void QOpenGL2PaintEngineExPrivate::drawTexture(const QOpenGLRect& dest, const QOpenGLRect& src, const QSize &textureSize, bool opaque, bool pattern) -{ - // Setup for texture drawing - currentBrush = noBrush; - - if (snapToPixelGrid) { - snapToPixelGrid = false; - matrixDirty = true; - } - - if (prepareForDraw(opaque)) - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT); - - if (pattern) { - QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity); - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::PatternColor), col); - } - - GLfloat dx = 1.0 / textureSize.width(); - GLfloat dy = 1.0 / textureSize.height(); - - QOpenGLRect srcTextureRect(src.left*dx, src.top*dy, src.right*dx, src.bottom*dy); - - setCoords(staticVertexCoordinateArray, dest); - setCoords(staticTextureCoordinateArray, srcTextureRect); - - setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, true); - setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, true); - - uploadData(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray, 8); - uploadData(QT_TEXTURE_COORDS_ATTR, staticTextureCoordinateArray, 8); - - funcs.glDrawArrays(GL_TRIANGLE_FAN, 0, 4); -} - -void QOpenGL2PaintEngineEx::beginNativePainting() -{ - Q_D(QOpenGL2PaintEngineEx); - ensureActive(); - d->transferMode(BrushDrawingMode); - - d->nativePaintingActive = true; - - d->funcs.glUseProgram(0); - - // Disable all the vertex attribute arrays: - for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i) - d->funcs.glDisableVertexAttribArray(i); - -#if !defined(QT_OPENGL_ES_2) && !defined(QT_OPENGL_DYNAMIC) - Q_ASSERT(QOpenGLContext::currentContext()); - const QOpenGLContext *ctx = d->ctx; - const QSurfaceFormat &fmt = d->device->context()->format(); - if (fmt.majorVersion() < 3 || (fmt.majorVersion() == 3 && fmt.minorVersion() < 1) - || (fmt.majorVersion() == 3 && fmt.minorVersion() == 1 && ctx->hasExtension(QByteArrayLiteral("GL_ARB_compatibility"))) - || fmt.profile() == QSurfaceFormat::CompatibilityProfile) - { - // be nice to people who mix OpenGL 1.x code with QPainter commands - // by setting modelview and projection matrices to mirror the GL 1 - // paint engine - const QTransform& mtx = state()->matrix; - - float mv_matrix[4][4] = - { - { float(mtx.m11()), float(mtx.m12()), 0, float(mtx.m13()) }, - { float(mtx.m21()), float(mtx.m22()), 0, float(mtx.m23()) }, - { 0, 0, 1, 0 }, - { float(mtx.dx()), float(mtx.dy()), 0, float(mtx.m33()) } - }; - - const QSize sz = d->device->size(); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, sz.width(), sz.height(), 0, -999999, 999999); - - glMatrixMode(GL_MODELVIEW); - glLoadMatrixf(&mv_matrix[0][0]); - } -#endif // QT_OPENGL_ES_2 - - d->resetGLState(); - - // We don't know what texture units and textures the native painting - // will activate and bind, so we can't assume anything when we return - // from the native painting. - d->lastTextureUnitUsed = QT_UNKNOWN_TEXTURE_UNIT; - d->lastTextureUsed = GLuint(-1); - - d->dirtyStencilRegion = QRect(0, 0, d->width, d->height); - - d->shaderManager->setDirty(); - - d->needsSync = true; -} - -void QOpenGL2PaintEngineExPrivate::resetGLState() -{ - activateTextureUnit(QT_DEFAULT_TEXTURE_UNIT); - - funcs.glDisable(GL_BLEND); - funcs.glDisable(GL_STENCIL_TEST); - funcs.glDisable(GL_DEPTH_TEST); - funcs.glDisable(GL_SCISSOR_TEST); - funcs.glDepthMask(true); - funcs.glDepthFunc(GL_LESS); - funcs.glClearDepthf(1); - funcs.glStencilMask(0xff); - funcs.glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - funcs.glStencilFunc(GL_ALWAYS, 0, 0xff); - setVertexAttribArrayEnabled(QT_TEXTURE_COORDS_ATTR, false); - setVertexAttribArrayEnabled(QT_VERTEX_COORDS_ATTR, false); - setVertexAttribArrayEnabled(QT_OPACITY_ATTR, false); - if (!QOpenGLContext::currentContext()->isOpenGLES()) { - // gl_Color, corresponding to vertex attribute 3, may have been changed - float color[] = { 1.0f, 1.0f, 1.0f, 1.0f }; - funcs.glVertexAttrib4fv(3, color); - } - if (vao.isCreated()) { - vao.release(); - funcs.glBindBuffer(GL_ARRAY_BUFFER, 0); - funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } -} - -void QOpenGL2PaintEngineEx::endNativePainting() -{ - Q_D(QOpenGL2PaintEngineEx); - d->needsSync = true; - d->nativePaintingActive = false; -} - -void QOpenGL2PaintEngineEx::invalidateState() -{ - Q_D(QOpenGL2PaintEngineEx); - d->needsSync = true; -} - -bool QOpenGL2PaintEngineEx::isNativePaintingActive() const { - Q_D(const QOpenGL2PaintEngineEx); - return d->nativePaintingActive; -} - -void QOpenGL2PaintEngineExPrivate::transferMode(EngineMode newMode) -{ - if (newMode == mode) - return; - - if (newMode == TextDrawingMode) { - shaderManager->setHasComplexGeometry(true); - } else { - shaderManager->setHasComplexGeometry(false); - } - - if (newMode == ImageDrawingMode) { - uploadData(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray, 8); - uploadData(QT_TEXTURE_COORDS_ATTR, staticTextureCoordinateArray, 8); - } - - if (newMode == ImageArrayDrawingMode || newMode == ImageOpacityArrayDrawingMode) { - uploadData(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data(), vertexCoordinateArray.vertexCount() * 2); - uploadData(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data(), textureCoordinateArray.vertexCount() * 2); - - if (newMode == ImageOpacityArrayDrawingMode) - uploadData(QT_OPACITY_ATTR, (GLfloat*)opacityArray.data(), opacityArray.size()); - } - - // This needs to change when we implement high-quality anti-aliasing... - if (newMode != TextDrawingMode) - shaderManager->setMaskType(QOpenGLEngineShaderManager::NoMask); - - mode = newMode; -} - -struct QOpenGL2PEVectorPathCache -{ -#ifdef QT_OPENGL_CACHE_AS_VBOS - GLuint vbo; - GLuint ibo; -#else - float *vertices; - void *indices; -#endif - int vertexCount; - int indexCount; - GLenum primitiveType; - qreal iscale; - QVertexIndexVector::Type indexType; -}; - -void QOpenGL2PaintEngineExPrivate::cleanupVectorPath(QPaintEngineEx *engine, void *data) -{ - QOpenGL2PEVectorPathCache *c = (QOpenGL2PEVectorPathCache *) data; -#ifdef QT_OPENGL_CACHE_AS_VBOS - Q_ASSERT(engine->type() == QPaintEngine::OpenGL2); - static_cast<QOpenGL2PaintEngineEx *>(engine)->d_func()->unusedVBOSToClean << c->vbo; - if (c->ibo) - d->unusedIBOSToClean << c->ibo; -#else - Q_UNUSED(engine); - free(c->vertices); - free(c->indices); -#endif - delete c; -} - -// Assumes everything is configured for the brush you want to use -void QOpenGL2PaintEngineExPrivate::fill(const QVectorPath& path) -{ - transferMode(BrushDrawingMode); - - if (snapToPixelGrid) { - snapToPixelGrid = false; - matrixDirty = true; - } - - // Might need to call updateMatrix to re-calculate inverseScale - if (matrixDirty) - updateMatrix(); - - const bool supportsElementIndexUint = funcs.hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint); - - const QPointF* const points = reinterpret_cast<const QPointF*>(path.points()); - - // Check to see if there's any hints - if (path.shape() == QVectorPath::RectangleHint) { - QOpenGLRect rect(points[0].x(), points[0].y(), points[2].x(), points[2].y()); - prepareForDraw(currentBrush.isOpaque()); - composite(rect); - } else if (path.isConvex()) { - - if (path.isCacheable()) { - QVectorPath::CacheEntry *data = path.lookupCacheData(q); - QOpenGL2PEVectorPathCache *cache; - - bool updateCache = false; - - if (data) { - cache = (QOpenGL2PEVectorPathCache *) data->data; - // Check if scale factor is exceeded and regenerate if so... - qreal scaleFactor = cache->iscale / inverseScale; - if (scaleFactor < 0.5 || scaleFactor > 2.0) { -#ifdef QT_OPENGL_CACHE_AS_VBOS - glDeleteBuffers(1, &cache->vbo); - cache->vbo = 0; - Q_ASSERT(cache->ibo == 0); -#else - free(cache->vertices); - Q_ASSERT(cache->indices == nullptr); -#endif - updateCache = true; - } - } else { - cache = new QOpenGL2PEVectorPathCache; - data = const_cast<QVectorPath &>(path).addCacheData(q, cache, cleanupVectorPath); - updateCache = true; - } - - // Flatten the path at the current scale factor and fill it into the cache struct. - if (updateCache) { - vertexCoordinateArray.clear(); - vertexCoordinateArray.addPath(path, inverseScale, false); - int vertexCount = vertexCoordinateArray.vertexCount(); - int floatSizeInBytes = vertexCount * 2 * sizeof(float); - cache->vertexCount = vertexCount; - cache->indexCount = 0; - cache->primitiveType = GL_TRIANGLE_FAN; - cache->iscale = inverseScale; -#ifdef QT_OPENGL_CACHE_AS_VBOS - funcs.glGenBuffers(1, &cache->vbo); - funcs.glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); - funcs.glBufferData(GL_ARRAY_BUFFER, floatSizeInBytes, vertexCoordinateArray.data(), GL_STATIC_DRAW); - cache->ibo = 0; -#else - cache->vertices = (float *) malloc(floatSizeInBytes); - memcpy(cache->vertices, vertexCoordinateArray.data(), floatSizeInBytes); - cache->indices = nullptr; -#endif - } - - prepareForDraw(currentBrush.isOpaque()); -#ifdef QT_OPENGL_CACHE_AS_VBOS - funcs.glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); - uploadData(QT_VERTEX_COORD_ATTR, 0, cache->vertexCount); - setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0); -#else - uploadData(QT_VERTEX_COORDS_ATTR, cache->vertices, cache->vertexCount * 2); -#endif - funcs.glDrawArrays(cache->primitiveType, 0, cache->vertexCount); - - } else { - // printf(" - Marking path as cachable...\n"); - // Tag it for later so that if the same path is drawn twice, it is assumed to be static and thus cachable - path.makeCacheable(); - vertexCoordinateArray.clear(); - vertexCoordinateArray.addPath(path, inverseScale, false); - prepareForDraw(currentBrush.isOpaque()); - drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN); - } - - } else { - bool useCache = path.isCacheable(); - if (useCache) { - QRectF bbox = path.controlPointRect(); - // If the path doesn't fit within these limits, it is possible that the triangulation will fail. - useCache &= (bbox.left() > -0x8000 * inverseScale) - && (bbox.right() < 0x8000 * inverseScale) - && (bbox.top() > -0x8000 * inverseScale) - && (bbox.bottom() < 0x8000 * inverseScale); - } - - if (useCache) { - QVectorPath::CacheEntry *data = path.lookupCacheData(q); - QOpenGL2PEVectorPathCache *cache; - - bool updateCache = false; - - if (data) { - cache = (QOpenGL2PEVectorPathCache *) data->data; - // Check if scale factor is exceeded and regenerate if so... - qreal scaleFactor = cache->iscale / inverseScale; - if (scaleFactor < 0.5 || scaleFactor > 2.0) { -#ifdef QT_OPENGL_CACHE_AS_VBOS - glDeleteBuffers(1, &cache->vbo); - glDeleteBuffers(1, &cache->ibo); -#else - free(cache->vertices); - free(cache->indices); -#endif - updateCache = true; - } - } else { - cache = new QOpenGL2PEVectorPathCache; - data = const_cast<QVectorPath &>(path).addCacheData(q, cache, cleanupVectorPath); - updateCache = true; - } - - // Flatten the path at the current scale factor and fill it into the cache struct. - if (updateCache) { - QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale), 1, supportsElementIndexUint); - cache->vertexCount = polys.vertices.size() / 2; - cache->indexCount = polys.indices.size(); - cache->primitiveType = GL_TRIANGLES; - cache->iscale = inverseScale; - cache->indexType = polys.indices.type(); -#ifdef QT_OPENGL_CACHE_AS_VBOS - funcs.glGenBuffers(1, &cache->vbo); - funcs.glGenBuffers(1, &cache->ibo); - funcs.glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); - funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache->ibo); - - if (polys.indices.type() == QVertexIndexVector::UnsignedInt) - funcs.glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(quint32) * polys.indices.size(), polys.indices.data(), GL_STATIC_DRAW); - else - funcs.glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(quint16) * polys.indices.size(), polys.indices.data(), GL_STATIC_DRAW); - - QVarLengthArray<float> vertices(polys.vertices.size()); - for (int i = 0; i < polys.vertices.size(); ++i) - vertices[i] = float(inverseScale * polys.vertices.at(i)); - funcs.glBufferData(GL_ARRAY_BUFFER, sizeof(float) * vertices.size(), vertices.data(), GL_STATIC_DRAW); -#else - cache->vertices = (float *) malloc(sizeof(float) * polys.vertices.size()); - if (polys.indices.type() == QVertexIndexVector::UnsignedInt) { - cache->indices = (quint32 *) malloc(sizeof(quint32) * polys.indices.size()); - memcpy(cache->indices, polys.indices.data(), sizeof(quint32) * polys.indices.size()); - } else { - cache->indices = (quint16 *) malloc(sizeof(quint16) * polys.indices.size()); - memcpy(cache->indices, polys.indices.data(), sizeof(quint16) * polys.indices.size()); - } - for (int i = 0; i < polys.vertices.size(); ++i) - cache->vertices[i] = float(inverseScale * polys.vertices.at(i)); -#endif - } - - prepareForDraw(currentBrush.isOpaque()); -#ifdef QT_OPENGL_CACHE_AS_VBOS - funcs.glBindBuffer(GL_ARRAY_BUFFER, cache->vbo); - funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache->ibo); - uploadData(QT_VERTEX_COORDS_ATTR, 0, cache->vertexCount); - setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, 0); - if (cache->indexType == QVertexIndexVector::UnsignedInt) - funcs.glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_INT, 0); - else - funcs.glDrawElements(cache->primitiveType, cache->indexCount, GL_UNSIGNED_SHORT, 0); - funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - funcs.glBindBuffer(GL_ARRAY_BUFFER, 0); -#else - uploadData(QT_VERTEX_COORDS_ATTR, cache->vertices, cache->vertexCount * 2); - const GLenum indexValueType = cache->indexType == QVertexIndexVector::UnsignedInt ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT; - const bool useIndexVbo = uploadIndexData(cache->indices, indexValueType, cache->indexCount); - funcs.glDrawElements(cache->primitiveType, cache->indexCount, indexValueType, useIndexVbo ? nullptr : cache->indices); -#endif - - } else { - // printf(" - Marking path as cachable...\n"); - // Tag it for later so that if the same path is drawn twice, it is assumed to be static and thus cachable - path.makeCacheable(); - - if (device->context()->format().stencilBufferSize() <= 0) { - // If there is no stencil buffer, triangulate the path instead. - - QRectF bbox = path.controlPointRect(); - // If the path doesn't fit within these limits, it is possible that the triangulation will fail. - bool withinLimits = (bbox.left() > -0x8000 * inverseScale) - && (bbox.right() < 0x8000 * inverseScale) - && (bbox.top() > -0x8000 * inverseScale) - && (bbox.bottom() < 0x8000 * inverseScale); - if (withinLimits) { - QTriangleSet polys = qTriangulate(path, QTransform().scale(1 / inverseScale, 1 / inverseScale), 1, supportsElementIndexUint); - - QVarLengthArray<float> vertices(polys.vertices.size()); - for (int i = 0; i < polys.vertices.size(); ++i) - vertices[i] = float(inverseScale * polys.vertices.at(i)); - - prepareForDraw(currentBrush.isOpaque()); - uploadData(QT_VERTEX_COORDS_ATTR, vertices.constData(), vertices.size()); - const GLenum indexValueType = funcs.hasOpenGLExtension(QOpenGLExtensions::ElementIndexUint) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT; - const bool useIndexVbo = uploadIndexData(polys.indices.data(), indexValueType, polys.indices.size()); - funcs.glDrawElements(GL_TRIANGLES, polys.indices.size(), indexValueType, useIndexVbo ? nullptr : polys.indices.data()); - } else { - // We can't handle big, concave painter paths with OpenGL without stencil buffer. - qWarning("Painter path exceeds +/-32767 pixels."); - } - return; - } - - // The path is too complicated & needs the stencil technique - vertexCoordinateArray.clear(); - vertexCoordinateArray.addPath(path, inverseScale, false); - - fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill()); - - funcs.glStencilMask(0xff); - funcs.glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); - - if (q->state()->clipTestEnabled) { - // Pass when high bit is set, replace stencil value with current clip - funcs.glStencilFunc(GL_NOTEQUAL, q->state()->currentClip, GL_STENCIL_HIGH_BIT); - } else if (path.hasWindingFill()) { - // Pass when any bit is set, replace stencil value with 0 - funcs.glStencilFunc(GL_NOTEQUAL, 0, 0xff); - } else { - // Pass when high bit is set, replace stencil value with 0 - funcs.glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT); - } - prepareForDraw(currentBrush.isOpaque()); - - // Stencil the brush onto the dest buffer - composite(vertexCoordinateArray.boundingRect()); - funcs.glStencilMask(0); - updateClipScissorTest(); - } - } -} - - -void QOpenGL2PaintEngineExPrivate::fillStencilWithVertexArray(const float *data, - int count, - int *stops, - int stopCount, - const QOpenGLRect &bounds, - StencilFillMode mode) -{ - Q_ASSERT(count || stops); - -// qDebug("QOpenGL2PaintEngineExPrivate::fillStencilWithVertexArray()"); - funcs.glStencilMask(0xff); // Enable stencil writes - - if (dirtyStencilRegion.intersects(currentScissorBounds)) { - const QRegion clearRegion = dirtyStencilRegion.intersected(currentScissorBounds); - funcs.glClearStencil(0); // Clear to zero - for (const QRect &rect : clearRegion) { -#ifndef QT_GL_NO_SCISSOR_TEST - setScissor(rect); -#endif - funcs.glClear(GL_STENCIL_BUFFER_BIT); - } - - dirtyStencilRegion -= currentScissorBounds; - -#ifndef QT_GL_NO_SCISSOR_TEST - updateClipScissorTest(); -#endif - } - - funcs.glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disable color writes - useSimpleShader(); - funcs.glEnable(GL_STENCIL_TEST); // For some reason, this has to happen _after_ the simple shader is use()'d - - if (mode == WindingFillMode) { - Q_ASSERT(stops && !count); - if (q->state()->clipTestEnabled) { - // Flatten clip values higher than current clip, and set high bit to match current clip - funcs.glStencilFunc(GL_LEQUAL, GL_STENCIL_HIGH_BIT | q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); - funcs.glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); - composite(bounds); - - funcs.glStencilFunc(GL_EQUAL, GL_STENCIL_HIGH_BIT, GL_STENCIL_HIGH_BIT); - } else if (!stencilClean) { - // Clear stencil buffer within bounding rect - funcs.glStencilFunc(GL_ALWAYS, 0, 0xff); - funcs.glStencilOp(GL_ZERO, GL_ZERO, GL_ZERO); - composite(bounds); - } - - // Inc. for front-facing triangle - funcs.glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR_WRAP, GL_INCR_WRAP); - // Dec. for back-facing "holes" - funcs.glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_DECR_WRAP); - funcs.glStencilMask(~GL_STENCIL_HIGH_BIT); - drawVertexArrays(data, stops, stopCount, GL_TRIANGLE_FAN); - - if (q->state()->clipTestEnabled) { - // Clear high bit of stencil outside of path - funcs.glStencilFunc(GL_EQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); - funcs.glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); - funcs.glStencilMask(GL_STENCIL_HIGH_BIT); - composite(bounds); - } - } else if (mode == OddEvenFillMode) { - funcs.glStencilMask(GL_STENCIL_HIGH_BIT); - funcs.glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit - drawVertexArrays(data, stops, stopCount, GL_TRIANGLE_FAN); - - } else { // TriStripStrokeFillMode - Q_ASSERT(count && !stops); // tristrips generated directly, so no vertexArray or stops - funcs.glStencilMask(GL_STENCIL_HIGH_BIT); -#if 0 - funcs.glStencilOp(GL_KEEP, GL_KEEP, GL_INVERT); // Simply invert the stencil bit - setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, data); - funcs.glDrawArrays(GL_TRIANGLE_STRIP, 0, count); -#else - - funcs.glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - if (q->state()->clipTestEnabled) { - funcs.glStencilFunc(GL_LEQUAL, q->state()->currentClip | GL_STENCIL_HIGH_BIT, - ~GL_STENCIL_HIGH_BIT); - } else { - funcs.glStencilFunc(GL_ALWAYS, GL_STENCIL_HIGH_BIT, 0xff); - } - - uploadData(QT_VERTEX_COORDS_ATTR, data, count * 2); - funcs.glDrawArrays(GL_TRIANGLE_STRIP, 0, count); -#endif - } - - // Enable color writes & disable stencil writes - funcs.glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); -} - -/* - If the maximum value in the stencil buffer is GL_STENCIL_HIGH_BIT - 1, - restore the stencil buffer to a pristine state. The current clip region - is set to 1, and the rest to 0. -*/ -void QOpenGL2PaintEngineExPrivate::resetClipIfNeeded() -{ - if (maxClip != (GL_STENCIL_HIGH_BIT - 1)) - return; - - Q_Q(QOpenGL2PaintEngineEx); - - useSimpleShader(); - funcs.glEnable(GL_STENCIL_TEST); - funcs.glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - - QRectF bounds = q->state()->matrix.inverted().mapRect(QRectF(0, 0, width, height)); - QOpenGLRect rect(bounds.left(), bounds.top(), bounds.right(), bounds.bottom()); - - // Set high bit on clip region - funcs.glStencilFunc(GL_LEQUAL, q->state()->currentClip, 0xff); - funcs.glStencilOp(GL_KEEP, GL_INVERT, GL_INVERT); - funcs.glStencilMask(GL_STENCIL_HIGH_BIT); - composite(rect); - - // Reset clipping to 1 and everything else to zero - funcs.glStencilFunc(GL_NOTEQUAL, 0x01, GL_STENCIL_HIGH_BIT); - funcs.glStencilOp(GL_ZERO, GL_REPLACE, GL_REPLACE); - funcs.glStencilMask(0xff); - composite(rect); - - q->state()->currentClip = 1; - q->state()->canRestoreClip = false; - - maxClip = 1; - - funcs.glStencilMask(0x0); - funcs.glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); -} - -bool QOpenGL2PaintEngineExPrivate::prepareForCachedGlyphDraw(const QFontEngineGlyphCache &cache) -{ - Q_Q(QOpenGL2PaintEngineEx); - - Q_ASSERT(cache.transform().type() <= QTransform::TxScale); - - QTransform &transform = q->state()->matrix; - transform.scale(1.0 / cache.transform().m11(), 1.0 / cache.transform().m22()); - bool ret = prepareForDraw(false); - transform.scale(cache.transform().m11(), cache.transform().m22()); - - return ret; -} - -bool QOpenGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque) -{ - if (brushTextureDirty && (mode == TextDrawingMode || mode == BrushDrawingMode)) - updateBrushTexture(); - - if (compositionModeDirty) - updateCompositionMode(); - - if (matrixDirty) - updateMatrix(); - - const bool stateHasOpacity = q->state()->opacity < 0.99f; - if (q->state()->composition_mode == QPainter::CompositionMode_Source - || (q->state()->composition_mode == QPainter::CompositionMode_SourceOver - && srcPixelsAreOpaque && !stateHasOpacity)) - { - funcs.glDisable(GL_BLEND); - } else { - funcs.glEnable(GL_BLEND); - } - - QOpenGLEngineShaderManager::OpacityMode opacityMode; - if (mode == ImageOpacityArrayDrawingMode) { - opacityMode = QOpenGLEngineShaderManager::AttributeOpacity; - } else { - opacityMode = stateHasOpacity ? QOpenGLEngineShaderManager::UniformOpacity - : QOpenGLEngineShaderManager::NoOpacity; - if (stateHasOpacity && (mode != ImageDrawingMode && mode != ImageArrayDrawingMode)) { - // Using a brush - bool brushIsPattern = (currentBrush.style() >= Qt::Dense1Pattern) && - (currentBrush.style() <= Qt::DiagCrossPattern); - - if ((currentBrush.style() == Qt::SolidPattern) || brushIsPattern) - opacityMode = QOpenGLEngineShaderManager::NoOpacity; // Global opacity handled by srcPixel shader - } - } - shaderManager->setOpacityMode(opacityMode); - - bool changed = shaderManager->useCorrectShaderProg(); - // If the shader program needs changing, we change it and mark all uniforms as dirty - if (changed) { - // The shader program has changed so mark all uniforms as dirty: - brushUniformsDirty = true; - opacityUniformDirty = true; - matrixUniformDirty = true; - } - - if (brushUniformsDirty && (mode == TextDrawingMode || mode == BrushDrawingMode)) - updateBrushUniforms(); - - if (opacityMode == QOpenGLEngineShaderManager::UniformOpacity && opacityUniformDirty) { - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::GlobalOpacity), (GLfloat)q->state()->opacity); - opacityUniformDirty = false; - } - - if (matrixUniformDirty && shaderManager->hasComplexGeometry()) { - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::Matrix), - pmvMatrix); - matrixUniformDirty = false; - } - - return changed; -} - -void QOpenGL2PaintEngineExPrivate::composite(const QOpenGLRect& boundingRect) -{ - setCoords(staticVertexCoordinateArray, boundingRect); - - uploadData(QT_VERTEX_COORDS_ATTR, staticVertexCoordinateArray, 8); - funcs.glDrawArrays(GL_TRIANGLE_FAN, 0, 4); -} - -// Draws the vertex array as a set of <vertexArrayStops.size()> triangle fans. -void QOpenGL2PaintEngineExPrivate::drawVertexArrays(const float *data, int *stops, int stopCount, - GLenum primitive) -{ - // Now setup the pointer to the vertex array: - uploadData(QT_VERTEX_COORDS_ATTR, data, stops[stopCount-1] * 2); - - int previousStop = 0; - for (int i=0; i<stopCount; ++i) { - int stop = stops[i]; - - funcs.glDrawArrays(primitive, previousStop, stop - previousStop); - previousStop = stop; - } -} - -/////////////////////////////////// Public Methods ////////////////////////////////////////// - -QOpenGL2PaintEngineEx::QOpenGL2PaintEngineEx() - : QPaintEngineEx(*(new QOpenGL2PaintEngineExPrivate(this))) -{ - gccaps &= ~QPaintEngine::RasterOpModes; -} - -QOpenGL2PaintEngineEx::~QOpenGL2PaintEngineEx() -{ -} - -void QOpenGL2PaintEngineEx::fill(const QVectorPath &path, const QBrush &brush) -{ - Q_D(QOpenGL2PaintEngineEx); - - if (qbrush_style(brush) == Qt::NoBrush) - return; - ensureActive(); - d->setBrush(brush); - d->fill(path); -} - -Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp - - -void QOpenGL2PaintEngineEx::stroke(const QVectorPath &path, const QPen &pen) -{ - Q_D(QOpenGL2PaintEngineEx); - - const QBrush &penBrush = qpen_brush(pen); - if (qpen_style(pen) == Qt::NoPen || qbrush_style(penBrush) == Qt::NoBrush) - return; - - QOpenGL2PaintEngineState *s = state(); - if (qt_pen_is_cosmetic(pen, state()->renderHints) && !qt_scaleForTransform(s->transform(), nullptr)) { - // QTriangulatingStroker class is not meant to support cosmetically sheared strokes. - QPaintEngineEx::stroke(path, pen); - return; - } - - ensureActive(); - d->setBrush(penBrush); - d->stroke(path, pen); -} - -void QOpenGL2PaintEngineExPrivate::stroke(const QVectorPath &path, const QPen &pen) -{ - const QOpenGL2PaintEngineState *s = q->state(); - if (snapToPixelGrid) { - snapToPixelGrid = false; - matrixDirty = true; - } - - const Qt::PenStyle penStyle = qpen_style(pen); - const QBrush &penBrush = qpen_brush(pen); - const bool opaque = penBrush.isOpaque() && s->opacity > 0.99; - - transferMode(BrushDrawingMode); - - // updateMatrix() is responsible for setting the inverse scale on - // the strokers, so we need to call it here and not wait for - // prepareForDraw() down below. - updateMatrix(); - - QRectF clip = q->state()->matrix.inverted().mapRect(q->state()->clipEnabled - ? q->state()->rectangleClip - : QRectF(0, 0, width, height)); - - if (penStyle == Qt::SolidLine) { - stroker.process(path, pen, clip, s->renderHints); - - } else { // Some sort of dash - dasher.process(path, pen, clip, s->renderHints); - - QVectorPath dashStroke(dasher.points(), - dasher.elementCount(), - dasher.elementTypes()); - stroker.process(dashStroke, pen, clip, s->renderHints); - } - - if (!stroker.vertexCount()) - return; - - if (opaque) { - prepareForDraw(opaque); - - uploadData(QT_VERTEX_COORDS_ATTR, stroker.vertices(), stroker.vertexCount()); - funcs.glDrawArrays(GL_TRIANGLE_STRIP, 0, stroker.vertexCount() / 2); - } else { - qreal width = qpen_widthf(pen) / 2; - if (width == 0) - width = 0.5; - qreal extra = pen.joinStyle() == Qt::MiterJoin - ? qMax(pen.miterLimit() * width, width) - : width; - - if (qt_pen_is_cosmetic(pen, q->state()->renderHints)) - extra = extra * inverseScale; - - QRectF bounds = path.controlPointRect().adjusted(-extra, -extra, extra, extra); - - fillStencilWithVertexArray(stroker.vertices(), stroker.vertexCount() / 2, - nullptr, 0, bounds, QOpenGL2PaintEngineExPrivate::TriStripStrokeFillMode); - - funcs.glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); - - // Pass when any bit is set, replace stencil value with 0 - funcs.glStencilFunc(GL_NOTEQUAL, 0, GL_STENCIL_HIGH_BIT); - prepareForDraw(false); - - // Stencil the brush onto the dest buffer - composite(bounds); - - funcs.glStencilMask(0); - - updateClipScissorTest(); - } -} - -void QOpenGL2PaintEngineEx::penChanged() { } -void QOpenGL2PaintEngineEx::brushChanged() { } -void QOpenGL2PaintEngineEx::brushOriginChanged() { } - -void QOpenGL2PaintEngineEx::opacityChanged() -{ -// qDebug("QOpenGL2PaintEngineEx::opacityChanged()"); - Q_D(QOpenGL2PaintEngineEx); - state()->opacityChanged = true; - - Q_ASSERT(d->shaderManager); - d->brushUniformsDirty = true; - d->opacityUniformDirty = true; -} - -void QOpenGL2PaintEngineEx::compositionModeChanged() -{ -// qDebug("QOpenGL2PaintEngineEx::compositionModeChanged()"); - Q_D(QOpenGL2PaintEngineEx); - state()->compositionModeChanged = true; - d->compositionModeDirty = true; -} - -void QOpenGL2PaintEngineEx::renderHintsChanged() -{ - state()->renderHintsChanged = true; - -#ifndef QT_OPENGL_ES_2 - if (!QOpenGLContext::currentContext()->isOpenGLES()) { - Q_D(QOpenGL2PaintEngineEx); -QT_WARNING_PUSH -QT_WARNING_DISABLE_DEPRECATED - if ((state()->renderHints & QPainter::Antialiasing) -#if QT_DEPRECATED_SINCE(5, 14) - || (state()->renderHints & QPainter::HighQualityAntialiasing) -#endif - ) - d->funcs.glEnable(GL_MULTISAMPLE); - else - d->funcs.glDisable(GL_MULTISAMPLE); -QT_WARNING_POP - } -#endif // QT_OPENGL_ES_2 - - Q_D(QOpenGL2PaintEngineEx); - - // This is a somewhat sneaky way of conceptually making the next call to - // updateTexture() use FoceUpdate for the TextureUpdateMode. We need this - // as new render hints may require updating the filter mode. - d->lastTextureUsed = GLuint(-1); - - d->brushTextureDirty = true; -// qDebug("QOpenGL2PaintEngineEx::renderHintsChanged() not implemented!"); -} - -void QOpenGL2PaintEngineEx::transformChanged() -{ - Q_D(QOpenGL2PaintEngineEx); - d->matrixDirty = true; - state()->matrixChanged = true; -} - - -static const QRectF scaleRect(const QRectF &r, qreal sx, qreal sy) -{ - return QRectF(r.x() * sx, r.y() * sy, r.width() * sx, r.height() * sy); -} - -void QOpenGL2PaintEngineEx::drawPixmap(const QRectF& dest, const QPixmap & pixmap, const QRectF & src) -{ - Q_D(QOpenGL2PaintEngineEx); - QOpenGLContext *ctx = d->ctx; - - // Draw pixmaps that are really images as images since drawImage has - // better handling of non-default image formats. - if (pixmap.paintEngine()->type() == QPaintEngine::Raster && !pixmap.isQBitmap()) - return drawImage(dest, pixmap.toImage(), src); - - int max_texture_size = ctx->d_func()->maxTextureSize(); - if (pixmap.width() > max_texture_size || pixmap.height() > max_texture_size) { - QPixmap scaled = pixmap.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio); - - const qreal sx = scaled.width() / qreal(pixmap.width()); - const qreal sy = scaled.height() / qreal(pixmap.height()); - - drawPixmap(dest, scaled, scaleRect(src, sx, sy)); - return; - } - - ensureActive(); - d->transferMode(ImageDrawingMode); - - GLenum filterMode = state()->renderHints & QPainter::SmoothPixmapTransform ? GL_LINEAR : GL_NEAREST; - d->updateTexture(QT_IMAGE_TEXTURE_UNIT, pixmap, GL_CLAMP_TO_EDGE, filterMode); - - bool isBitmap = pixmap.isQBitmap(); - bool isOpaque = !isBitmap && !pixmap.hasAlpha(); - - d->shaderManager->setSrcPixelType(isBitmap ? QOpenGLEngineShaderManager::PatternSrc : QOpenGLEngineShaderManager::ImageSrc); - - QOpenGLRect srcRect(src.left(), src.top(), src.right(), src.bottom()); - d->drawTexture(dest, srcRect, pixmap.size(), isOpaque, isBitmap); -} - -void QOpenGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, const QRectF& src, - Qt::ImageConversionFlags) -{ - Q_D(QOpenGL2PaintEngineEx); - QOpenGLContext *ctx = d->ctx; - - int max_texture_size = ctx->d_func()->maxTextureSize(); - if (image.width() > max_texture_size || image.height() > max_texture_size) { - QImage scaled = image.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio); - - const qreal sx = scaled.width() / qreal(image.width()); - const qreal sy = scaled.height() / qreal(image.height()); - - drawImage(dest, scaled, scaleRect(src, sx, sy)); - return; - } - - ensureActive(); - d->transferMode(ImageDrawingMode); - - QOpenGLTextureUploader::BindOptions bindOption = QOpenGLTextureUploader::PremultipliedAlphaBindOption; - // Use specialized bind for formats we have specialized shaders for. - switch (image.format()) { - case QImage::Format_RGBA8888: - case QImage::Format_ARGB32: - case QImage::Format_RGBA64: - d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::NonPremultipliedImageSrc); - bindOption = { }; - break; - case QImage::Format_Alpha8: - if (ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::TextureRGFormats)) { - d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::AlphaImageSrc); - bindOption = QOpenGLTextureUploader::UseRedForAlphaAndLuminanceBindOption; - } else - d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::ImageSrc); - break; - case QImage::Format_Grayscale8: - case QImage::Format_Grayscale16: - if (ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::TextureRGFormats)) { - d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::GrayscaleImageSrc); - bindOption = QOpenGLTextureUploader::UseRedForAlphaAndLuminanceBindOption; - } else - d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::ImageSrc); - break; - default: - d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::ImageSrc); - break; - } - - ImageWithBindOptions imageWithOptions = { image, bindOption }; - GLenum filterMode = state()->renderHints & QPainter::SmoothPixmapTransform ? GL_LINEAR : GL_NEAREST; - d->updateTexture(QT_IMAGE_TEXTURE_UNIT, imageWithOptions, GL_CLAMP_TO_EDGE, filterMode); - - d->drawTexture(dest, src, image.size(), !image.hasAlphaChannel()); -} - -void QOpenGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem) -{ - Q_D(QOpenGL2PaintEngineEx); - - ensureActive(); - - QPainterState *s = state(); - - QFontEngine *fontEngine = textItem->fontEngine(); - if (shouldDrawCachedGlyphs(fontEngine, s->matrix)) { - QFontEngine::GlyphFormat glyphFormat = fontEngine->glyphFormat != QFontEngine::Format_None - ? fontEngine->glyphFormat : d->glyphCacheFormat; - if (glyphFormat == QFontEngine::Format_A32) { - if (d->device->context()->format().alphaBufferSize() > 0 || s->matrix.type() > QTransform::TxTranslate - || (s->composition_mode != QPainter::CompositionMode_Source - && s->composition_mode != QPainter::CompositionMode_SourceOver)) - { - glyphFormat = QFontEngine::Format_A8; - } - } - - d->drawCachedGlyphs(glyphFormat, textItem); - } else { - QPaintEngineEx::drawStaticTextItem(textItem); - } -} - -bool QOpenGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const QSize &size, const QRectF &src) -{ - Q_D(QOpenGL2PaintEngineEx); - if (!d->shaderManager) - return false; - - ensureActive(); - d->transferMode(ImageDrawingMode); - - GLenum filterMode = state()->renderHints & QPainter::SmoothPixmapTransform ? GL_LINEAR : GL_NEAREST; - d->updateTexture(QT_IMAGE_TEXTURE_UNIT, textureId, GL_CLAMP_TO_EDGE, filterMode); - - d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::ImageSrc); - - QOpenGLRect srcRect(src.left(), src.bottom(), src.right(), src.top()); - d->drawTexture(dest, srcRect, size, false); - - return true; -} - -void QOpenGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem) -{ - Q_D(QOpenGL2PaintEngineEx); - - ensureActive(); - QOpenGL2PaintEngineState *s = state(); - - const QTextItemInt &ti = static_cast<const QTextItemInt &>(textItem); - - QTransform::TransformationType txtype = s->matrix.type(); - - QFontEngine::GlyphFormat glyphFormat = ti.fontEngine->glyphFormat != QFontEngine::Format_None - ? ti.fontEngine->glyphFormat : d->glyphCacheFormat; - - if (glyphFormat == QFontEngine::Format_A32) { - if (d->device->context()->format().alphaBufferSize() > 0 || txtype > QTransform::TxTranslate - || (state()->composition_mode != QPainter::CompositionMode_Source - && state()->composition_mode != QPainter::CompositionMode_SourceOver)) - { - glyphFormat = QFontEngine::Format_A8; - } - } - - if (shouldDrawCachedGlyphs(ti.fontEngine, s->matrix)) { - QVarLengthArray<QFixedPoint> positions; - QVarLengthArray<glyph_t> glyphs; - QTransform matrix = QTransform::fromTranslate(p.x(), p.y()); - ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions); - - { - QStaticTextItem staticTextItem; - staticTextItem.setFontEngine(ti.fontEngine); - staticTextItem.glyphs = glyphs.data(); - staticTextItem.numGlyphs = glyphs.size(); - staticTextItem.glyphPositions = positions.data(); - - d->drawCachedGlyphs(glyphFormat, &staticTextItem); - } - return; - } - - QPaintEngineEx::drawTextItem(p, ti); -} - -namespace { - - class QOpenGLStaticTextUserData: public QStaticTextUserData - { - public: - QOpenGLStaticTextUserData() - : QStaticTextUserData(OpenGLUserData), cacheSize(0, 0), cacheSerialNumber(0) - { - } - - ~QOpenGLStaticTextUserData() - { - } - - QSize cacheSize; - QOpenGL2PEXVertexArray vertexCoordinateArray; - QOpenGL2PEXVertexArray textureCoordinateArray; - QFontEngine::GlyphFormat glyphFormat; - int cacheSerialNumber; - }; - -} - - -// #define QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO - -bool QOpenGL2PaintEngineEx::shouldDrawCachedGlyphs(QFontEngine *fontEngine, const QTransform &t) const -{ - // The paint engine does not support projected cached glyph drawing - if (t.type() == QTransform::TxProject) - return false; - - // The font engine might not support filling the glyph cache - // with the given transform applied, in which case we need to - // fall back to the QPainterPath code-path. - if (!fontEngine->supportsTransformation(t)) { - // Except that drawing paths is slow, so for scales between - // 0.5 and 2.0 we leave the glyph cache untransformed and deal - // with the transform ourselves when painting, resulting in - // drawing 1x cached glyphs with a smooth-scale. - float det = t.determinant(); - if (det >= 0.25f && det <= 4.f) { - // Assuming the baseclass still agrees - return QPaintEngineEx::shouldDrawCachedGlyphs(fontEngine, t); - } - - return false; // Fall back to path-drawing - } - - return QPaintEngineEx::shouldDrawCachedGlyphs(fontEngine, t); -} - -void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngine::GlyphFormat glyphFormat, - QStaticTextItem *staticTextItem) -{ - Q_Q(QOpenGL2PaintEngineEx); - - QOpenGL2PaintEngineState *s = q->state(); - - void *cacheKey = ctx; // use context, not the shareGroup() -> the GL glyph cache uses FBOs which may not be shareable - bool recreateVertexArrays = false; - - QTransform glyphCacheTransform; - QFontEngine *fe = staticTextItem->fontEngine(); - if (fe->supportsTransformation(s->matrix)) { - // The font-engine supports rendering glyphs with the current transform, so we - // build a glyph-cache with the scale pre-applied, so that the cache contains - // glyphs with the appropriate resolution in the case of retina displays. - glyphCacheTransform = s->matrix.type() < QTransform::TxRotate ? - QTransform::fromScale(qAbs(s->matrix.m11()), qAbs(s->matrix.m22())) : - QTransform::fromScale( - QVector2D(s->matrix.m11(), s->matrix.m12()).length(), - QVector2D(s->matrix.m21(), s->matrix.m22()).length()); - } - - QOpenGLTextureGlyphCache *cache = - (QOpenGLTextureGlyphCache *) fe->glyphCache(cacheKey, glyphFormat, glyphCacheTransform); - if (!cache || cache->glyphFormat() != glyphFormat || cache->contextGroup() == nullptr) { - cache = new QOpenGLTextureGlyphCache(glyphFormat, glyphCacheTransform); - fe->setGlyphCache(cacheKey, cache); - recreateVertexArrays = true; - } - - if (staticTextItem->userDataNeedsUpdate) { - recreateVertexArrays = true; - } else if (staticTextItem->userData() == nullptr) { - recreateVertexArrays = true; - } else if (staticTextItem->userData()->type != QStaticTextUserData::OpenGLUserData) { - recreateVertexArrays = true; - } else { - QOpenGLStaticTextUserData *userData = static_cast<QOpenGLStaticTextUserData *>(staticTextItem->userData()); - if (userData->glyphFormat != glyphFormat) { - recreateVertexArrays = true; - } else if (userData->cacheSerialNumber != cache->serialNumber()) { - recreateVertexArrays = true; - } - } - - // We only need to update the cache with new glyphs if we are actually going to recreate the vertex arrays. - // If the cache size has changed, we do need to regenerate the vertices, but we don't need to repopulate the - // cache so this text is performed before we test if the cache size has changed. - if (recreateVertexArrays) { - cache->setPaintEnginePrivate(this); - if (!cache->populate(fe, staticTextItem->numGlyphs, - staticTextItem->glyphs, staticTextItem->glyphPositions)) { - // No space for glyphs in cache. We need to reset it and try again. - cache->clear(); - cache->populate(fe, staticTextItem->numGlyphs, - staticTextItem->glyphs, staticTextItem->glyphPositions); - } - - if (cache->hasPendingGlyphs()) { - // Filling in the glyphs binds and sets parameters, so we need to - // ensure that the glyph cache doesn't mess with whatever unit - // is currently active. Note that the glyph cache internally - // uses the image texture unit for blitting to the cache, while - // we switch between image and mask units when drawing. - static const GLenum glypchCacheTextureUnit = QT_IMAGE_TEXTURE_UNIT; - activateTextureUnit(glypchCacheTextureUnit); - - cache->fillInPendingGlyphs(); - - // We assume the cache can be trusted on which texture was bound - lastTextureUsed = cache->texture(); - - // But since the brush and image texture units are possibly shared - // we may have to re-bind brush textures after filling in the cache. - brushTextureDirty = (QT_BRUSH_TEXTURE_UNIT == glypchCacheTextureUnit); - } - cache->setPaintEnginePrivate(nullptr); - } - - if (cache->width() == 0 || cache->height() == 0) - return; - - if (glyphFormat == QFontEngine::Format_ARGB) - transferMode(ImageArrayDrawingMode); - else - transferMode(TextDrawingMode); - - int margin = fe->glyphMargin(glyphFormat); - - GLfloat dx = 1.0 / cache->width(); - GLfloat dy = 1.0 / cache->height(); - - // Use global arrays by default - QOpenGL2PEXVertexArray *vertexCoordinates = &vertexCoordinateArray; - QOpenGL2PEXVertexArray *textureCoordinates = &textureCoordinateArray; - - if (staticTextItem->useBackendOptimizations) { - QOpenGLStaticTextUserData *userData = nullptr; - - if (staticTextItem->userData() == nullptr - || staticTextItem->userData()->type != QStaticTextUserData::OpenGLUserData) { - - userData = new QOpenGLStaticTextUserData(); - staticTextItem->setUserData(userData); - - } else { - userData = static_cast<QOpenGLStaticTextUserData*>(staticTextItem->userData()); - } - - userData->glyphFormat = glyphFormat; - userData->cacheSerialNumber = cache->serialNumber(); - - // Use cache if backend optimizations is turned on - vertexCoordinates = &userData->vertexCoordinateArray; - textureCoordinates = &userData->textureCoordinateArray; - - QSize size(cache->width(), cache->height()); - if (userData->cacheSize != size) { - recreateVertexArrays = true; - userData->cacheSize = size; - } - } - - if (recreateVertexArrays) { - vertexCoordinates->clear(); - textureCoordinates->clear(); - - bool supportsSubPixelPositions = fe->supportsSubPixelPositions(); - for (int i=0; i<staticTextItem->numGlyphs; ++i) { - QFixed subPixelPosition; - if (supportsSubPixelPositions) - subPixelPosition = fe->subPixelPositionForX(staticTextItem->glyphPositions[i].x); - - QTextureGlyphCache::GlyphAndSubPixelPosition glyph(staticTextItem->glyphs[i], subPixelPosition); - - const QTextureGlyphCache::Coord &c = cache->coords[glyph]; - if (c.isNull()) - continue; - - int x = qFloor(staticTextItem->glyphPositions[i].x.toReal() * cache->transform().m11()) + c.baseLineX - margin; - int y = qRound(staticTextItem->glyphPositions[i].y.toReal() * cache->transform().m22()) - c.baseLineY - margin; - - vertexCoordinates->addQuad(QRectF(x, y, c.w, c.h)); - textureCoordinates->addQuad(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy)); - } - - staticTextItem->userDataNeedsUpdate = false; - } - - int numGlyphs = vertexCoordinates->vertexCount() / 4; - if (numGlyphs == 0) - return; - - if (elementIndices.size() < numGlyphs*6) { - Q_ASSERT(elementIndices.size() % 6 == 0); - int j = elementIndices.size() / 6 * 4; - while (j < numGlyphs*4) { - elementIndices.append(j + 0); - elementIndices.append(j + 0); - elementIndices.append(j + 1); - elementIndices.append(j + 2); - elementIndices.append(j + 3); - elementIndices.append(j + 3); - - j += 4; - } - -#if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO) - if (elementIndicesVBOId == 0) - funcs.glGenBuffers(1, &elementIndicesVBOId); - - funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementIndicesVBOId); - funcs.glBufferData(GL_ELEMENT_ARRAY_BUFFER, elementIndices.size() * sizeof(GLushort), - elementIndices.constData(), GL_STATIC_DRAW); -#endif - } else { -#if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO) - funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementIndicesVBOId); -#endif - } - - if (glyphFormat != QFontEngine::Format_ARGB || recreateVertexArrays) { - uploadData(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinates->data(), vertexCoordinates->vertexCount() * 2); - uploadData(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinates->data(), textureCoordinates->vertexCount() * 2); - } - - if (!snapToPixelGrid) { - snapToPixelGrid = true; - matrixDirty = true; - } - - QBrush pensBrush = q->state()->pen.brush(); - setBrush(pensBrush); - - if (glyphFormat == QFontEngine::Format_A32) { - - // Subpixel antialiasing without gamma correction - - QPainter::CompositionMode compMode = q->state()->composition_mode; - Q_ASSERT(compMode == QPainter::CompositionMode_Source - || compMode == QPainter::CompositionMode_SourceOver); - - shaderManager->setMaskType(QOpenGLEngineShaderManager::SubPixelMaskPass1); - - if (pensBrush.style() == Qt::SolidPattern) { - // Solid patterns can get away with only one pass. - QColor c = pensBrush.color(); - qreal oldOpacity = q->state()->opacity; - if (compMode == QPainter::CompositionMode_Source) { - c = qt_premultiplyColor(c, q->state()->opacity); - q->state()->opacity = 1; - opacityUniformDirty = true; - } - - compositionModeDirty = false; // I can handle this myself, thank you very much - prepareForCachedGlyphDraw(*cache); - - // prepareForCachedGlyphDraw() have set the opacity on the current shader, so the opacity state can now be reset. - if (compMode == QPainter::CompositionMode_Source) { - q->state()->opacity = oldOpacity; - opacityUniformDirty = true; - } - - funcs.glEnable(GL_BLEND); - funcs.glBlendFunc(GL_CONSTANT_COLOR, GL_ONE_MINUS_SRC_COLOR); - funcs.glBlendColor(c.redF(), c.greenF(), c.blueF(), c.alphaF()); - } else { - // Other brush styles need two passes. - - qreal oldOpacity = q->state()->opacity; - if (compMode == QPainter::CompositionMode_Source) { - q->state()->opacity = 1; - opacityUniformDirty = true; - pensBrush = Qt::white; - setBrush(pensBrush); - } - - compositionModeDirty = false; // I can handle this myself, thank you very much - prepareForCachedGlyphDraw(*cache); - funcs.glEnable(GL_BLEND); - funcs.glBlendFunc(GL_ZERO, GL_ONE_MINUS_SRC_COLOR); - - updateTexture(QT_MASK_TEXTURE_UNIT, cache->texture(), GL_REPEAT, GL_NEAREST, ForceUpdate); - -#if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO) - funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, 0); -#else - const bool useIndexVbo = uploadIndexData(elementIndices.data(), GL_UNSIGNED_SHORT, 6 * numGlyphs); - funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, useIndexVbo ? nullptr : elementIndices.data()); -#endif - - shaderManager->setMaskType(QOpenGLEngineShaderManager::SubPixelMaskPass2); - - if (compMode == QPainter::CompositionMode_Source) { - q->state()->opacity = oldOpacity; - opacityUniformDirty = true; - pensBrush = q->state()->pen.brush(); - setBrush(pensBrush); - } - - compositionModeDirty = false; - prepareForCachedGlyphDraw(*cache); - funcs.glEnable(GL_BLEND); - funcs.glBlendFunc(GL_ONE, GL_ONE); - } - compositionModeDirty = true; - } else if (glyphFormat == QFontEngine::Format_ARGB) { - currentBrush = noBrush; - shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::ImageSrc); - if (prepareForCachedGlyphDraw(*cache)) - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT); - } else { - // Grayscale/mono glyphs - - shaderManager->setMaskType(QOpenGLEngineShaderManager::PixelMask); - prepareForCachedGlyphDraw(*cache); - } - - GLenum textureUnit = QT_MASK_TEXTURE_UNIT; - if (glyphFormat == QFontEngine::Format_ARGB) - textureUnit = QT_IMAGE_TEXTURE_UNIT; - - QOpenGLTextureGlyphCache::FilterMode filterMode = (s->matrix.type() > QTransform::TxTranslate) ? - QOpenGLTextureGlyphCache::Linear : QOpenGLTextureGlyphCache::Nearest; - - GLenum glFilterMode = filterMode == QOpenGLTextureGlyphCache::Linear ? GL_LINEAR : GL_NEAREST; - - TextureUpdateMode updateMode = UpdateIfNeeded; - if (cache->filterMode() != filterMode) { - updateMode = ForceUpdate; - cache->setFilterMode(filterMode); - } - - updateTexture(textureUnit, cache->texture(), GL_REPEAT, glFilterMode, updateMode); - -#if defined(QT_OPENGL_DRAWCACHEDGLYPHS_INDEX_ARRAY_VBO) - funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, 0); - funcs.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); -#else - const bool useIndexVbo = uploadIndexData(elementIndices.data(), GL_UNSIGNED_SHORT, 6 * numGlyphs); - funcs.glDrawElements(GL_TRIANGLE_STRIP, 6 * numGlyphs, GL_UNSIGNED_SHORT, useIndexVbo ? nullptr : elementIndices.data()); -#endif -} - -void QOpenGL2PaintEngineEx::drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap, - QPainter::PixmapFragmentHints hints) -{ - Q_D(QOpenGL2PaintEngineEx); - // Use fallback for extended composition modes. - if (state()->composition_mode > QPainter::CompositionMode_Plus) { - QPaintEngineEx::drawPixmapFragments(fragments, fragmentCount, pixmap, hints); - return; - } - - ensureActive(); - int max_texture_size = d->ctx->d_func()->maxTextureSize(); - if (pixmap.width() > max_texture_size || pixmap.height() > max_texture_size) { - QPixmap scaled = pixmap.scaled(max_texture_size, max_texture_size, Qt::KeepAspectRatio); - d->drawPixmapFragments(fragments, fragmentCount, scaled, hints); - } else { - d->drawPixmapFragments(fragments, fragmentCount, pixmap, hints); - } -} - - -void QOpenGL2PaintEngineExPrivate::drawPixmapFragments(const QPainter::PixmapFragment *fragments, - int fragmentCount, const QPixmap &pixmap, - QPainter::PixmapFragmentHints hints) -{ - GLfloat dx = 1.0f / pixmap.size().width(); - GLfloat dy = 1.0f / pixmap.size().height(); - - vertexCoordinateArray.clear(); - textureCoordinateArray.clear(); - opacityArray.reset(); - - if (snapToPixelGrid) { - snapToPixelGrid = false; - matrixDirty = true; - } - - bool allOpaque = true; - - for (int i = 0; i < fragmentCount; ++i) { - qreal s = 0; - qreal c = 1; - if (fragments[i].rotation != 0) { - s = qFastSin(qDegreesToRadians(fragments[i].rotation)); - c = qFastCos(qDegreesToRadians(fragments[i].rotation)); - } - - qreal right = 0.5 * fragments[i].scaleX * fragments[i].width; - qreal bottom = 0.5 * fragments[i].scaleY * fragments[i].height; - QOpenGLPoint bottomRight(right * c - bottom * s, right * s + bottom * c); - QOpenGLPoint bottomLeft(-right * c - bottom * s, -right * s + bottom * c); - - vertexCoordinateArray.addVertex(bottomRight.x + fragments[i].x, bottomRight.y + fragments[i].y); - vertexCoordinateArray.addVertex(-bottomLeft.x + fragments[i].x, -bottomLeft.y + fragments[i].y); - vertexCoordinateArray.addVertex(-bottomRight.x + fragments[i].x, -bottomRight.y + fragments[i].y); - vertexCoordinateArray.addVertex(-bottomRight.x + fragments[i].x, -bottomRight.y + fragments[i].y); - vertexCoordinateArray.addVertex(bottomLeft.x + fragments[i].x, bottomLeft.y + fragments[i].y); - vertexCoordinateArray.addVertex(bottomRight.x + fragments[i].x, bottomRight.y + fragments[i].y); - - QOpenGLRect src(fragments[i].sourceLeft * dx, fragments[i].sourceTop * dy, - (fragments[i].sourceLeft + fragments[i].width) * dx, - (fragments[i].sourceTop + fragments[i].height) * dy); - - textureCoordinateArray.addVertex(src.right, src.bottom); - textureCoordinateArray.addVertex(src.right, src.top); - textureCoordinateArray.addVertex(src.left, src.top); - textureCoordinateArray.addVertex(src.left, src.top); - textureCoordinateArray.addVertex(src.left, src.bottom); - textureCoordinateArray.addVertex(src.right, src.bottom); - - qreal opacity = fragments[i].opacity * q->state()->opacity; - opacityArray << opacity << opacity << opacity << opacity << opacity << opacity; - allOpaque &= (opacity >= 0.99f); - } - - transferMode(ImageOpacityArrayDrawingMode); - - GLenum filterMode = q->state()->renderHints & QPainter::SmoothPixmapTransform ? GL_LINEAR : GL_NEAREST; - updateTexture(QT_IMAGE_TEXTURE_UNIT, pixmap, GL_CLAMP_TO_EDGE, filterMode); - - bool isBitmap = pixmap.isQBitmap(); - bool isOpaque = !isBitmap && (!pixmap.hasAlpha() || (hints & QPainter::OpaqueHint)) && allOpaque; - - // Setup for texture drawing - currentBrush = noBrush; - shaderManager->setSrcPixelType(isBitmap ? QOpenGLEngineShaderManager::PatternSrc - : QOpenGLEngineShaderManager::ImageSrc); - if (prepareForDraw(isOpaque)) - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT); - - if (isBitmap) { - QColor col = qt_premultiplyColor(q->state()->pen.color(), (GLfloat)q->state()->opacity); - shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::PatternColor), col); - } - - funcs.glDrawArrays(GL_TRIANGLES, 0, 6 * fragmentCount); -} - -bool QOpenGL2PaintEngineEx::begin(QPaintDevice *pdev) -{ - Q_D(QOpenGL2PaintEngineEx); - - Q_ASSERT(pdev->devType() == QInternal::OpenGL); - d->device = static_cast<QOpenGLPaintDevice*>(pdev); - - if (!d->device) - return false; - - d->device->ensureActiveTarget(); - - if (d->device->context() != QOpenGLContext::currentContext() || !d->device->context()) { - qWarning("QPainter::begin(): QOpenGLPaintDevice's context needs to be current"); - return false; - } - - if (d->ctx != QOpenGLContext::currentContext() - || (d->ctx && QOpenGLContext::currentContext() && d->ctx->format() != QOpenGLContext::currentContext()->format())) { - d->vertexBuffer.destroy(); - d->texCoordBuffer.destroy(); - d->opacityBuffer.destroy(); - d->indexBuffer.destroy(); - d->vao.destroy(); - } - - d->ctx = QOpenGLContext::currentContext(); - d->ctx->d_func()->active_engine = this; - - QOpenGLPaintDevicePrivate::get(d->device)->beginPaint(); - - d->funcs.initializeOpenGLFunctions(); - - // Generate a new Vertex Array Object if we don't have one already. We can - // only hit the VAO-based path when using a core profile context. This is - // because while non-core contexts can support VAOs via extensions, legacy - // components like the QtOpenGL module do not know about VAOs. There are - // still tests for QGL-QOpenGL paint engine interoperability, so keep the - // status quo for now, and avoid introducing a VAO in non-core contexts. - const bool needsVAO = d->ctx->format().profile() == QSurfaceFormat::CoreProfile - && d->ctx->format().version() >= qMakePair(3, 2); - if (needsVAO && !d->vao.isCreated()) { - bool created = d->vao.create(); - - // If we managed to create it then we have a profile that supports VAOs - if (created) { - d->vao.bind(); - - // Generate a new Vertex Buffer Object if we don't have one already - if (!d->vertexBuffer.isCreated()) { - d->vertexBuffer.create(); - // Set its usage to StreamDraw, we will use this buffer only a few times before refilling it - d->vertexBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw); - } - if (!d->texCoordBuffer.isCreated()) { - d->texCoordBuffer.create(); - d->texCoordBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw); - } - if (!d->opacityBuffer.isCreated()) { - d->opacityBuffer.create(); - d->opacityBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw); - } - if (!d->indexBuffer.isCreated()) { - d->indexBuffer.create(); - d->indexBuffer.setUsagePattern(QOpenGLBuffer::StreamDraw); - } - } - } - - for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i) - d->vertexAttributeArraysEnabledState[i] = false; - - const QSize sz = d->device->size(); - d->width = sz.width(); - d->height = sz.height(); - d->mode = BrushDrawingMode; - d->brushTextureDirty = true; - d->brushUniformsDirty = true; - d->matrixUniformDirty = true; - d->matrixDirty = true; - d->compositionModeDirty = true; - d->opacityUniformDirty = true; - d->needsSync = true; - d->useSystemClip = !systemClip().isEmpty(); - d->currentBrush = QBrush(); - - d->dirtyStencilRegion = QRect(0, 0, d->width, d->height); - d->stencilClean = true; - - d->shaderManager = new QOpenGLEngineShaderManager(d->ctx); - - d->funcs.glDisable(GL_STENCIL_TEST); - d->funcs.glDisable(GL_DEPTH_TEST); - d->funcs.glDisable(GL_SCISSOR_TEST); - - d->glyphCacheFormat = QFontEngine::Format_A8; - -#ifndef QT_OPENGL_ES_2 - if (!QOpenGLContext::currentContext()->isOpenGLES()) { - d->funcs.glDisable(GL_MULTISAMPLE); - d->glyphCacheFormat = QFontEngine::Format_A32; - d->multisamplingAlwaysEnabled = false; - } else -#endif // QT_OPENGL_ES_2 - { - // OpenGL ES can't switch MSAA off, so if the gl paint device is - // multisampled, it's always multisampled. - d->multisamplingAlwaysEnabled = d->device->context()->format().samples() > 1; - } - - return true; -} - -bool QOpenGL2PaintEngineEx::end() -{ - Q_D(QOpenGL2PaintEngineEx); - - QOpenGLPaintDevicePrivate::get(d->device)->endPaint(); - - QOpenGLContext *ctx = d->ctx; - d->funcs.glUseProgram(0); - d->transferMode(BrushDrawingMode); - - ctx->d_func()->active_engine = nullptr; - - d->resetGLState(); - - delete d->shaderManager; - d->shaderManager = nullptr; - d->currentBrush = QBrush(); - -#ifdef QT_OPENGL_CACHE_AS_VBOS - if (!d->unusedVBOSToClean.isEmpty()) { - glDeleteBuffers(d->unusedVBOSToClean.size(), d->unusedVBOSToClean.constData()); - d->unusedVBOSToClean.clear(); - } - if (!d->unusedIBOSToClean.isEmpty()) { - glDeleteBuffers(d->unusedIBOSToClean.size(), d->unusedIBOSToClean.constData()); - d->unusedIBOSToClean.clear(); - } -#endif - - return false; -} - -void QOpenGL2PaintEngineEx::ensureActive() -{ - Q_D(QOpenGL2PaintEngineEx); - QOpenGLContext *ctx = d->ctx; - - if (d->vao.isCreated()) - d->vao.bind(); - - if (isActive() && ctx->d_func()->active_engine != this) { - ctx->d_func()->active_engine = this; - d->needsSync = true; - } - - if (d->needsSync) { - d->device->ensureActiveTarget(); - - d->transferMode(BrushDrawingMode); - d->funcs.glViewport(0, 0, d->width, d->height); - d->needsSync = false; - d->shaderManager->setDirty(); - d->syncGlState(); - for (int i = 0; i < 3; ++i) - d->vertexAttribPointers[i] = (GLfloat*)-1; // Assume the pointers are clobbered - setState(state()); - } -} - -void QOpenGL2PaintEngineExPrivate::updateClipScissorTest() -{ - Q_Q(QOpenGL2PaintEngineEx); - if (q->state()->clipTestEnabled) { - funcs.glEnable(GL_STENCIL_TEST); - funcs.glStencilFunc(GL_LEQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); - } else { - funcs.glDisable(GL_STENCIL_TEST); - funcs.glStencilFunc(GL_ALWAYS, 0, 0xff); - } - -#ifdef QT_GL_NO_SCISSOR_TEST - currentScissorBounds = QRect(0, 0, width, height); -#else - QRect bounds = q->state()->rectangleClip; - if (!q->state()->clipEnabled) { - if (useSystemClip) - bounds = systemClip.boundingRect(); - else - bounds = QRect(0, 0, width, height); - } else { - if (useSystemClip) - bounds = bounds.intersected(systemClip.boundingRect()); - else - bounds = bounds.intersected(QRect(0, 0, width, height)); - } - - currentScissorBounds = bounds; - - if (bounds == QRect(0, 0, width, height)) { - funcs.glDisable(GL_SCISSOR_TEST); - } else { - funcs.glEnable(GL_SCISSOR_TEST); - setScissor(bounds); - } -#endif -} - -void QOpenGL2PaintEngineExPrivate::setScissor(const QRect &rect) -{ - const int left = rect.left(); - const int width = rect.width(); - int bottom = height - (rect.top() + rect.height()); - if (device->paintFlipped()) { - bottom = rect.top(); - } - const int height = rect.height(); - - funcs.glScissor(left, bottom, width, height); -} - -void QOpenGL2PaintEngineEx::clipEnabledChanged() -{ - Q_D(QOpenGL2PaintEngineEx); - - state()->clipChanged = true; - - if (painter()->hasClipping()) - d->regenerateClip(); - else - d->systemStateChanged(); -} - -void QOpenGL2PaintEngineExPrivate::clearClip(uint value) -{ - dirtyStencilRegion -= currentScissorBounds; - - funcs.glStencilMask(0xff); - funcs.glClearStencil(value); - funcs.glClear(GL_STENCIL_BUFFER_BIT); - funcs.glStencilMask(0x0); - - q->state()->needsClipBufferClear = false; -} - -void QOpenGL2PaintEngineExPrivate::writeClip(const QVectorPath &path, uint value) -{ - transferMode(BrushDrawingMode); - - if (snapToPixelGrid) { - snapToPixelGrid = false; - matrixDirty = true; - } - - if (matrixDirty) - updateMatrix(); - - stencilClean = false; - - const bool singlePass = !path.hasWindingFill() - && (((q->state()->currentClip == maxClip - 1) && q->state()->clipTestEnabled) - || q->state()->needsClipBufferClear); - const uint referenceClipValue = q->state()->needsClipBufferClear ? 1 : q->state()->currentClip; - - if (q->state()->needsClipBufferClear) - clearClip(1); - - if (path.isEmpty()) { - funcs.glEnable(GL_STENCIL_TEST); - funcs.glStencilFunc(GL_LEQUAL, value, ~GL_STENCIL_HIGH_BIT); - return; - } - - if (q->state()->clipTestEnabled) - funcs.glStencilFunc(GL_LEQUAL, q->state()->currentClip, ~GL_STENCIL_HIGH_BIT); - else - funcs.glStencilFunc(GL_ALWAYS, 0, 0xff); - - vertexCoordinateArray.clear(); - vertexCoordinateArray.addPath(path, inverseScale, false); - - if (!singlePass) - fillStencilWithVertexArray(vertexCoordinateArray, path.hasWindingFill()); - - funcs.glColorMask(false, false, false, false); - funcs.glEnable(GL_STENCIL_TEST); - useSimpleShader(); - - if (singlePass) { - // Under these conditions we can set the new stencil value in a single - // pass, by using the current value and the "new value" as the toggles - - funcs.glStencilFunc(GL_LEQUAL, referenceClipValue, ~GL_STENCIL_HIGH_BIT); - funcs.glStencilOp(GL_KEEP, GL_INVERT, GL_INVERT); - funcs.glStencilMask(value ^ referenceClipValue); - - drawVertexArrays(vertexCoordinateArray, GL_TRIANGLE_FAN); - } else { - funcs.glStencilOp(GL_KEEP, GL_REPLACE, GL_REPLACE); - funcs.glStencilMask(0xff); - - if (!q->state()->clipTestEnabled && path.hasWindingFill()) { - // Pass when any clip bit is set, set high bit - funcs.glStencilFunc(GL_NOTEQUAL, GL_STENCIL_HIGH_BIT, ~GL_STENCIL_HIGH_BIT); - composite(vertexCoordinateArray.boundingRect()); - } - - // Pass when high bit is set, replace stencil value with new clip value - funcs.glStencilFunc(GL_NOTEQUAL, value, GL_STENCIL_HIGH_BIT); - - composite(vertexCoordinateArray.boundingRect()); - } - - funcs.glStencilFunc(GL_LEQUAL, value, ~GL_STENCIL_HIGH_BIT); - funcs.glStencilMask(0); - - funcs.glColorMask(true, true, true, true); -} - -void QOpenGL2PaintEngineEx::clip(const QVectorPath &path, Qt::ClipOperation op) -{ -// qDebug("QOpenGL2PaintEngineEx::clip()"); - Q_D(QOpenGL2PaintEngineEx); - - state()->clipChanged = true; - - ensureActive(); - - if (op == Qt::ReplaceClip) { - op = Qt::IntersectClip; - if (d->hasClipOperations()) { - d->systemStateChanged(); - state()->canRestoreClip = false; - } - } - -#ifndef QT_GL_NO_SCISSOR_TEST - if (!path.isEmpty() && op == Qt::IntersectClip && (path.shape() == QVectorPath::RectangleHint)) { - const QPointF* const points = reinterpret_cast<const QPointF*>(path.points()); - QRectF rect(points[0], points[2]); - - if (state()->matrix.type() <= QTransform::TxScale - || (state()->matrix.type() == QTransform::TxRotate - && qFuzzyIsNull(state()->matrix.m11()) - && qFuzzyIsNull(state()->matrix.m22()))) - { - state()->rectangleClip = state()->rectangleClip.intersected(state()->matrix.mapRect(rect).toRect()); - d->updateClipScissorTest(); - return; - } - } -#endif - - const QRect pathRect = state()->matrix.mapRect(path.controlPointRect()).toAlignedRect(); - - switch (op) { - case Qt::NoClip: - if (d->useSystemClip) { - state()->clipTestEnabled = true; - state()->currentClip = 1; - } else { - state()->clipTestEnabled = false; - } - state()->rectangleClip = QRect(0, 0, d->width, d->height); - state()->canRestoreClip = false; - d->updateClipScissorTest(); - break; - case Qt::IntersectClip: - state()->rectangleClip = state()->rectangleClip.intersected(pathRect); - d->updateClipScissorTest(); - d->resetClipIfNeeded(); - ++d->maxClip; - d->writeClip(path, d->maxClip); - state()->currentClip = d->maxClip; - state()->clipTestEnabled = true; - break; - default: - break; - } -} - -void QOpenGL2PaintEngineExPrivate::regenerateClip() -{ - systemStateChanged(); - replayClipOperations(); -} - -void QOpenGL2PaintEngineExPrivate::systemStateChanged() -{ - Q_Q(QOpenGL2PaintEngineEx); - - q->state()->clipChanged = true; - - if (systemClip.isEmpty()) { - useSystemClip = false; - } else { - if (q->paintDevice()->devType() == QInternal::Widget && currentClipDevice) { - //QWidgetPrivate *widgetPrivate = qt_widget_private(static_cast<QWidget *>(currentClipDevice)->window()); - //useSystemClip = widgetPrivate->extra && widgetPrivate->extra->inRenderWithPainter; - useSystemClip = true; - } else { - useSystemClip = true; - } - } - - q->state()->clipTestEnabled = false; - q->state()->needsClipBufferClear = true; - - q->state()->currentClip = 1; - maxClip = 1; - - q->state()->rectangleClip = useSystemClip ? systemClip.boundingRect() : QRect(0, 0, width, height); - updateClipScissorTest(); - - if (systemClip.rectCount() == 1) { - if (systemClip.boundingRect() == QRect(0, 0, width, height)) - useSystemClip = false; -#ifndef QT_GL_NO_SCISSOR_TEST - // scissoring takes care of the system clip - return; -#endif - } - - if (useSystemClip) { - clearClip(0); - - QPainterPath path; - path.addRegion(systemClip); - - q->state()->currentClip = 0; - writeClip(qtVectorPathForPath(q->state()->matrix.inverted().map(path)), 1); - q->state()->currentClip = 1; - q->state()->clipTestEnabled = true; - } -} - -void QOpenGL2PaintEngineEx::setState(QPainterState *new_state) -{ - // qDebug("QOpenGL2PaintEngineEx::setState()"); - - Q_D(QOpenGL2PaintEngineEx); - - QOpenGL2PaintEngineState *s = static_cast<QOpenGL2PaintEngineState *>(new_state); - QOpenGL2PaintEngineState *old_state = state(); - - QPaintEngineEx::setState(s); - - if (s->isNew) { - // Newly created state object. The call to setState() - // will either be followed by a call to begin(), or we are - // setting the state as part of a save(). - s->isNew = false; - return; - } - - // Setting the state as part of a restore(). - - if (old_state == s || old_state->renderHintsChanged) - renderHintsChanged(); - - if (old_state == s || old_state->matrixChanged) - d->matrixDirty = true; - - if (old_state == s || old_state->compositionModeChanged) - d->compositionModeDirty = true; - - if (old_state == s || old_state->opacityChanged) - d->opacityUniformDirty = true; - - if (old_state == s || old_state->clipChanged) { - if (old_state && old_state != s && old_state->canRestoreClip) { - d->updateClipScissorTest(); - d->funcs.glDepthFunc(GL_LEQUAL); - } else { - d->regenerateClip(); - } - } -} - -QPainterState *QOpenGL2PaintEngineEx::createState(QPainterState *orig) const -{ - if (orig) - const_cast<QOpenGL2PaintEngineEx *>(this)->ensureActive(); - - QOpenGL2PaintEngineState *s; - if (!orig) - s = new QOpenGL2PaintEngineState(); - else - s = new QOpenGL2PaintEngineState(*static_cast<QOpenGL2PaintEngineState *>(orig)); - - s->matrixChanged = false; - s->compositionModeChanged = false; - s->opacityChanged = false; - s->renderHintsChanged = false; - s->clipChanged = false; - - return s; -} - -QOpenGL2PaintEngineState::QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other) - : QPainterState(other) -{ - isNew = true; - needsClipBufferClear = other.needsClipBufferClear; - clipTestEnabled = other.clipTestEnabled; - currentClip = other.currentClip; - canRestoreClip = other.canRestoreClip; - rectangleClip = other.rectangleClip; -} - -QOpenGL2PaintEngineState::QOpenGL2PaintEngineState() -{ - isNew = true; - needsClipBufferClear = true; - clipTestEnabled = false; - canRestoreClip = true; -} - -QOpenGL2PaintEngineState::~QOpenGL2PaintEngineState() -{ -} - -void QOpenGL2PaintEngineExPrivate::setVertexAttribArrayEnabled(int arrayIndex, bool enabled) -{ - Q_ASSERT(arrayIndex < QT_GL_VERTEX_ARRAY_TRACKED_COUNT); - - if (vertexAttributeArraysEnabledState[arrayIndex] && !enabled) - funcs.glDisableVertexAttribArray(arrayIndex); - - if (!vertexAttributeArraysEnabledState[arrayIndex] && enabled) - funcs.glEnableVertexAttribArray(arrayIndex); - - vertexAttributeArraysEnabledState[arrayIndex] = enabled; -} - -void QOpenGL2PaintEngineExPrivate::syncGlState() -{ - for (int i = 0; i < QT_GL_VERTEX_ARRAY_TRACKED_COUNT; ++i) { - if (vertexAttributeArraysEnabledState[i]) - funcs.glEnableVertexAttribArray(i); - else - funcs.glDisableVertexAttribArray(i); - } -} - - -QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglpaintengine_p.h b/src/gui/opengl/qopenglpaintengine_p.h deleted file mode 100644 index 81f17572b2..0000000000 --- a/src/gui/opengl/qopenglpaintengine_p.h +++ /dev/null @@ -1,396 +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 QOPENGLPAINTENGINE_P_H -#define QOPENGLPAINTENGINE_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtGui/private/qtguiglobal_p.h> -#include <QDebug> - -#include <qopenglpaintdevice.h> - -#include <private/qpaintengineex_p.h> -#include <private/qopenglengineshadermanager_p.h> -#include <private/qopengl2pexvertexarray_p.h> -#include <private/qfontengine_p.h> -#include <private/qdatabuffer_p.h> -#include <private/qtriangulatingstroker_p.h> - -#include <private/qopenglextensions_p.h> - -#include <QOpenGLVertexArrayObject> -#include <QOpenGLBuffer> - -enum EngineMode { - ImageDrawingMode, - TextDrawingMode, - BrushDrawingMode, - ImageArrayDrawingMode, - ImageOpacityArrayDrawingMode -}; - -QT_BEGIN_NAMESPACE - -#define GL_STENCIL_HIGH_BIT GLuint(0x80) -#define QT_UNKNOWN_TEXTURE_UNIT GLuint(-1) -#define QT_DEFAULT_TEXTURE_UNIT GLuint(0) -#define QT_BRUSH_TEXTURE_UNIT GLuint(0) -#define QT_IMAGE_TEXTURE_UNIT GLuint(0) //Can be the same as brush texture unit -#define QT_MASK_TEXTURE_UNIT GLuint(1) -#define QT_BACKGROUND_TEXTURE_UNIT GLuint(2) - -class QOpenGL2PaintEngineExPrivate; - -class QOpenGL2PaintEngineState : public QPainterState -{ -public: - QOpenGL2PaintEngineState(QOpenGL2PaintEngineState &other); - QOpenGL2PaintEngineState(); - ~QOpenGL2PaintEngineState(); - - uint isNew : 1; - uint needsClipBufferClear : 1; - uint clipTestEnabled : 1; - uint canRestoreClip : 1; - uint matrixChanged : 1; - uint compositionModeChanged : 1; - uint opacityChanged : 1; - uint renderHintsChanged : 1; - uint clipChanged : 1; - uint currentClip : 8; - - QRect rectangleClip; -}; - -class Q_GUI_EXPORT QOpenGL2PaintEngineEx : public QPaintEngineEx -{ - Q_DECLARE_PRIVATE(QOpenGL2PaintEngineEx) -public: - QOpenGL2PaintEngineEx(); - ~QOpenGL2PaintEngineEx(); - - bool begin(QPaintDevice *device) override; - void ensureActive(); - bool end() override; - - virtual void clipEnabledChanged() override; - virtual void penChanged() override; - virtual void brushChanged() override; - virtual void brushOriginChanged() override; - virtual void opacityChanged() override; - virtual void compositionModeChanged() override; - virtual void renderHintsChanged() override; - virtual void transformChanged() override; - - virtual void drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr) override; - virtual void drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap, - QPainter::PixmapFragmentHints hints) override; - virtual void drawImage(const QRectF &r, const QImage &pm, const QRectF &sr, - Qt::ImageConversionFlags flags = Qt::AutoColor) override; - virtual void drawTextItem(const QPointF &p, const QTextItem &textItem) override; - virtual void fill(const QVectorPath &path, const QBrush &brush) override; - virtual void stroke(const QVectorPath &path, const QPen &pen) override; - virtual void clip(const QVectorPath &path, Qt::ClipOperation op) override; - - virtual void drawStaticTextItem(QStaticTextItem *textItem) override; - - bool drawTexture(const QRectF &r, GLuint textureId, const QSize &size, const QRectF &sr); - - Type type() const override { return OpenGL2; } - - virtual void setState(QPainterState *s) override; - virtual QPainterState *createState(QPainterState *orig) const override; - inline QOpenGL2PaintEngineState *state() { - return static_cast<QOpenGL2PaintEngineState *>(QPaintEngineEx::state()); - } - inline const QOpenGL2PaintEngineState *state() const { - return static_cast<const QOpenGL2PaintEngineState *>(QPaintEngineEx::state()); - } - - void beginNativePainting() override; - void endNativePainting() override; - - void invalidateState(); - - void setRenderTextActive(bool); - - bool isNativePaintingActive() const; - bool requiresPretransformedGlyphPositions(QFontEngine *, const QTransform &) const override { return false; } - bool shouldDrawCachedGlyphs(QFontEngine *, const QTransform &) const override; - -private: - Q_DISABLE_COPY_MOVE(QOpenGL2PaintEngineEx) - - friend class QOpenGLEngineShaderManager; -}; - -// This probably needs to grow to GL_MAX_VERTEX_ATTRIBS, but 3 is ok for now as that's -// all the GL2 engine uses: -#define QT_GL_VERTEX_ARRAY_TRACKED_COUNT 3 - -class QOpenGL2PaintEngineExPrivate : public QPaintEngineExPrivate -{ - Q_DECLARE_PUBLIC(QOpenGL2PaintEngineEx) -public: - enum StencilFillMode { - OddEvenFillMode, - WindingFillMode, - TriStripStrokeFillMode - }; - - QOpenGL2PaintEngineExPrivate(QOpenGL2PaintEngineEx *q_ptr) : - q(q_ptr), - shaderManager(nullptr), - width(0), height(0), - ctx(nullptr), - useSystemClip(true), - elementIndicesVBOId(0), - opacityArray(0), - snapToPixelGrid(false), - nativePaintingActive(false), - inverseScale(1), - lastTextureUnitUsed(QT_UNKNOWN_TEXTURE_UNIT), - vertexBuffer(QOpenGLBuffer::VertexBuffer), - texCoordBuffer(QOpenGLBuffer::VertexBuffer), - opacityBuffer(QOpenGLBuffer::VertexBuffer), - indexBuffer(QOpenGLBuffer::IndexBuffer) - { } - - ~QOpenGL2PaintEngineExPrivate(); - - void updateBrushTexture(); - void updateBrushUniforms(); - void updateMatrix(); - void updateCompositionMode(); - - enum TextureUpdateMode { UpdateIfNeeded, ForceUpdate }; - template<typename T> - void updateTexture(GLenum textureUnit, const T &texture, GLenum wrapMode, GLenum filterMode, TextureUpdateMode updateMode = UpdateIfNeeded); - template<typename T> - GLuint bindTexture(const T &texture); - void activateTextureUnit(GLenum textureUnit); - - void resetGLState(); - - // fill, stroke, drawTexture, drawPixmaps & drawCachedGlyphs are the main rendering entry-points, - // however writeClip can also be thought of as en entry point as it does similar things. - void fill(const QVectorPath &path); - void stroke(const QVectorPath &path, const QPen &pen); - void drawTexture(const QOpenGLRect& dest, const QOpenGLRect& src, const QSize &textureSize, bool opaque, bool pattern = false); - void drawPixmapFragments(const QPainter::PixmapFragment *fragments, int fragmentCount, const QPixmap &pixmap, - QPainter::PixmapFragmentHints hints); - void drawCachedGlyphs(QFontEngine::GlyphFormat glyphFormat, QStaticTextItem *staticTextItem); - - // Calls glVertexAttributePointer if the pointer has changed - inline void uploadData(unsigned int arrayIndex, const GLfloat *data, GLuint count); - inline bool uploadIndexData(const void *data, GLenum indexValueType, GLuint count); - - // draws whatever is in the vertex array: - void drawVertexArrays(const float *data, int *stops, int stopCount, GLenum primitive); - void drawVertexArrays(QOpenGL2PEXVertexArray &vertexArray, GLenum primitive) { - drawVertexArrays((const float *) vertexArray.data(), vertexArray.stops(), vertexArray.stopCount(), primitive); - } - - // Composites the bounding rect onto dest buffer: - void composite(const QOpenGLRect& boundingRect); - - // Calls drawVertexArrays to render into stencil buffer: - void fillStencilWithVertexArray(const float *data, int count, int *stops, int stopCount, const QOpenGLRect &bounds, StencilFillMode mode); - void fillStencilWithVertexArray(QOpenGL2PEXVertexArray& vertexArray, bool useWindingFill) { - fillStencilWithVertexArray((const float *) vertexArray.data(), 0, vertexArray.stops(), vertexArray.stopCount(), - vertexArray.boundingRect(), - useWindingFill ? WindingFillMode : OddEvenFillMode); - } - - void setBrush(const QBrush& brush); - void transferMode(EngineMode newMode); - bool prepareForDraw(bool srcPixelsAreOpaque); // returns true if the program has changed - bool prepareForCachedGlyphDraw(const QFontEngineGlyphCache &cache); - inline void useSimpleShader(); - inline GLuint location(const QOpenGLEngineShaderManager::Uniform uniform) { - return shaderManager->getUniformLocation(uniform); - } - - void clearClip(uint value); - void writeClip(const QVectorPath &path, uint value); - void resetClipIfNeeded(); - - void updateClipScissorTest(); - void setScissor(const QRect &rect); - void regenerateClip(); - void systemStateChanged() override; - - void setVertexAttribArrayEnabled(int arrayIndex, bool enabled = true); - void syncGlState(); - - static QOpenGLEngineShaderManager* shaderManagerForEngine(QOpenGL2PaintEngineEx *engine) { return engine->d_func()->shaderManager; } - static QOpenGL2PaintEngineExPrivate *getData(QOpenGL2PaintEngineEx *engine) { return engine->d_func(); } - static void cleanupVectorPath(QPaintEngineEx *engine, void *data); - - QOpenGLExtensions funcs; - - QOpenGL2PaintEngineEx* q; - QOpenGLEngineShaderManager* shaderManager; - QOpenGLPaintDevice* device; - int width, height; - QOpenGLContext *ctx; - EngineMode mode; - QFontEngine::GlyphFormat glyphCacheFormat; - - bool vertexAttributeArraysEnabledState[QT_GL_VERTEX_ARRAY_TRACKED_COUNT]; - - // Dirty flags - bool matrixDirty; // Implies matrix uniforms are also dirty - bool compositionModeDirty; - bool brushTextureDirty; - bool brushUniformsDirty; - bool opacityUniformDirty; - bool matrixUniformDirty; - - bool stencilClean; // Has the stencil not been used for clipping so far? - bool useSystemClip; - QRegion dirtyStencilRegion; - QRect currentScissorBounds; - uint maxClip; - - QBrush currentBrush; // May not be the state's brush! - const QBrush noBrush; - - QImage currentBrushImage; - - QOpenGL2PEXVertexArray vertexCoordinateArray; - QOpenGL2PEXVertexArray textureCoordinateArray; - QVector<GLushort> elementIndices; - GLuint elementIndicesVBOId; - QDataBuffer<GLfloat> opacityArray; - GLfloat staticVertexCoordinateArray[8]; - GLfloat staticTextureCoordinateArray[8]; - - bool snapToPixelGrid; - bool nativePaintingActive; - GLfloat pmvMatrix[3][3]; - GLfloat inverseScale; - - GLenum lastTextureUnitUsed; - GLuint lastTextureUsed; - - QOpenGLVertexArrayObject vao; - QOpenGLBuffer vertexBuffer; - QOpenGLBuffer texCoordBuffer; - QOpenGLBuffer opacityBuffer; - QOpenGLBuffer indexBuffer; - - bool needsSync; - bool multisamplingAlwaysEnabled; - - QTriangulatingStroker stroker; - QDashedStrokeProcessor dasher; - - QVector<GLuint> unusedVBOSToClean; - QVector<GLuint> unusedIBOSToClean; - - const GLfloat *vertexAttribPointers[3]; -}; - - -void QOpenGL2PaintEngineExPrivate::uploadData(unsigned int arrayIndex, const GLfloat *data, GLuint count) -{ - Q_ASSERT(arrayIndex < 3); - - // If a vertex array object is created we have a profile that supports them - // and we will upload the data via a QOpenGLBuffer. Otherwise we will use - // the legacy way of uploading the data via glVertexAttribPointer. - if (vao.isCreated()) { - if (arrayIndex == QT_VERTEX_COORDS_ATTR) { - vertexBuffer.bind(); - vertexBuffer.allocate(data, count * sizeof(float)); - } - if (arrayIndex == QT_TEXTURE_COORDS_ATTR) { - texCoordBuffer.bind(); - texCoordBuffer.allocate(data, count * sizeof(float)); - } - if (arrayIndex == QT_OPACITY_ATTR) { - opacityBuffer.bind(); - opacityBuffer.allocate(data, count * sizeof(float)); - } - if (arrayIndex == QT_OPACITY_ATTR) - funcs.glVertexAttribPointer(arrayIndex, 1, GL_FLOAT, GL_FALSE, 0, nullptr); - else - funcs.glVertexAttribPointer(arrayIndex, 2, GL_FLOAT, GL_FALSE, 0, nullptr); - } else { - // If we already uploaded the data we don't have to do it again - if (data == vertexAttribPointers[arrayIndex]) - return; - - // Store the data in cache and upload it to the graphics card. - vertexAttribPointers[arrayIndex] = data; - if (arrayIndex == QT_OPACITY_ATTR) - funcs.glVertexAttribPointer(arrayIndex, 1, GL_FLOAT, GL_FALSE, 0, data); - else - funcs.glVertexAttribPointer(arrayIndex, 2, GL_FLOAT, GL_FALSE, 0, data); - } -} - -bool QOpenGL2PaintEngineExPrivate::uploadIndexData(const void *data, GLenum indexValueType, GLuint count) -{ - // Follow the uploadData() logic: VBOs are used only when VAO support is available. - // Otherwise the legacy client-side pointer path is used. - if (vao.isCreated()) { - Q_ASSERT(indexValueType == GL_UNSIGNED_SHORT || indexValueType == GL_UNSIGNED_INT); - indexBuffer.bind(); - indexBuffer.allocate(data, count * (indexValueType == GL_UNSIGNED_SHORT ? sizeof(quint16) : sizeof(quint32))); - return true; - } - return false; -} - -QT_END_NAMESPACE - -#endif diff --git a/src/gui/opengl/qopenglpixeltransferoptions.cpp b/src/gui/opengl/qopenglpixeltransferoptions.cpp deleted file mode 100644 index b0d953d76b..0000000000 --- a/src/gui/opengl/qopenglpixeltransferoptions.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB). -** 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 "qopenglpixeltransferoptions.h" -#include <QSharedData> - -QT_BEGIN_NAMESPACE - -/*! - * \class QOpenGLPixelTransferOptions - * - * \brief The QOpenGLPixelTransferOptions class describes the pixel storage - * modes that affect the unpacking of pixels during texture upload. - */ - -/*! - * \fn QOpenGLPixelTransferOptions & QOpenGLPixelTransferOptions::operator=(QOpenGLPixelTransferOptions &&other) - * \internal - */ - -/*! - * \fn void QOpenGLPixelTransferOptions::swap(QOpenGLPixelTransferOptions &other) - * \internal - */ - -class QOpenGLPixelTransferOptionsData : public QSharedData -{ -public: - QOpenGLPixelTransferOptionsData() - : alignment(4) - , skipImages(0) - , skipRows(0) - , skipPixels(0) - , imageHeight(0) - , rowLength(0) - , lsbFirst(false) - , swapBytes(false) - {} - - int alignment; - int skipImages; - int skipRows; - int skipPixels; - int imageHeight; - int rowLength; - bool lsbFirst; - bool swapBytes; -}; - -/*! - * Constructs a new QOpenGLPixelTransferOptions instance with the default settings. - */ -QOpenGLPixelTransferOptions::QOpenGLPixelTransferOptions() - : data(new QOpenGLPixelTransferOptionsData) -{ -} - -/*! - * \internal - */ -QOpenGLPixelTransferOptions::QOpenGLPixelTransferOptions(const QOpenGLPixelTransferOptions &rhs) - : data(rhs.data) -{ -} - -/*! - * \internal - */ -QOpenGLPixelTransferOptions &QOpenGLPixelTransferOptions::operator=(const QOpenGLPixelTransferOptions &rhs) -{ - if (this != &rhs) - data.operator=(rhs.data); - return *this; -} - -/*! - * Destructor. - */ -QOpenGLPixelTransferOptions::~QOpenGLPixelTransferOptions() -{ -} - -/*! - * Sets the \a alignment requirements for each pixel row. Corresponds to \c GL_UNPACK_ALIGNMENT. - * The default value is 4, as specified by OpenGL. - */ -void QOpenGLPixelTransferOptions::setAlignment(int alignment) -{ - data->alignment = alignment; -} - -/*! - * \return the current alignment requirement for each pixel row. - */ -int QOpenGLPixelTransferOptions::alignment() const -{ - return data->alignment; -} - -/*! - * Sets the number of images that are skipped to \a skipImages. - * Corresponds to \c GL_UNPACK_SKIP_IMAGES. Equivalent to incrementing the pointer - * passed to QOpenGLTexture::setData(). The default value is 0. - */ -void QOpenGLPixelTransferOptions::setSkipImages(int skipImages) -{ - data->skipImages = skipImages; -} - -/*! - * \return the number of images that are skipped. - */ -int QOpenGLPixelTransferOptions::skipImages() const -{ - return data->skipImages; -} - -/*! - * Sets the number of rows that are skipped to \a skipRows. - * Corresponds to \c GL_UNPACK_SKIP_ROWS. Equivalent to incrementing the pointer - * passed to QOpenGLTexture::setData(). The default value is 0. - */ -void QOpenGLPixelTransferOptions::setSkipRows(int skipRows) -{ - data->skipRows = skipRows; -} - -/*! - * \return the number of rows that are skipped. - */ -int QOpenGLPixelTransferOptions::skipRows() const -{ - return data->skipRows; -} - -/*! - * Sets the number of pixels that are skipped to \a skipPixels. - * Corresponds to \c GL_UNPACK_SKIP_PIXELS. Equivalent to incrementing the pointer - * passed to QOpenGLTexture::setData(). The default value is 0. - */ -void QOpenGLPixelTransferOptions::setSkipPixels(int skipPixels) -{ - data->skipPixels = skipPixels; -} - -/*! - * \return the number of pixels that are skipped. - */ -int QOpenGLPixelTransferOptions::skipPixels() const -{ - return data->skipPixels; -} - -/*! - * Sets the image height for 3D textures to \a imageHeight. - * Corresponds to \c GL_UNPACK_IMAGE_HEIGHT. - * The default value is 0. - */ -void QOpenGLPixelTransferOptions::setImageHeight(int imageHeight) -{ - data->imageHeight = imageHeight; -} - -/*! - * \return the currently set image height. - */ -int QOpenGLPixelTransferOptions::imageHeight() const -{ - return data->imageHeight; -} - -/*! - * Sets the number of pixels in a row to \a rowLength. - * Corresponds to \c GL_UNPACK_ROW_LENGTH. - * The default value is 0. - */ -void QOpenGLPixelTransferOptions::setRowLength(int rowLength) -{ - data->rowLength = rowLength; -} - -/*! - * \return the currently set row length. - */ -int QOpenGLPixelTransferOptions::rowLength() const -{ - return data->rowLength; -} - -/*! - * \a lsbFirst specifies if bits within a byte are ordered from least to most significat. - * The default value is \c false, meaning that the first bit in each byte is the - * most significant one. This is significant for bitmap data only. - * Corresponds to \c GL_UNPACK_LSB_FIRST. - */ -void QOpenGLPixelTransferOptions::setLeastSignificantByteFirst(bool lsbFirst) -{ - data->lsbFirst = lsbFirst; -} - -/*! - * \return \c true if bits within a byte are ordered from least to most significant. - */ -bool QOpenGLPixelTransferOptions::isLeastSignificantBitFirst() const -{ - return data->lsbFirst; -} - -/*! - * \a swapBytes specifies if the byte ordering for multibyte components is reversed. - * The default value is \c false. - * Corresponds to \c GL_UNPACK_SWAP_BYTES. - */ -void QOpenGLPixelTransferOptions::setSwapBytesEnabled(bool swapBytes) -{ - data->swapBytes = swapBytes; -} - -/*! - * \return \c true if the byte ordering for multibyte components is reversed. - */ -bool QOpenGLPixelTransferOptions::isSwapBytesEnabled() const -{ - return data->swapBytes; -} - -QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglpixeltransferoptions.h b/src/gui/opengl/qopenglpixeltransferoptions.h deleted file mode 100644 index 195543ae90..0000000000 --- a/src/gui/opengl/qopenglpixeltransferoptions.h +++ /dev/null @@ -1,100 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB). -** 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 QOPENGLPIXELUPLOADOPTIONS_H -#define QOPENGLPIXELUPLOADOPTIONS_H - -#include <QtGui/qtguiglobal.h> - -#if !defined(QT_NO_OPENGL) - -#include <QtCore/QSharedDataPointer> - -QT_BEGIN_NAMESPACE - -class QOpenGLPixelTransferOptionsData; - -class Q_GUI_EXPORT QOpenGLPixelTransferOptions -{ -public: - QOpenGLPixelTransferOptions(); - QOpenGLPixelTransferOptions(const QOpenGLPixelTransferOptions &); - QOpenGLPixelTransferOptions &operator=(QOpenGLPixelTransferOptions &&other) noexcept - { swap(other); return *this; } - QOpenGLPixelTransferOptions &operator=(const QOpenGLPixelTransferOptions &); - ~QOpenGLPixelTransferOptions(); - - void swap(QOpenGLPixelTransferOptions &other) noexcept - { data.swap(other.data); } - - void setAlignment(int alignment); - int alignment() const; - - void setSkipImages(int skipImages); - int skipImages() const; - - void setSkipRows(int skipRows); - int skipRows() const; - - void setSkipPixels(int skipPixels); - int skipPixels() const; - - void setImageHeight(int imageHeight); - int imageHeight() const; - - void setRowLength(int rowLength); - int rowLength() const; - - void setLeastSignificantByteFirst(bool lsbFirst); - bool isLeastSignificantBitFirst() const; - - void setSwapBytesEnabled(bool swapBytes); - bool isSwapBytesEnabled() const; - -private: - QSharedDataPointer<QOpenGLPixelTransferOptionsData> data; -}; - -Q_DECLARE_SHARED(QOpenGLPixelTransferOptions) - -QT_END_NAMESPACE - -#endif // QT_NO_OPENGL - -#endif // QOPENGLPIXELUPLOADOPTIONS_H 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 <QDir> #include <QSaveFile> #include <QCoreApplication> -#include <QLoggingCategory> #include <QCryptographicHash> #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 <QtGui/qtguiglobal.h> #include <QtCore/qcache.h> #include <QtCore/qmutex.h> +#include <QtCore/QLoggingCategory> #include <QtGui/private/qopenglcontext_p.h> #include <QtGui/private/qshader_p.h> @@ -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<ShaderDesc> 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/qopenglqueryhelper_p.h b/src/gui/opengl/qopenglqueryhelper_p.h deleted file mode 100644 index ad91ca9f96..0000000000 --- a/src/gui/opengl/qopenglqueryhelper_p.h +++ /dev/null @@ -1,186 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB). -** 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 QOPENGLQUERYHELPER_P_H -#define QOPENGLQUERYHELPER_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtGui/private/qtguiglobal_p.h> - -#if !defined(QT_OPENGL_ES_2) - -#include <QtGui/QOpenGLContext> - -QT_BEGIN_NAMESPACE - -// Helper class used by QOpenGLTimerQuery and later will be used by -// QOpenGLOcclusionQuery -class QOpenGLQueryHelper -{ -public: - QOpenGLQueryHelper(QOpenGLContext *context) - : GetQueryObjectuiv(nullptr), - GetQueryObjectiv(nullptr), - GetQueryiv(nullptr), - EndQuery(nullptr), - BeginQuery(nullptr), - IsQuery(nullptr), - DeleteQueries(nullptr), - GenQueries(nullptr), - GetInteger64v(nullptr), - GetQueryObjectui64v(nullptr), - GetQueryObjecti64v(nullptr), - QueryCounter(nullptr) - { - Q_ASSERT(context); - - // Core in OpenGL >=1.5 - GetQueryObjectuiv = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLuint *)>(context->getProcAddress("glGetQueryObjectuiv")); - GetQueryObjectiv = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLint *)>(context->getProcAddress("glGetQueryObjectiv")); - GetQueryiv = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLenum , GLint *)>(context->getProcAddress("glGetQueryiv")); - EndQuery = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum )>(context->getProcAddress("glEndQuery")); - BeginQuery = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLuint )>(context->getProcAddress("glBeginQuery")); - IsQuery = reinterpret_cast<GLboolean (QOPENGLF_APIENTRYP)(GLuint )>(context->getProcAddress("glIsQuery")); - DeleteQueries = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLsizei , const GLuint *)>(context->getProcAddress("glDeleteQueries")); - GenQueries = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLsizei , GLuint *)>(context->getProcAddress("glGenQueries")); - - // Core in OpenGL >=3.2 - GetInteger64v = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint64 *)>(context->getProcAddress("glGetInteger64v")); - - // Core in OpenGL >=3.3 / ARB_timer_query - GetQueryObjectui64v = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLuint64 *)>(context->getProcAddress("glGetQueryObjectui64v")); - GetQueryObjecti64v = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLint64 *)>(context->getProcAddress("glGetQueryObjecti64v")); - QueryCounter = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum )>(context->getProcAddress("glQueryCounter")); - } - - inline void glGetQueryObjectuiv(GLuint id, GLenum pname, GLuint *params) - { - GetQueryObjectuiv(id, pname, params); - } - - inline void glGetQueryObjectiv(GLuint id, GLenum pname, GLint *params) - { - GetQueryObjectiv(id, pname, params); - } - - inline void glGetQueryiv(GLenum target, GLenum pname, GLint *params) - { - GetQueryiv(target, pname, params); - } - - inline void glEndQuery(GLenum target) - { - EndQuery(target); - } - - inline void glBeginQuery(GLenum target, GLuint id) - { - BeginQuery(target, id); - } - - inline GLboolean glIsQuery(GLuint id) - { - return IsQuery(id); - } - - inline void glDeleteQueries(GLsizei n, const GLuint *ids) - { - DeleteQueries(n, ids); - } - - inline void glGenQueries(GLsizei n, GLuint *ids) - { - GenQueries(n, ids); - } - - inline void glGetInteger64v(GLenum pname, GLint64 *params) - { - GetInteger64v(pname, params); - } - - inline void glGetQueryObjectui64v(GLuint id, GLenum pname, GLuint64 *params) - { - GetQueryObjectui64v(id, pname, params); - } - - inline void glGetQueryObjecti64v(GLuint id, GLenum pname, GLint64 *params) - { - GetQueryObjecti64v(id, pname, params); - } - - inline void glQueryCounter(GLuint id, GLenum target) - { - QueryCounter(id, target); - } - -private: - // Core in OpenGL >=1.5 - void (QOPENGLF_APIENTRYP GetQueryObjectuiv)(GLuint id, GLenum pname, GLuint *params); - void (QOPENGLF_APIENTRYP GetQueryObjectiv)(GLuint id, GLenum pname, GLint *params); - void (QOPENGLF_APIENTRYP GetQueryiv)(GLenum target, GLenum pname, GLint *params); - void (QOPENGLF_APIENTRYP EndQuery)(GLenum target); - void (QOPENGLF_APIENTRYP BeginQuery)(GLenum target, GLuint id); - GLboolean (QOPENGLF_APIENTRYP IsQuery)(GLuint id); - void (QOPENGLF_APIENTRYP DeleteQueries)(GLsizei n, const GLuint *ids); - void (QOPENGLF_APIENTRYP GenQueries)(GLsizei n, GLuint *ids); - - // Core in OpenGL >=3.2 - void (QOPENGLF_APIENTRYP GetInteger64v)(GLenum pname, GLint64 *params); - - // Core in OpenGL >=3.3 and provided by ARB_timer_query - void (QOPENGLF_APIENTRYP GetQueryObjectui64v)(GLuint id, GLenum pname, GLuint64 *params); - void (QOPENGLF_APIENTRYP GetQueryObjecti64v)(GLuint id, GLenum pname, GLint64 *params); - void (QOPENGLF_APIENTRYP QueryCounter)(GLuint id, GLenum target); -}; - -QT_END_NAMESPACE - -#endif - -#endif // QOPENGLQUERYHELPER_P_H diff --git a/src/gui/opengl/qopenglshadercache_p.h b/src/gui/opengl/qopenglshadercache_p.h deleted file mode 100644 index 0f730602b0..0000000000 --- a/src/gui/opengl/qopenglshadercache_p.h +++ /dev/null @@ -1,86 +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$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#ifndef QOPENGLSHADERCACHE_P_H -#define QOPENGLSHADERCACHE_P_H - -#include <QtGui/private/qtguiglobal_p.h> - -QT_BEGIN_NAMESPACE - - -class QOpenGLShaderProgram; -class QOpenGLContext; - -class CachedShader -{ -public: - inline CachedShader(const QByteArray &, const QByteArray &) - {} - - inline bool isCached() - { - return false; - } - - inline bool load(QOpenGLShaderProgram *, QOpenGLContext *) - { - return false; - } - - inline bool store(QOpenGLShaderProgram *, QOpenGLContext *) - { - return false; - } -}; - -QT_END_NAMESPACE - -#endif 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 <QtCore/private/qobject_p.h> -#include <QtCore/qdebug.h> -#include <QtCore/qfile.h> -#include <QtCore/qvarlengtharray.h> -#include <QtCore/qvector.h> -#include <QtCore/qloggingcategory.h> -#include <QtGui/qtransform.h> -#include <QtGui/QColor> -#include <QtGui/QSurfaceFormat> - -#if !defined(QT_OPENGL_ES_2) -#include <QtGui/qopenglfunctions_4_0_core.h> -#endif - -#include <algorithm> - -QT_BEGIN_NAMESPACE - -/*! - \class QOpenGLShaderProgram - \brief The QOpenGLShaderProgram class allows OpenGL shader programs to be linked and used. - \since 5.0 - \ingroup painting-3D - \inmodule QtGui - - \section1 Introduction - - This class supports shader programs written in the OpenGL Shading - Language (GLSL) and in the OpenGL/ES Shading Language (GLSL/ES). - - QOpenGLShader and QOpenGLShaderProgram shelter the programmer from the details of - compiling and linking vertex and fragment shaders. - - The following example creates a vertex shader program using the - supplied source \c{code}. Once compiled and linked, the shader - program is activated in the current QOpenGLContext by calling - QOpenGLShaderProgram::bind(): - - \snippet code/src_gui_qopenglshaderprogram.cpp 0 - - \section1 Writing Portable Shaders - - Shader programs can be difficult to reuse across OpenGL implementations - because of varying levels of support for standard vertex attributes and - uniform variables. In particular, GLSL/ES lacks all of the - standard variables that are present on desktop OpenGL systems: - \c{gl_Vertex}, \c{gl_Normal}, \c{gl_Color}, and so on. Desktop OpenGL - lacks the variable qualifiers \c{highp}, \c{mediump}, and \c{lowp}. - - The QOpenGLShaderProgram class makes the process of writing portable shaders - easier by prefixing all shader programs with the following lines on - desktop OpenGL: - - \code - #define highp - #define mediump - #define lowp - \endcode - - This makes it possible to run most GLSL/ES shader programs - on desktop systems. The programmer should restrict themselves - to just features that are present in GLSL/ES, and avoid - standard variable names that only work on the desktop. - - \section1 Simple Shader Example - - \snippet code/src_gui_qopenglshaderprogram.cpp 1 - - With the above shader program active, we can draw a green triangle - as follows: - - \snippet code/src_gui_qopenglshaderprogram.cpp 2 - - \section1 Binary Shaders and Programs - - Binary shaders may be specified using \c{glShaderBinary()} on - the return value from QOpenGLShader::shaderId(). The QOpenGLShader instance - containing the binary can then be added to the shader program with - addShader() and linked in the usual fashion with link(). - - Binary programs may be specified using \c{glProgramBinaryOES()} - on the return value from programId(). Then the application should - call link(), which will notice that the program has already been - specified and linked, allowing other operations to be performed - on the shader program. The shader program's id can be explicitly - created using the create() function. - - \section2 Caching Program Binaries - - As of Qt 5.9, support for caching program binaries on disk is built in. To - enable this, switch to using addCacheableShaderFromSourceCode() and - addCacheableShaderFromSourceFile(). With an OpenGL ES 3.x context or support - for \c{GL_ARB_get_program_binary}, this will transparently cache program - binaries under QStandardPaths::GenericCacheLocation or - QStandardPaths::CacheLocation. When support is not available, calling the - cacheable function variants is equivalent to the normal ones. - - \note Some drivers do not have any binary formats available, even though - they advertise the extension or offer OpenGL ES 3.0. In this case program - binary support will be disabled. - - \sa QOpenGLShader -*/ - -/*! - \class QOpenGLShader - \brief The QOpenGLShader class allows OpenGL shaders to be compiled. - \since 5.0 - \ingroup painting-3D - \inmodule QtGui - - This class supports shaders written in the OpenGL Shading Language (GLSL) - and in the OpenGL/ES Shading Language (GLSL/ES). - - QOpenGLShader and QOpenGLShaderProgram shelter the programmer from the details of - compiling and linking vertex and fragment shaders. - - \sa QOpenGLShaderProgram -*/ - -/*! - \enum QOpenGLShader::ShaderTypeBit - This enum specifies the type of QOpenGLShader that is being created. - - \value Vertex Vertex shader written in the OpenGL Shading Language (GLSL). - \value Fragment Fragment shader written in the OpenGL Shading Language (GLSL). - \value Geometry Geometry shaders written in the OpenGL Shading Language (GLSL) - (requires OpenGL >= 3.2 or OpenGL ES >= 3.2). - \value TessellationControl Tessellation control shaders written in the OpenGL - shading language (GLSL) (requires OpenGL >= 4.0 or OpenGL ES >= 3.2). - \value TessellationEvaluation Tessellation evaluation shaders written in the OpenGL - shading language (GLSL) (requires OpenGL >= 4.0 or OpenGL ES >= 3.2). - \value Compute Compute shaders written in the OpenGL shading language (GLSL) - (requires OpenGL >= 4.3 or OpenGL ES >= 3.1). -*/ - -Q_DECLARE_LOGGING_CATEGORY(lcOpenGLProgramDiskCache) - -// For GLES 3.1/3.2 -#ifndef GL_GEOMETRY_SHADER -#define GL_GEOMETRY_SHADER 0x8DD9 -#endif -#ifndef GL_TESS_CONTROL_SHADER -#define GL_TESS_CONTROL_SHADER 0x8E88 -#endif -#ifndef GL_TESS_EVALUATION_SHADER -#define GL_TESS_EVALUATION_SHADER 0x8E87 -#endif -#ifndef GL_COMPUTE_SHADER -#define GL_COMPUTE_SHADER 0x91B9 -#endif -#ifndef GL_MAX_GEOMETRY_OUTPUT_VERTICES -#define GL_MAX_GEOMETRY_OUTPUT_VERTICES 0x8DE0 -#endif -#ifndef GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS -#define GL_MAX_GEOMETRY_TOTAL_OUTPUT_COMPONENTS 0x8DE1 -#endif -#ifndef GL_PATCH_VERTICES -#define GL_PATCH_VERTICES 0x8E72 -#endif -#ifndef GL_PATCH_DEFAULT_OUTER_LEVEL -#define GL_PATCH_DEFAULT_OUTER_LEVEL 0x8E74 -#endif -#ifndef GL_PATCH_DEFAULT_INNER_LEVEL -#define GL_PATCH_DEFAULT_INNER_LEVEL 0x8E73 -#endif - -#ifndef QT_OPENGL_ES_2 -static inline bool isFormatGLES(const QSurfaceFormat &f) -{ - return (f.renderableType() == QSurfaceFormat::OpenGLES); -} -#endif - -static inline bool supportsGeometry(const QSurfaceFormat &f) -{ - return f.version() >= qMakePair(3, 2); -} - -static inline bool supportsCompute(const QSurfaceFormat &f) -{ -#ifndef QT_OPENGL_ES_2 - if (!isFormatGLES(f)) - return f.version() >= qMakePair(4, 3); - else - return f.version() >= qMakePair(3, 1); -#else - return f.version() >= qMakePair(3, 1); -#endif -} - -static inline bool supportsTessellation(const QSurfaceFormat &f) -{ -#ifndef QT_OPENGL_ES_2 - if (!isFormatGLES(f)) - return f.version() >= qMakePair(4, 0); - else - return f.version() >= qMakePair(3, 2); -#else - return f.version() >= qMakePair(3, 2); -#endif -} - -class QOpenGLShaderPrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QOpenGLShader) -public: - QOpenGLShaderPrivate(QOpenGLContext *ctx, QOpenGLShader::ShaderType type) - : shaderGuard(nullptr) - , shaderType(type) - , compiled(false) - , glfuncs(new QOpenGLExtraFunctions(ctx)) - , supportsGeometryShaders(false) - , supportsTessellationShaders(false) - , supportsComputeShaders(false) - { - if (shaderType & QOpenGLShader::Geometry) - supportsGeometryShaders = supportsGeometry(ctx->format()); - else if (shaderType & (QOpenGLShader::TessellationControl | QOpenGLShader::TessellationEvaluation)) - supportsTessellationShaders = supportsTessellation(ctx->format()); - else if (shaderType & QOpenGLShader::Compute) - supportsComputeShaders = supportsCompute(ctx->format()); - } - ~QOpenGLShaderPrivate(); - - QOpenGLSharedResourceGuard *shaderGuard; - QOpenGLShader::ShaderType shaderType; - bool compiled; - QString log; - - QOpenGLExtraFunctions *glfuncs; - - // Support for geometry shaders - bool supportsGeometryShaders; - // Support for tessellation shaders - bool supportsTessellationShaders; - // Support for compute shaders - bool supportsComputeShaders; - - - bool create(); - bool compile(QOpenGLShader *q); - void deleteShader(); -}; - -namespace { - void freeShaderFunc(QOpenGLFunctions *funcs, GLuint id) - { - funcs->glDeleteShader(id); - } -} - -QOpenGLShaderPrivate::~QOpenGLShaderPrivate() -{ - delete glfuncs; - if (shaderGuard) - shaderGuard->free(); -} - -bool QOpenGLShaderPrivate::create() -{ - QOpenGLContext *context = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext()); - if (!context) - return false; - GLuint shader = 0; - if (shaderType == QOpenGLShader::Vertex) { - shader = glfuncs->glCreateShader(GL_VERTEX_SHADER); - } else if (shaderType == QOpenGLShader::Geometry && supportsGeometryShaders) { - shader = glfuncs->glCreateShader(GL_GEOMETRY_SHADER); - } else if (shaderType == QOpenGLShader::TessellationControl && supportsTessellationShaders) { - shader = glfuncs->glCreateShader(GL_TESS_CONTROL_SHADER); - } else if (shaderType == QOpenGLShader::TessellationEvaluation && supportsTessellationShaders) { - shader = glfuncs->glCreateShader(GL_TESS_EVALUATION_SHADER); - } else if (shaderType == QOpenGLShader::Compute && supportsComputeShaders) { - shader = glfuncs->glCreateShader(GL_COMPUTE_SHADER); - } else if (shaderType == QOpenGLShader::Fragment) { - shader = glfuncs->glCreateShader(GL_FRAGMENT_SHADER); - } - if (!shader) { - qWarning("QOpenGLShader: could not create shader"); - return false; - } - shaderGuard = new QOpenGLSharedResourceGuard(context, shader, freeShaderFunc); - return true; -} - -bool QOpenGLShaderPrivate::compile(QOpenGLShader *q) -{ - GLuint shader = shaderGuard ? shaderGuard->id() : 0; - if (!shader) - return false; - - // Try to compile shader - glfuncs->glCompileShader(shader); - GLint value = 0; - - // Get compilation status - glfuncs->glGetShaderiv(shader, GL_COMPILE_STATUS, &value); - compiled = (value != 0); - - if (!compiled) { - // Compilation failed, try to provide some information about the failure - QString name = q->objectName(); - - const char *types[] = { - "Fragment", - "Vertex", - "Geometry", - "Tessellation Control", - "Tessellation Evaluation", - "Compute", - "" - }; - - const char *type = types[6]; - switch (shaderType) { - case QOpenGLShader::Fragment: - type = types[0]; break; - case QOpenGLShader::Vertex: - type = types[1]; break; - case QOpenGLShader::Geometry: - type = types[2]; break; - case QOpenGLShader::TessellationControl: - type = types[3]; break; - case QOpenGLShader::TessellationEvaluation: - type = types[4]; break; - case QOpenGLShader::Compute: - type = types[5]; break; - } - - // Get info and source code lengths - GLint infoLogLength = 0; - GLint sourceCodeLength = 0; - char *logBuffer = nullptr; - char *sourceCodeBuffer = nullptr; - - // Get the compilation info log - glfuncs->glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength); - - if (infoLogLength > 1) { - GLint temp; - logBuffer = new char [infoLogLength]; - glfuncs->glGetShaderInfoLog(shader, infoLogLength, &temp, logBuffer); - } - - // Get the source code - glfuncs->glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &sourceCodeLength); - - if (sourceCodeLength > 1) { - GLint temp; - sourceCodeBuffer = new char [sourceCodeLength]; - glfuncs->glGetShaderSource(shader, sourceCodeLength, &temp, sourceCodeBuffer); - } - - if (logBuffer) - log = QString::fromLatin1(logBuffer); - else - log = QLatin1String("failed"); - - if (name.isEmpty()) - qWarning("QOpenGLShader::compile(%s): %s", type, qPrintable(log)); - else - qWarning("QOpenGLShader::compile(%s)[%s]: %s", type, qPrintable(name), qPrintable(log)); - - // Dump the source code if we got it - if (sourceCodeBuffer) { - qWarning("*** Problematic %s shader source code ***\n" - "%ls\n" - "***", - type, qUtf16Printable(QString::fromLatin1(sourceCodeBuffer))); - } - - // Cleanup - delete [] logBuffer; - delete [] sourceCodeBuffer; - } - - return compiled; -} - -void QOpenGLShaderPrivate::deleteShader() -{ - if (shaderGuard) { - shaderGuard->free(); - shaderGuard = nullptr; - } -} - -/*! - Constructs a new QOpenGLShader object of the specified \a type - and attaches it to \a parent. If shader programs are not supported, - QOpenGLShaderProgram::hasOpenGLShaderPrograms() will return false. - - This constructor is normally followed by a call to compileSourceCode() - or compileSourceFile(). - - The shader will be associated with the current QOpenGLContext. - - \sa compileSourceCode(), compileSourceFile() -*/ -QOpenGLShader::QOpenGLShader(QOpenGLShader::ShaderType type, QObject *parent) - : QObject(*new QOpenGLShaderPrivate(QOpenGLContext::currentContext(), type), parent) -{ - Q_D(QOpenGLShader); - d->create(); -} - -/*! - Deletes this shader. If the shader has been attached to a - QOpenGLShaderProgram object, then the actual shader will stay around - until the QOpenGLShaderProgram is destroyed. -*/ -QOpenGLShader::~QOpenGLShader() -{ -} - -/*! - Returns the type of this shader. -*/ -QOpenGLShader::ShaderType QOpenGLShader::shaderType() const -{ - Q_D(const QOpenGLShader); - return d->shaderType; -} - -static const char qualifierDefines[] = - "#define lowp\n" - "#define mediump\n" - "#define highp\n"; - -#if defined(QT_OPENGL_ES) && !defined(QT_OPENGL_FORCE_SHADER_DEFINES) -// The "highp" qualifier doesn't exist in fragment shaders -// on all ES platforms. When it doesn't exist, use "mediump". -#define QOpenGL_REDEFINE_HIGHP 1 -static const char redefineHighp[] = - "#ifndef GL_FRAGMENT_PRECISION_HIGH\n" - "#define highp mediump\n" - "#endif\n"; -#endif - -// Boiler-plate header to have the layout attributes available we need later -static const char blendEquationAdvancedHeader[] = - "#ifdef GL_KHR_blend_equation_advanced\n" - "#extension GL_ARB_fragment_coord_conventions : enable\n" - "#extension GL_KHR_blend_equation_advanced : enable\n" - "#endif\n"; - -struct QVersionDirectivePosition -{ - Q_DECL_CONSTEXPR QVersionDirectivePosition(int position = 0, int line = -1) - : position(position) - , line(line) - { - } - - Q_DECL_CONSTEXPR bool hasPosition() const - { - return position > 0; - } - - const int position; - const int line; -}; - -static QVersionDirectivePosition findVersionDirectivePosition(const char *source) -{ - Q_ASSERT(source); - - // According to the GLSL spec the #version directive must not be - // preceded by anything but whitespace and comments. - // In order to not get confused by #version directives within a - // multiline comment, we need to do some minimal comment parsing - // while searching for the directive. - enum { - Normal, - StartOfLine, - PreprocessorDirective, - CommentStarting, - MultiLineComment, - SingleLineComment, - CommentEnding - } state = StartOfLine; - - const char *c = source; - while (*c) { - switch (state) { - case PreprocessorDirective: - if (*c == ' ' || *c == '\t') - break; - if (!strncmp(c, "version", strlen("version"))) { - // Found version directive - c += strlen("version"); - while (*c && *c != '\n') - ++c; - int splitPosition = c - source + 1; - int linePosition = int(std::count(source, c, '\n')) + 1; - return QVersionDirectivePosition(splitPosition, linePosition); - } else if (*c == '/') - state = CommentStarting; - else if (*c == '\n') - state = StartOfLine; - else - state = Normal; - break; - case StartOfLine: - if (*c == ' ' || *c == '\t') - break; - else if (*c == '#') { - state = PreprocessorDirective; - break; - } - state = Normal; - Q_FALLTHROUGH(); - case Normal: - if (*c == '/') - state = CommentStarting; - else if (*c == '\n') - state = StartOfLine; - break; - case CommentStarting: - if (*c == '*') - state = MultiLineComment; - else if (*c == '/') - state = SingleLineComment; - else - state = Normal; - break; - case MultiLineComment: - if (*c == '*') - state = CommentEnding; - break; - case SingleLineComment: - if (*c == '\n') - state = Normal; - break; - case CommentEnding: - if (*c == '/') - state = Normal; - else if (*c != QLatin1Char('*')) - state = MultiLineComment; - break; - } - ++c; - } - - return QVersionDirectivePosition(0, 1); -} - -/*! - Sets the \a source code for this shader and compiles it. - Returns \c true if the source was successfully compiled, false otherwise. - - \sa compileSourceFile() -*/ -bool QOpenGLShader::compileSourceCode(const char *source) -{ - Q_D(QOpenGLShader); - // This method breaks the shader code into two parts: - // 1. Up to and including an optional #version directive. - // 2. The rest. - // If a #version directive exists, qualifierDefines and redefineHighp - // are inserted after. Otherwise they are inserted right at the start. - // In both cases a #line directive is appended in order to compensate - // for line number changes in case of compiler errors. - - if (d->shaderGuard && d->shaderGuard->id() && source) { - const QVersionDirectivePosition versionDirectivePosition = findVersionDirectivePosition(source); - - QVarLengthArray<const char *, 5> sourceChunks; - QVarLengthArray<GLint, 5> sourceChunkLengths; - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - - if (versionDirectivePosition.hasPosition()) { - // Append source up to and including the #version directive - sourceChunks.append(source); - sourceChunkLengths.append(GLint(versionDirectivePosition.position)); - } else { - // QTBUG-55733: Intel on Windows with Compatibility profile requires a #version always - if (ctx->format().profile() == QSurfaceFormat::CompatibilityProfile) { - const char *vendor = reinterpret_cast<const char *>(ctx->functions()->glGetString(GL_VENDOR)); - if (vendor && !strcmp(vendor, "Intel")) { - static const char version110[] = "#version 110\n"; - sourceChunks.append(version110); - sourceChunkLengths.append(GLint(sizeof(version110)) - 1); - } - } - } - if (d->shaderType == Fragment) { - sourceChunks.append(blendEquationAdvancedHeader); - sourceChunkLengths.append(GLint(sizeof(blendEquationAdvancedHeader) - 1)); - } - - // The precision qualifiers are useful on OpenGL/ES systems, - // but usually not present on desktop systems. - const QSurfaceFormat currentSurfaceFormat = ctx->format(); - QOpenGLContextPrivate *ctx_d = QOpenGLContextPrivate::get(QOpenGLContext::currentContext()); - if (currentSurfaceFormat.renderableType() == QSurfaceFormat::OpenGL - || ctx_d->workaround_missingPrecisionQualifiers -#ifdef QT_OPENGL_FORCE_SHADER_DEFINES - || true -#endif - ) { - sourceChunks.append(qualifierDefines); - sourceChunkLengths.append(GLint(sizeof(qualifierDefines) - 1)); - } - -#ifdef QOpenGL_REDEFINE_HIGHP - if (d->shaderType == Fragment && !ctx_d->workaround_missingPrecisionQualifiers - && QOpenGLContext::currentContext()->isOpenGLES()) { - sourceChunks.append(redefineHighp); - sourceChunkLengths.append(GLint(sizeof(redefineHighp) - 1)); - } -#endif - - QByteArray lineDirective; - // #line is rejected by some drivers: - // "2.1 Mesa 8.1-devel (git-48a3d4e)" or "MESA 2.1 Mesa 8.1-devel" - const char *version = reinterpret_cast<const char *>(ctx->functions()->glGetString(GL_VERSION)); - if (!version || !strstr(version, "2.1 Mesa 8")) { - // Append #line directive in order to compensate for text insertion - lineDirective = QStringLiteral("#line %1\n").arg(versionDirectivePosition.line).toUtf8(); - sourceChunks.append(lineDirective.constData()); - sourceChunkLengths.append(GLint(lineDirective.length())); - } - - // Append rest of shader code - sourceChunks.append(source + versionDirectivePosition.position); - sourceChunkLengths.append(GLint(qstrlen(source + versionDirectivePosition.position))); - - d->glfuncs->glShaderSource(d->shaderGuard->id(), sourceChunks.size(), sourceChunks.data(), sourceChunkLengths.data()); - return d->compile(this); - } else { - return false; - } -} - -/*! - \overload - - Sets the \a source code for this shader and compiles it. - Returns \c true if the source was successfully compiled, false otherwise. - - \sa compileSourceFile() -*/ -bool QOpenGLShader::compileSourceCode(const QByteArray& source) -{ - return compileSourceCode(source.constData()); -} - -/*! - \overload - - Sets the \a source code for this shader and compiles it. - Returns \c true if the source was successfully compiled, false otherwise. - - \sa compileSourceFile() -*/ -bool QOpenGLShader::compileSourceCode(const QString& source) -{ - return compileSourceCode(source.toLatin1().constData()); -} - -/*! - Sets the source code for this shader to the contents of \a fileName - and compiles it. Returns \c true if the file could be opened and the - source compiled, false otherwise. - - \sa compileSourceCode() -*/ -bool QOpenGLShader::compileSourceFile(const QString& fileName) -{ - QFile file(fileName); - if (!file.open(QFile::ReadOnly)) { - qWarning() << "QOpenGLShader: Unable to open file" << fileName; - return false; - } - - QByteArray contents = file.readAll(); - return compileSourceCode(contents.constData()); -} - -/*! - Returns the source code for this shader. - - \sa compileSourceCode() -*/ -QByteArray QOpenGLShader::sourceCode() const -{ - Q_D(const QOpenGLShader); - GLuint shader = d->shaderGuard ? d->shaderGuard->id() : 0; - if (!shader) - return QByteArray(); - GLint size = 0; - d->glfuncs->glGetShaderiv(shader, GL_SHADER_SOURCE_LENGTH, &size); - if (size <= 0) - return QByteArray(); - GLint len = 0; - char *source = new char [size]; - d->glfuncs->glGetShaderSource(shader, size, &len, source); - QByteArray src(source); - delete [] source; - return src; -} - -/*! - Returns \c true if this shader has been compiled; false otherwise. - - \sa compileSourceCode(), compileSourceFile() -*/ -bool QOpenGLShader::isCompiled() const -{ - Q_D(const QOpenGLShader); - return d->compiled; -} - -/*! - Returns the errors and warnings that occurred during the last compile. - - \sa compileSourceCode(), compileSourceFile() -*/ -QString QOpenGLShader::log() const -{ - Q_D(const QOpenGLShader); - return d->log; -} - -/*! - Returns the OpenGL identifier associated with this shader. - - \sa QOpenGLShaderProgram::programId() -*/ -GLuint QOpenGLShader::shaderId() const -{ - Q_D(const QOpenGLShader); - return d->shaderGuard ? d->shaderGuard->id() : 0; -} - -class QOpenGLShaderProgramPrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QOpenGLShaderProgram) -public: - QOpenGLShaderProgramPrivate() - : programGuard(nullptr) - , linked(false) - , inited(false) - , removingShaders(false) - , glfuncs(new QOpenGLExtraFunctions) -#ifndef QT_OPENGL_ES_2 - , tessellationFuncs(nullptr) -#endif - , linkBinaryRecursion(false) - { - } - ~QOpenGLShaderProgramPrivate(); - - QOpenGLSharedResourceGuard *programGuard; - bool linked; - bool inited; - bool removingShaders; - - QString log; - QList<QOpenGLShader *> shaders; - QList<QOpenGLShader *> anonShaders; - - QOpenGLExtraFunctions *glfuncs; -#ifndef QT_OPENGL_ES_2 - // for tessellation features not in GLES 3.2 - QOpenGLFunctions_4_0_Core *tessellationFuncs; -#endif - - bool hasShader(QOpenGLShader::ShaderType type) const; - - QOpenGLProgramBinaryCache::ProgramDesc binaryProgram; - bool isCacheDisabled() const; - bool compileCacheable(); - bool linkBinary(); - - bool linkBinaryRecursion; -}; - -namespace { - void freeProgramFunc(QOpenGLFunctions *funcs, GLuint id) - { - funcs->glDeleteProgram(id); - } -} - - -QOpenGLShaderProgramPrivate::~QOpenGLShaderProgramPrivate() -{ - delete glfuncs; - if (programGuard) - programGuard->free(); -} - -bool QOpenGLShaderProgramPrivate::hasShader(QOpenGLShader::ShaderType type) const -{ - for (QOpenGLShader *shader : shaders) { - if (shader->shaderType() == type) - return true; - } - return false; -} - -/*! - Constructs a new shader program and attaches it to \a parent. - The program will be invalid until addShader() is called. - - The shader program will be associated with the current QOpenGLContext. - - \sa addShader() -*/ -QOpenGLShaderProgram::QOpenGLShaderProgram(QObject *parent) - : QObject(*new QOpenGLShaderProgramPrivate, parent) -{ -} - -/*! - Deletes this shader program. -*/ -QOpenGLShaderProgram::~QOpenGLShaderProgram() -{ -} - -/*! - Requests the shader program's id to be created immediately. Returns \c true - if successful; \c false otherwise. - - This function is primarily useful when combining QOpenGLShaderProgram - with other OpenGL functions that operate directly on the shader - program id, like \c {GL_OES_get_program_binary}. - - When the shader program is used normally, the shader program's id will - be created on demand. - - \sa programId() - - \since 5.3 - */ -bool QOpenGLShaderProgram::create() -{ - return init(); -} - -bool QOpenGLShaderProgram::init() -{ - Q_D(QOpenGLShaderProgram); - if ((d->programGuard && d->programGuard->id()) || d->inited) - return true; - d->inited = true; - QOpenGLContext *context = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext()); - if (!context) - return false; - d->glfuncs->initializeOpenGLFunctions(); - -#ifndef QT_OPENGL_ES_2 - if (!context->isOpenGLES() && context->format().version() >= qMakePair(4, 0)) { - d->tessellationFuncs = context->versionFunctions<QOpenGLFunctions_4_0_Core>(); - d->tessellationFuncs->initializeOpenGLFunctions(); - } -#endif - - GLuint program = d->glfuncs->glCreateProgram(); - if (!program) { - qWarning("QOpenGLShaderProgram: could not create shader program"); - return false; - } - if (d->programGuard) - delete d->programGuard; - d->programGuard = new QOpenGLSharedResourceGuard(context, program, freeProgramFunc); - return true; -} - -/*! - Adds a compiled \a shader to this shader program. Returns \c true - if the shader could be added, or false otherwise. - - Ownership of the \a shader object remains with the caller. - It will not be deleted when this QOpenGLShaderProgram instance - is deleted. This allows the caller to add the same shader - to multiple shader programs. - - \sa addShaderFromSourceCode(), addShaderFromSourceFile() - \sa removeShader(), link(), removeAllShaders() -*/ -bool QOpenGLShaderProgram::addShader(QOpenGLShader *shader) -{ - Q_D(QOpenGLShaderProgram); - if (!init()) - return false; - if (d->shaders.contains(shader)) - return true; // Already added to this shader program. - if (d->programGuard && d->programGuard->id() && shader) { - if (!shader->d_func()->shaderGuard || !shader->d_func()->shaderGuard->id()) - return false; - if (d->programGuard->group() != shader->d_func()->shaderGuard->group()) { - qWarning("QOpenGLShaderProgram::addShader: Program and shader are not associated with same context."); - return false; - } - d->glfuncs->glAttachShader(d->programGuard->id(), shader->d_func()->shaderGuard->id()); - d->linked = false; // Program needs to be relinked. - d->shaders.append(shader); - connect(shader, SIGNAL(destroyed()), this, SLOT(shaderDestroyed())); - return true; - } else { - return false; - } -} - -/*! - Compiles \a source as a shader of the specified \a type and - adds it to this shader program. Returns \c true if compilation - was successful, false otherwise. The compilation errors - and warnings will be made available via log(). - - This function is intended to be a short-cut for quickly - adding vertex and fragment shaders to a shader program without - creating an instance of QOpenGLShader first. - - \sa addShader(), addShaderFromSourceFile() - \sa removeShader(), link(), log(), removeAllShaders() -*/ -bool QOpenGLShaderProgram::addShaderFromSourceCode(QOpenGLShader::ShaderType type, const char *source) -{ - Q_D(QOpenGLShaderProgram); - if (!init()) - return false; - QOpenGLShader *shader = new QOpenGLShader(type, this); - if (!shader->compileSourceCode(source)) { - d->log = shader->log(); - delete shader; - return false; - } - d->anonShaders.append(shader); - return addShader(shader); -} - -/*! - \overload - - Compiles \a source as a shader of the specified \a type and - adds it to this shader program. Returns \c true if compilation - was successful, false otherwise. The compilation errors - and warnings will be made available via log(). - - This function is intended to be a short-cut for quickly - adding vertex and fragment shaders to a shader program without - creating an instance of QOpenGLShader first. - - \sa addShader(), addShaderFromSourceFile() - \sa removeShader(), link(), log(), removeAllShaders() -*/ -bool QOpenGLShaderProgram::addShaderFromSourceCode(QOpenGLShader::ShaderType type, const QByteArray& source) -{ - return addShaderFromSourceCode(type, source.constData()); -} - -/*! - \overload - - Compiles \a source as a shader of the specified \a type and - adds it to this shader program. Returns \c true if compilation - was successful, false otherwise. The compilation errors - and warnings will be made available via log(). - - This function is intended to be a short-cut for quickly - adding vertex and fragment shaders to a shader program without - creating an instance of QOpenGLShader first. - - \sa addShader(), addShaderFromSourceFile() - \sa removeShader(), link(), log(), removeAllShaders() -*/ -bool QOpenGLShaderProgram::addShaderFromSourceCode(QOpenGLShader::ShaderType type, const QString& source) -{ - return addShaderFromSourceCode(type, source.toLatin1().constData()); -} - -/*! - Compiles the contents of \a fileName as a shader of the specified - \a type and adds it to this shader program. Returns \c true if - compilation was successful, false otherwise. The compilation errors - and warnings will be made available via log(). - - This function is intended to be a short-cut for quickly - adding vertex and fragment shaders to a shader program without - creating an instance of QOpenGLShader first. - - \sa addShader(), addShaderFromSourceCode() -*/ -bool QOpenGLShaderProgram::addShaderFromSourceFile - (QOpenGLShader::ShaderType type, const QString& fileName) -{ - Q_D(QOpenGLShaderProgram); - if (!init()) - return false; - QOpenGLShader *shader = new QOpenGLShader(type, this); - if (!shader->compileSourceFile(fileName)) { - d->log = shader->log(); - delete shader; - return false; - } - d->anonShaders.append(shader); - return addShader(shader); -} - -/*! - Registers the shader of the specified \a type and \a source to this - program. Unlike addShaderFromSourceCode(), this function does not perform - compilation. Compilation is deferred to link(), and may not happen at all, - because link() may potentially use a program binary from Qt's shader disk - cache. This will typically lead to a significant increase in performance. - - \return true if the shader has been registered or, in the non-cached case, - compiled successfully; false if there was an error. The compilation error - messages can be retrieved via log(). - - When the disk cache is disabled, via Qt::AA_DisableShaderDiskCache for - example, or the OpenGL context has no support for context binaries, calling - this function is equivalent to addShaderFromSourceCode(). - - \since 5.9 - \sa addShaderFromSourceCode(), addCacheableShaderFromSourceFile() - */ -bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const char *source) -{ - Q_D(QOpenGLShaderProgram); - if (!init()) - return false; - if (d->isCacheDisabled()) - return addShaderFromSourceCode(type, source); - - return addCacheableShaderFromSourceCode(type, QByteArray(source)); -} - -static inline QShader::Stage qt_shaderTypeToStage(QOpenGLShader::ShaderType type) -{ - switch (type) { - case QOpenGLShader::Vertex: - return QShader::VertexStage; - case QOpenGLShader::Fragment: - return QShader::FragmentStage; - case QOpenGLShader::Geometry: - return QShader::GeometryStage; - case QOpenGLShader::TessellationControl: - return QShader::TessellationControlStage; - case QOpenGLShader::TessellationEvaluation: - return QShader::TessellationEvaluationStage; - case QOpenGLShader::Compute: - return QShader::ComputeStage; - } - return QShader::VertexStage; -} - -static inline QOpenGLShader::ShaderType qt_shaderStageToType(QShader::Stage stage) -{ - switch (stage) { - case QShader::VertexStage: - return QOpenGLShader::Vertex; - case QShader::TessellationControlStage: - return QOpenGLShader::TessellationControl; - case QShader::TessellationEvaluationStage: - return QOpenGLShader::TessellationEvaluation; - case QShader::GeometryStage: - return QOpenGLShader::Geometry; - case QShader::FragmentStage: - return QOpenGLShader::Fragment; - case QShader::ComputeStage: - return QOpenGLShader::Compute; - } - return QOpenGLShader::Vertex; -} - -/*! - \overload - - Registers the shader of the specified \a type and \a source to this - program. Unlike addShaderFromSourceCode(), this function does not perform - compilation. Compilation is deferred to link(), and may not happen at all, - because link() may potentially use a program binary from Qt's shader disk - cache. This will typically lead to a significant increase in performance. - - \return true if the shader has been registered or, in the non-cached case, - compiled successfully; false if there was an error. The compilation error - messages can be retrieved via log(). - - When the disk cache is disabled, via Qt::AA_DisableShaderDiskCache for - example, or the OpenGL context has no support for context binaries, calling - this function is equivalent to addShaderFromSourceCode(). - - \since 5.9 - \sa addShaderFromSourceCode(), addCacheableShaderFromSourceFile() - */ -bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const QByteArray &source) -{ - Q_D(QOpenGLShaderProgram); - if (!init()) - return false; - if (d->isCacheDisabled()) - return addShaderFromSourceCode(type, source); - - d->binaryProgram.shaders.append(QOpenGLProgramBinaryCache::ShaderDesc(qt_shaderTypeToStage(type), source)); - return true; -} - -/*! - \overload - - Registers the shader of the specified \a type and \a source to this - program. Unlike addShaderFromSourceCode(), this function does not perform - compilation. Compilation is deferred to link(), and may not happen at all, - because link() may potentially use a program binary from Qt's shader disk - cache. This will typically lead to a significant increase in performance. - - When the disk cache is disabled, via Qt::AA_DisableShaderDiskCache for - example, or the OpenGL context has no support for context binaries, calling - this function is equivalent to addShaderFromSourceCode(). - - \since 5.9 - \sa addShaderFromSourceCode(), addCacheableShaderFromSourceFile() - */ -bool QOpenGLShaderProgram::addCacheableShaderFromSourceCode(QOpenGLShader::ShaderType type, const QString &source) -{ - Q_D(QOpenGLShaderProgram); - if (!init()) - return false; - if (d->isCacheDisabled()) - return addShaderFromSourceCode(type, source); - - return addCacheableShaderFromSourceCode(type, source.toUtf8().constData()); -} - -/*! - Registers the shader of the specified \a type and \a fileName to this - program. Unlike addShaderFromSourceFile(), this function does not perform - compilation. Compilation is deferred to link(), and may not happen at all, - because link() may potentially use a program binary from Qt's shader disk - cache. This will typically lead to a significant increase in performance. - - \return true if the file has been read successfully, false if the file could - not be opened or the normal, non-cached compilation of the shader has - failed. The compilation error messages can be retrieved via log(). - - When the disk cache is disabled, via Qt::AA_DisableShaderDiskCache for - example, or the OpenGL context has no support for context binaries, calling - this function is equivalent to addShaderFromSourceFile(). - - \since 5.9 - \sa addShaderFromSourceFile(), addCacheableShaderFromSourceCode() - */ -bool QOpenGLShaderProgram::addCacheableShaderFromSourceFile(QOpenGLShader::ShaderType type, const QString &fileName) -{ - Q_D(QOpenGLShaderProgram); - if (!init()) - return false; - if (d->isCacheDisabled()) - return addShaderFromSourceFile(type, fileName); - - QOpenGLProgramBinaryCache::ShaderDesc shader(qt_shaderTypeToStage(type)); - // NB! It could be tempting to defer reading the file contents and just - // hash the filename as the cache key, perhaps combined with last-modified - // timestamp checks. However, this would raise a number of issues (no - // timestamps for files in the resource system; preference for global, not - // per-application cache items (where filenames may clash); resource-based - // shaders from libraries like Qt Quick; etc.), so just avoid it. - QFile f(fileName); - if (f.open(QIODevice::ReadOnly | QIODevice::Text)) { - shader.source = f.readAll(); - f.close(); - } else { - qWarning("QOpenGLShaderProgram: Unable to open file %s", qPrintable(fileName)); - return false; - } - d->binaryProgram.shaders.append(shader); - return true; -} - -/*! - Removes \a shader from this shader program. The object is not deleted. - - The shader program must be valid in the current QOpenGLContext. - - \sa addShader(), link(), removeAllShaders() -*/ -void QOpenGLShaderProgram::removeShader(QOpenGLShader *shader) -{ - Q_D(QOpenGLShaderProgram); - if (d->programGuard && d->programGuard->id() - && shader && shader->d_func()->shaderGuard) - { - d->glfuncs->glDetachShader(d->programGuard->id(), shader->d_func()->shaderGuard->id()); - } - d->linked = false; // Program needs to be relinked. - if (shader) { - d->shaders.removeAll(shader); - d->anonShaders.removeAll(shader); - disconnect(shader, SIGNAL(destroyed()), this, SLOT(shaderDestroyed())); - } -} - -/*! - Returns a list of all shaders that have been added to this shader - program using addShader(). - - \sa addShader(), removeShader() -*/ -QList<QOpenGLShader *> QOpenGLShaderProgram::shaders() const -{ - Q_D(const QOpenGLShaderProgram); - return d->shaders; -} - -/*! - Removes all of the shaders that were added to this program previously. - The QOpenGLShader objects for the shaders will not be deleted if they - were constructed externally. QOpenGLShader objects that are constructed - internally by QOpenGLShaderProgram will be deleted. - - \sa addShader(), removeShader() -*/ -void QOpenGLShaderProgram::removeAllShaders() -{ - Q_D(QOpenGLShaderProgram); - d->removingShaders = true; - for (QOpenGLShader *shader : qAsConst(d->shaders)) { - if (d->programGuard && d->programGuard->id() - && shader && shader->d_func()->shaderGuard) - { - d->glfuncs->glDetachShader(d->programGuard->id(), shader->d_func()->shaderGuard->id()); - } - } - // Delete shader objects that were created anonymously. - qDeleteAll(d->anonShaders); - d->shaders.clear(); - d->anonShaders.clear(); - d->binaryProgram = QOpenGLProgramBinaryCache::ProgramDesc(); - d->linked = false; // Program needs to be relinked. - d->removingShaders = false; -} - -/*! - Links together the shaders that were added to this program with - addShader(). Returns \c true if the link was successful or - false otherwise. If the link failed, the error messages can - be retrieved with log(). - - Subclasses can override this function to initialize attributes - and uniform variables for use in specific shader programs. - - If the shader program was already linked, calling this - function again will force it to be re-linked. - - When shaders were added to this program via - addCacheableShaderFromSourceCode() or addCacheableShaderFromSourceFile(), - program binaries are supported, and a cached binary is available on disk, - actual compilation and linking are skipped. Instead, link() will initialize - the program with the binary blob via glProgramBinary(). If there is no - cached version of the program or it was generated with a different driver - version, the shaders will be compiled from source and the program will get - linked normally. This allows seamless upgrading of the graphics drivers, - without having to worry about potentially incompatible binary formats. - - \sa addShader(), log() -*/ -bool QOpenGLShaderProgram::link() -{ - Q_D(QOpenGLShaderProgram); - GLuint program = d->programGuard ? d->programGuard->id() : 0; - if (!program) - return false; - - if (!d->linkBinaryRecursion && d->shaders.isEmpty() && !d->binaryProgram.shaders.isEmpty()) - return d->linkBinary(); - - GLint value; - if (d->shaders.isEmpty()) { - // If there are no explicit shaders, then it is possible that the - // application added a program binary with glProgramBinaryOES(), or - // otherwise populated the shaders itself. This is also the case when - // we are recursively called back from linkBinary() after a successful - // glProgramBinary(). Check to see if the program is already linked and - // bail out if so. - value = 0; - d->glfuncs->glGetProgramiv(program, GL_LINK_STATUS, &value); - d->linked = (value != 0); - if (d->linked) - return true; - } - - d->glfuncs->glLinkProgram(program); - value = 0; - d->glfuncs->glGetProgramiv(program, GL_LINK_STATUS, &value); - d->linked = (value != 0); - value = 0; - d->glfuncs->glGetProgramiv(program, GL_INFO_LOG_LENGTH, &value); - d->log = QString(); - if (value > 1) { - char *logbuf = new char [value]; - GLint len; - d->glfuncs->glGetProgramInfoLog(program, value, &len, logbuf); - d->log = QString::fromLatin1(logbuf); - if (!d->linked && !d->linkBinaryRecursion) { - QString name = objectName(); - if (name.isEmpty()) - qWarning("QOpenGLShader::link: %ls", qUtf16Printable(d->log)); - else - qWarning("QOpenGLShader::link[%ls]: %ls", qUtf16Printable(name), qUtf16Printable(d->log)); - } - delete [] logbuf; - } - return d->linked; -} - -/*! - Returns \c true if this shader program has been linked; false otherwise. - - \sa link() -*/ -bool QOpenGLShaderProgram::isLinked() const -{ - Q_D(const QOpenGLShaderProgram); - return d->linked; -} - -/*! - Returns the errors and warnings that occurred during the last link() - or addShader() with explicitly specified source code. - - \sa link() -*/ -QString QOpenGLShaderProgram::log() const -{ - Q_D(const QOpenGLShaderProgram); - return d->log; -} - -/*! - Binds this shader program to the active QOpenGLContext and makes - it the current shader program. Any previously bound shader program - is released. This is equivalent to calling \c{glUseProgram()} on - programId(). Returns \c true if the program was successfully bound; - false otherwise. If the shader program has not yet been linked, - or it needs to be re-linked, this function will call link(). - - \sa link(), release() -*/ -bool QOpenGLShaderProgram::bind() -{ - Q_D(QOpenGLShaderProgram); - GLuint program = d->programGuard ? d->programGuard->id() : 0; - if (!program) - return false; - if (!d->linked && !link()) - return false; -#ifndef QT_NO_DEBUG - if (d->programGuard->group() != QOpenGLContextGroup::currentContextGroup()) { - qWarning("QOpenGLShaderProgram::bind: program is not valid in the current context."); - return false; - } -#endif - d->glfuncs->glUseProgram(program); - return true; -} - -/*! - Releases the active shader program from the current QOpenGLContext. - This is equivalent to calling \c{glUseProgram(0)}. - - \sa bind() -*/ -void QOpenGLShaderProgram::release() -{ - Q_D(QOpenGLShaderProgram); -#ifndef QT_NO_DEBUG - if (d->programGuard && d->programGuard->group() != QOpenGLContextGroup::currentContextGroup()) - qWarning("QOpenGLShaderProgram::release: program is not valid in the current context."); -#endif - d->glfuncs->glUseProgram(0); -} - -/*! - Returns the OpenGL identifier associated with this shader program. - - \sa QOpenGLShader::shaderId() -*/ -GLuint QOpenGLShaderProgram::programId() const -{ - Q_D(const QOpenGLShaderProgram); - GLuint id = d->programGuard ? d->programGuard->id() : 0; - if (id) - return id; - - // Create the identifier if we don't have one yet. This is for - // applications that want to create the attached shader configuration - // themselves, particularly those using program binaries. - if (!const_cast<QOpenGLShaderProgram *>(this)->init()) - return 0; - return d->programGuard ? d->programGuard->id() : 0; -} - -/*! - Binds the attribute \a name to the specified \a location. This - function can be called before or after the program has been linked. - Any attributes that have not been explicitly bound when the program - is linked will be assigned locations automatically. - - When this function is called after the program has been linked, - the program will need to be relinked for the change to take effect. - - \sa attributeLocation() -*/ -void QOpenGLShaderProgram::bindAttributeLocation(const char *name, int location) -{ - Q_D(QOpenGLShaderProgram); - if (!init() || !d->programGuard || !d->programGuard->id()) - return; - d->glfuncs->glBindAttribLocation(d->programGuard->id(), location, name); - d->linked = false; // Program needs to be relinked. -} - -/*! - \overload - - Binds the attribute \a name to the specified \a location. This - function can be called before or after the program has been linked. - Any attributes that have not been explicitly bound when the program - is linked will be assigned locations automatically. - - When this function is called after the program has been linked, - the program will need to be relinked for the change to take effect. - - \sa attributeLocation() -*/ -void QOpenGLShaderProgram::bindAttributeLocation(const QByteArray& name, int location) -{ - bindAttributeLocation(name.constData(), location); -} - -/*! - \overload - - Binds the attribute \a name to the specified \a location. This - function can be called before or after the program has been linked. - Any attributes that have not been explicitly bound when the program - is linked will be assigned locations automatically. - - When this function is called after the program has been linked, - the program will need to be relinked for the change to take effect. - - \sa attributeLocation() -*/ -void QOpenGLShaderProgram::bindAttributeLocation(const QString& name, int location) -{ - bindAttributeLocation(name.toLatin1().constData(), location); -} - -/*! - Returns the location of the attribute \a name within this shader - program's parameter list. Returns -1 if \a name is not a valid - attribute for this shader program. - - \sa uniformLocation(), bindAttributeLocation() -*/ -int QOpenGLShaderProgram::attributeLocation(const char *name) const -{ - Q_D(const QOpenGLShaderProgram); - if (d->linked && d->programGuard && d->programGuard->id()) { - return d->glfuncs->glGetAttribLocation(d->programGuard->id(), name); - } else { - qWarning("QOpenGLShaderProgram::attributeLocation(%s): shader program is not linked", name); - return -1; - } -} - -/*! - \overload - - Returns the location of the attribute \a name within this shader - program's parameter list. Returns -1 if \a name is not a valid - attribute for this shader program. - - \sa uniformLocation(), bindAttributeLocation() -*/ -int QOpenGLShaderProgram::attributeLocation(const QByteArray& name) const -{ - return attributeLocation(name.constData()); -} - -/*! - \overload - - Returns the location of the attribute \a name within this shader - program's parameter list. Returns -1 if \a name is not a valid - attribute for this shader program. - - \sa uniformLocation(), bindAttributeLocation() -*/ -int QOpenGLShaderProgram::attributeLocation(const QString& name) const -{ - return attributeLocation(name.toLatin1().constData()); -} - -/*! - Sets the attribute at \a location in the current context to \a value. - - \sa setUniformValue() -*/ -void QOpenGLShaderProgram::setAttributeValue(int location, GLfloat value) -{ - Q_D(QOpenGLShaderProgram); - if (location != -1) - d->glfuncs->glVertexAttrib1fv(location, &value); -} - -/*! - \overload - - Sets the attribute called \a name in the current context to \a value. - - \sa setUniformValue() -*/ -void QOpenGLShaderProgram::setAttributeValue(const char *name, GLfloat value) -{ - setAttributeValue(attributeLocation(name), value); -} - -/*! - Sets the attribute at \a location in the current context to - the 2D vector (\a x, \a y). - - \sa setUniformValue() -*/ -void QOpenGLShaderProgram::setAttributeValue(int location, GLfloat x, GLfloat y) -{ - Q_D(QOpenGLShaderProgram); - if (location != -1) { - GLfloat values[2] = {x, y}; - d->glfuncs->glVertexAttrib2fv(location, values); - } -} - -/*! - \overload - - Sets the attribute called \a name in the current context to - the 2D vector (\a x, \a y). - - \sa setUniformValue() -*/ -void QOpenGLShaderProgram::setAttributeValue(const char *name, GLfloat x, GLfloat y) -{ - setAttributeValue(attributeLocation(name), x, y); -} - -/*! - Sets the attribute at \a location in the current context to - the 3D vector (\a x, \a y, \a z). - - \sa setUniformValue() -*/ -void QOpenGLShaderProgram::setAttributeValue - (int location, GLfloat x, GLfloat y, GLfloat z) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) { - GLfloat values[3] = {x, y, z}; - d->glfuncs->glVertexAttrib3fv(location, values); - } -} - -/*! - \overload - - Sets the attribute called \a name in the current context to - the 3D vector (\a x, \a y, \a z). - - \sa setUniformValue() -*/ -void QOpenGLShaderProgram::setAttributeValue - (const char *name, GLfloat x, GLfloat y, GLfloat z) -{ - setAttributeValue(attributeLocation(name), x, y, z); -} - -/*! - Sets the attribute at \a location in the current context to - the 4D vector (\a x, \a y, \a z, \a w). - - \sa setUniformValue() -*/ -void QOpenGLShaderProgram::setAttributeValue - (int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - Q_D(QOpenGLShaderProgram); - if (location != -1) { - GLfloat values[4] = {x, y, z, w}; - d->glfuncs->glVertexAttrib4fv(location, values); - } -} - -/*! - \overload - - Sets the attribute called \a name in the current context to - the 4D vector (\a x, \a y, \a z, \a w). - - \sa setUniformValue() -*/ -void QOpenGLShaderProgram::setAttributeValue - (const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - setAttributeValue(attributeLocation(name), x, y, z, w); -} - -/*! - Sets the attribute at \a location in the current context to \a value. - - \sa setUniformValue() -*/ -void QOpenGLShaderProgram::setAttributeValue(int location, const QVector2D& value) -{ - Q_D(QOpenGLShaderProgram); - if (location != -1) - d->glfuncs->glVertexAttrib2fv(location, reinterpret_cast<const GLfloat *>(&value)); -} - -/*! - \overload - - Sets the attribute called \a name in the current context to \a value. - - \sa setUniformValue() -*/ -void QOpenGLShaderProgram::setAttributeValue(const char *name, const QVector2D& value) -{ - setAttributeValue(attributeLocation(name), value); -} - -/*! - Sets the attribute at \a location in the current context to \a value. - - \sa setUniformValue() -*/ -void QOpenGLShaderProgram::setAttributeValue(int location, const QVector3D& value) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) - d->glfuncs->glVertexAttrib3fv(location, reinterpret_cast<const GLfloat *>(&value)); -} - -/*! - \overload - - Sets the attribute called \a name in the current context to \a value. - - \sa setUniformValue() -*/ -void QOpenGLShaderProgram::setAttributeValue(const char *name, const QVector3D& value) -{ - setAttributeValue(attributeLocation(name), value); -} - -/*! - Sets the attribute at \a location in the current context to \a value. - - \sa setUniformValue() -*/ -void QOpenGLShaderProgram::setAttributeValue(int location, const QVector4D& value) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) - d->glfuncs->glVertexAttrib4fv(location, reinterpret_cast<const GLfloat *>(&value)); -} - -/*! - \overload - - Sets the attribute called \a name in the current context to \a value. - - \sa setUniformValue() -*/ -void QOpenGLShaderProgram::setAttributeValue(const char *name, const QVector4D& value) -{ - setAttributeValue(attributeLocation(name), value); -} - -/*! - Sets the attribute at \a location in the current context to \a value. - - \sa setUniformValue() -*/ -void QOpenGLShaderProgram::setAttributeValue(int location, const QColor& value) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) { - GLfloat values[4] = {GLfloat(value.redF()), GLfloat(value.greenF()), - GLfloat(value.blueF()), GLfloat(value.alphaF())}; - d->glfuncs->glVertexAttrib4fv(location, values); - } -} - -/*! - \overload - - Sets the attribute called \a name in the current context to \a value. - - \sa setUniformValue() -*/ -void QOpenGLShaderProgram::setAttributeValue(const char *name, const QColor& value) -{ - setAttributeValue(attributeLocation(name), value); -} - -/*! - Sets the attribute at \a location in the current context to the - contents of \a values, which contains \a columns elements, each - consisting of \a rows elements. The \a rows value should be - 1, 2, 3, or 4. This function is typically used to set matrix - values and column vectors. - - \sa setUniformValue() -*/ -void QOpenGLShaderProgram::setAttributeValue - (int location, const GLfloat *values, int columns, int rows) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (rows < 1 || rows > 4) { - qWarning("QOpenGLShaderProgram::setAttributeValue: rows %d not supported", rows); - return; - } - if (location != -1) { - while (columns-- > 0) { - if (rows == 1) - d->glfuncs->glVertexAttrib1fv(location, values); - else if (rows == 2) - d->glfuncs->glVertexAttrib2fv(location, values); - else if (rows == 3) - d->glfuncs->glVertexAttrib3fv(location, values); - else - d->glfuncs->glVertexAttrib4fv(location, values); - values += rows; - ++location; - } - } -} - -/*! - \overload - - Sets the attribute called \a name in the current context to the - contents of \a values, which contains \a columns elements, each - consisting of \a rows elements. The \a rows value should be - 1, 2, 3, or 4. This function is typically used to set matrix - values and column vectors. - - \sa setUniformValue() -*/ -void QOpenGLShaderProgram::setAttributeValue - (const char *name, const GLfloat *values, int columns, int rows) -{ - setAttributeValue(attributeLocation(name), values, columns, rows); -} - -/*! - Sets an array of vertex \a values on the attribute at \a location - in this shader program. The \a tupleSize indicates the number of - components per vertex (1, 2, 3, or 4), and the \a stride indicates - the number of bytes between vertices. A default \a stride value - of zero indicates that the vertices are densely packed in \a values. - - The array will become active when enableAttributeArray() is called - on the \a location. Otherwise the value specified with - setAttributeValue() for \a location will be used. - - \sa setAttributeValue(), setUniformValue(), enableAttributeArray() - \sa disableAttributeArray() -*/ -void QOpenGLShaderProgram::setAttributeArray - (int location, const GLfloat *values, int tupleSize, int stride) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) { - d->glfuncs->glVertexAttribPointer(location, tupleSize, GL_FLOAT, GL_FALSE, - stride, values); - } -} - -/*! - Sets an array of 2D vertex \a values on the attribute at \a location - in this shader program. The \a stride indicates the number of bytes - between vertices. A default \a stride value of zero indicates that - the vertices are densely packed in \a values. - - The array will become active when enableAttributeArray() is called - on the \a location. Otherwise the value specified with - setAttributeValue() for \a location will be used. - - \sa setAttributeValue(), setUniformValue(), enableAttributeArray() - \sa disableAttributeArray() -*/ -void QOpenGLShaderProgram::setAttributeArray - (int location, const QVector2D *values, int stride) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) { - d->glfuncs->glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, - stride, values); - } -} - -/*! - Sets an array of 3D vertex \a values on the attribute at \a location - in this shader program. The \a stride indicates the number of bytes - between vertices. A default \a stride value of zero indicates that - the vertices are densely packed in \a values. - - The array will become active when enableAttributeArray() is called - on the \a location. Otherwise the value specified with - setAttributeValue() for \a location will be used. - - \sa setAttributeValue(), setUniformValue(), enableAttributeArray() - \sa disableAttributeArray() -*/ -void QOpenGLShaderProgram::setAttributeArray - (int location, const QVector3D *values, int stride) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) { - d->glfuncs->glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, - stride, values); - } -} - -/*! - Sets an array of 4D vertex \a values on the attribute at \a location - in this shader program. The \a stride indicates the number of bytes - between vertices. A default \a stride value of zero indicates that - the vertices are densely packed in \a values. - - The array will become active when enableAttributeArray() is called - on the \a location. Otherwise the value specified with - setAttributeValue() for \a location will be used. - - \sa setAttributeValue(), setUniformValue(), enableAttributeArray() - \sa disableAttributeArray() -*/ -void QOpenGLShaderProgram::setAttributeArray - (int location, const QVector4D *values, int stride) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) { - d->glfuncs->glVertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, - stride, values); - } -} - -/*! - Sets an array of vertex \a values on the attribute at \a location - in this shader program. The \a stride indicates the number of bytes - between vertices. A default \a stride value of zero indicates that - the vertices are densely packed in \a values. - - The \a type indicates the type of elements in the \a values array, - usually \c{GL_FLOAT}, \c{GL_UNSIGNED_BYTE}, etc. The \a tupleSize - indicates the number of components per vertex: 1, 2, 3, or 4. - - The array will become active when enableAttributeArray() is called - on the \a location. Otherwise the value specified with - setAttributeValue() for \a location will be used. - - The setAttributeBuffer() function can be used to set the attribute - array to an offset within a vertex buffer. - - \note Normalization will be enabled. If this is not desired, call - glVertexAttribPointer directly through QOpenGLFunctions. - - \sa setAttributeValue(), setUniformValue(), enableAttributeArray() - \sa disableAttributeArray(), setAttributeBuffer() -*/ -void QOpenGLShaderProgram::setAttributeArray - (int location, GLenum type, const void *values, int tupleSize, int stride) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) { - d->glfuncs->glVertexAttribPointer(location, tupleSize, type, GL_TRUE, - stride, values); - } -} - -/*! - \overload - - Sets an array of vertex \a values on the attribute called \a name - in this shader program. The \a tupleSize indicates the number of - components per vertex (1, 2, 3, or 4), and the \a stride indicates - the number of bytes between vertices. A default \a stride value - of zero indicates that the vertices are densely packed in \a values. - - The array will become active when enableAttributeArray() is called - on \a name. Otherwise the value specified with setAttributeValue() - for \a name will be used. - - \sa setAttributeValue(), setUniformValue(), enableAttributeArray() - \sa disableAttributeArray() -*/ -void QOpenGLShaderProgram::setAttributeArray - (const char *name, const GLfloat *values, int tupleSize, int stride) -{ - setAttributeArray(attributeLocation(name), values, tupleSize, stride); -} - -/*! - \overload - - Sets an array of 2D vertex \a values on the attribute called \a name - in this shader program. The \a stride indicates the number of bytes - between vertices. A default \a stride value of zero indicates that - the vertices are densely packed in \a values. - - The array will become active when enableAttributeArray() is called - on \a name. Otherwise the value specified with setAttributeValue() - for \a name will be used. - - \sa setAttributeValue(), setUniformValue(), enableAttributeArray() - \sa disableAttributeArray() -*/ -void QOpenGLShaderProgram::setAttributeArray - (const char *name, const QVector2D *values, int stride) -{ - setAttributeArray(attributeLocation(name), values, stride); -} - -/*! - \overload - - Sets an array of 3D vertex \a values on the attribute called \a name - in this shader program. The \a stride indicates the number of bytes - between vertices. A default \a stride value of zero indicates that - the vertices are densely packed in \a values. - - The array will become active when enableAttributeArray() is called - on \a name. Otherwise the value specified with setAttributeValue() - for \a name will be used. - - \sa setAttributeValue(), setUniformValue(), enableAttributeArray() - \sa disableAttributeArray() -*/ -void QOpenGLShaderProgram::setAttributeArray - (const char *name, const QVector3D *values, int stride) -{ - setAttributeArray(attributeLocation(name), values, stride); -} - -/*! - \overload - - Sets an array of 4D vertex \a values on the attribute called \a name - in this shader program. The \a stride indicates the number of bytes - between vertices. A default \a stride value of zero indicates that - the vertices are densely packed in \a values. - - The array will become active when enableAttributeArray() is called - on \a name. Otherwise the value specified with setAttributeValue() - for \a name will be used. - - \sa setAttributeValue(), setUniformValue(), enableAttributeArray() - \sa disableAttributeArray() -*/ -void QOpenGLShaderProgram::setAttributeArray - (const char *name, const QVector4D *values, int stride) -{ - setAttributeArray(attributeLocation(name), values, stride); -} - -/*! - \overload - - Sets an array of vertex \a values on the attribute called \a name - in this shader program. The \a stride indicates the number of bytes - between vertices. A default \a stride value of zero indicates that - the vertices are densely packed in \a values. - - The \a type indicates the type of elements in the \a values array, - usually \c{GL_FLOAT}, \c{GL_UNSIGNED_BYTE}, etc. The \a tupleSize - indicates the number of components per vertex: 1, 2, 3, or 4. - - The array will become active when enableAttributeArray() is called - on the \a name. Otherwise the value specified with - setAttributeValue() for \a name will be used. - - The setAttributeBuffer() function can be used to set the attribute - array to an offset within a vertex buffer. - - \sa setAttributeValue(), setUniformValue(), enableAttributeArray() - \sa disableAttributeArray(), setAttributeBuffer() -*/ -void QOpenGLShaderProgram::setAttributeArray - (const char *name, GLenum type, const void *values, int tupleSize, int stride) -{ - setAttributeArray(attributeLocation(name), type, values, tupleSize, stride); -} - -/*! - Sets an array of vertex values on the attribute at \a location in - this shader program, starting at a specific \a offset in the - currently bound vertex buffer. The \a stride indicates the number - of bytes between vertices. A default \a stride value of zero - indicates that the vertices are densely packed in the value array. - - The \a type indicates the type of elements in the vertex value - array, usually \c{GL_FLOAT}, \c{GL_UNSIGNED_BYTE}, etc. The \a - tupleSize indicates the number of components per vertex: 1, 2, 3, - or 4. - - The array will become active when enableAttributeArray() is called - on the \a location. Otherwise the value specified with - setAttributeValue() for \a location will be used. - - \note Normalization will be enabled. If this is not desired, call - glVertexAttribPointer directly through QOpenGLFunctions. - - \sa setAttributeArray() -*/ -void QOpenGLShaderProgram::setAttributeBuffer - (int location, GLenum type, int offset, int tupleSize, int stride) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) { - d->glfuncs->glVertexAttribPointer(location, tupleSize, type, GL_TRUE, stride, - reinterpret_cast<const void *>(qintptr(offset))); - } -} - -/*! - \overload - - Sets an array of vertex values on the attribute called \a name - in this shader program, starting at a specific \a offset in the - currently bound vertex buffer. The \a stride indicates the number - of bytes between vertices. A default \a stride value of zero - indicates that the vertices are densely packed in the value array. - - The \a type indicates the type of elements in the vertex value - array, usually \c{GL_FLOAT}, \c{GL_UNSIGNED_BYTE}, etc. The \a - tupleSize indicates the number of components per vertex: 1, 2, 3, - or 4. - - The array will become active when enableAttributeArray() is called - on the \a name. Otherwise the value specified with - setAttributeValue() for \a name will be used. - - \sa setAttributeArray() -*/ -void QOpenGLShaderProgram::setAttributeBuffer - (const char *name, GLenum type, int offset, int tupleSize, int stride) -{ - setAttributeBuffer(attributeLocation(name), type, offset, tupleSize, stride); -} - -/*! - Enables the vertex array at \a location in this shader program - so that the value set by setAttributeArray() on \a location - will be used by the shader program. - - \sa disableAttributeArray(), setAttributeArray(), setAttributeValue() - \sa setUniformValue() -*/ -void QOpenGLShaderProgram::enableAttributeArray(int location) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) - d->glfuncs->glEnableVertexAttribArray(location); -} - -/*! - \overload - - Enables the vertex array called \a name in this shader program - so that the value set by setAttributeArray() on \a name - will be used by the shader program. - - \sa disableAttributeArray(), setAttributeArray(), setAttributeValue() - \sa setUniformValue() -*/ -void QOpenGLShaderProgram::enableAttributeArray(const char *name) -{ - enableAttributeArray(attributeLocation(name)); -} - -/*! - Disables the vertex array at \a location in this shader program - that was enabled by a previous call to enableAttributeArray(). - - \sa enableAttributeArray(), setAttributeArray(), setAttributeValue() - \sa setUniformValue() -*/ -void QOpenGLShaderProgram::disableAttributeArray(int location) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) - d->glfuncs->glDisableVertexAttribArray(location); -} - -/*! - \overload - - Disables the vertex array called \a name in this shader program - that was enabled by a previous call to enableAttributeArray(). - - \sa enableAttributeArray(), setAttributeArray(), setAttributeValue() - \sa setUniformValue() -*/ -void QOpenGLShaderProgram::disableAttributeArray(const char *name) -{ - disableAttributeArray(attributeLocation(name)); -} - -/*! - Returns the location of the uniform variable \a name within this shader - program's parameter list. Returns -1 if \a name is not a valid - uniform variable for this shader program. - - \sa attributeLocation() -*/ -int QOpenGLShaderProgram::uniformLocation(const char *name) const -{ - Q_D(const QOpenGLShaderProgram); - Q_UNUSED(d); - if (d->linked && d->programGuard && d->programGuard->id()) { - return d->glfuncs->glGetUniformLocation(d->programGuard->id(), name); - } else { - qWarning("QOpenGLShaderProgram::uniformLocation(%s): shader program is not linked", name); - return -1; - } -} - -/*! - \overload - - Returns the location of the uniform variable \a name within this shader - program's parameter list. Returns -1 if \a name is not a valid - uniform variable for this shader program. - - \sa attributeLocation() -*/ -int QOpenGLShaderProgram::uniformLocation(const QByteArray& name) const -{ - return uniformLocation(name.constData()); -} - -/*! - \overload - - Returns the location of the uniform variable \a name within this shader - program's parameter list. Returns -1 if \a name is not a valid - uniform variable for this shader program. - - \sa attributeLocation() -*/ -int QOpenGLShaderProgram::uniformLocation(const QString& name) const -{ - return uniformLocation(name.toLatin1().constData()); -} - -/*! - Sets the uniform variable at \a location in the current context to \a value. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(int location, GLfloat value) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) - d->glfuncs->glUniform1fv(location, 1, &value); -} - -/*! - \overload - - Sets the uniform variable called \a name in the current context - to \a value. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(const char *name, GLfloat value) -{ - setUniformValue(uniformLocation(name), value); -} - -/*! - Sets the uniform variable at \a location in the current context to \a value. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(int location, GLint value) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) - d->glfuncs->glUniform1i(location, value); -} - -/*! - \overload - - Sets the uniform variable called \a name in the current context - to \a value. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(const char *name, GLint value) -{ - setUniformValue(uniformLocation(name), value); -} - -/*! - Sets the uniform variable at \a location in the current context to \a value. - This function should be used when setting sampler values. - - \note This function is not aware of unsigned int support in modern OpenGL - versions and therefore treats \a value as a GLint and calls glUniform1i. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(int location, GLuint value) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) - d->glfuncs->glUniform1i(location, value); -} - -/*! - \overload - - Sets the uniform variable called \a name in the current context - to \a value. This function should be used when setting sampler values. - - \note This function is not aware of unsigned int support in modern OpenGL - versions and therefore treats \a value as a GLint and calls glUniform1i. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(const char *name, GLuint value) -{ - setUniformValue(uniformLocation(name), value); -} - -/*! - Sets the uniform variable at \a location in the current context to - the 2D vector (\a x, \a y). - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(int location, GLfloat x, GLfloat y) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) { - GLfloat values[2] = {x, y}; - d->glfuncs->glUniform2fv(location, 1, values); - } -} - -/*! - \overload - - Sets the uniform variable called \a name in the current context to - the 2D vector (\a x, \a y). - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(const char *name, GLfloat x, GLfloat y) -{ - setUniformValue(uniformLocation(name), x, y); -} - -/*! - Sets the uniform variable at \a location in the current context to - the 3D vector (\a x, \a y, \a z). - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue - (int location, GLfloat x, GLfloat y, GLfloat z) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) { - GLfloat values[3] = {x, y, z}; - d->glfuncs->glUniform3fv(location, 1, values); - } -} - -/*! - \overload - - Sets the uniform variable called \a name in the current context to - the 3D vector (\a x, \a y, \a z). - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue - (const char *name, GLfloat x, GLfloat y, GLfloat z) -{ - setUniformValue(uniformLocation(name), x, y, z); -} - -/*! - Sets the uniform variable at \a location in the current context to - the 4D vector (\a x, \a y, \a z, \a w). - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue - (int location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) { - GLfloat values[4] = {x, y, z, w}; - d->glfuncs->glUniform4fv(location, 1, values); - } -} - -/*! - \overload - - Sets the uniform variable called \a name in the current context to - the 4D vector (\a x, \a y, \a z, \a w). - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue - (const char *name, GLfloat x, GLfloat y, GLfloat z, GLfloat w) -{ - setUniformValue(uniformLocation(name), x, y, z, w); -} - -/*! - Sets the uniform variable at \a location in the current context to \a value. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(int location, const QVector2D& value) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) - d->glfuncs->glUniform2fv(location, 1, reinterpret_cast<const GLfloat *>(&value)); -} - -/*! - \overload - - Sets the uniform variable called \a name in the current context - to \a value. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(const char *name, const QVector2D& value) -{ - setUniformValue(uniformLocation(name), value); -} - -/*! - Sets the uniform variable at \a location in the current context to \a value. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(int location, const QVector3D& value) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) - d->glfuncs->glUniform3fv(location, 1, reinterpret_cast<const GLfloat *>(&value)); -} - -/*! - \overload - - Sets the uniform variable called \a name in the current context - to \a value. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(const char *name, const QVector3D& value) -{ - setUniformValue(uniformLocation(name), value); -} - -/*! - Sets the uniform variable at \a location in the current context to \a value. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(int location, const QVector4D& value) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) - d->glfuncs->glUniform4fv(location, 1, reinterpret_cast<const GLfloat *>(&value)); -} - -/*! - \overload - - Sets the uniform variable called \a name in the current context - to \a value. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(const char *name, const QVector4D& value) -{ - setUniformValue(uniformLocation(name), value); -} - -/*! - Sets the uniform variable at \a location in the current context to - the red, green, blue, and alpha components of \a color. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(int location, const QColor& color) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) { - GLfloat values[4] = {GLfloat(color.redF()), GLfloat(color.greenF()), - GLfloat(color.blueF()), GLfloat(color.alphaF())}; - d->glfuncs->glUniform4fv(location, 1, values); - } -} - -/*! - \overload - - Sets the uniform variable called \a name in the current context to - the red, green, blue, and alpha components of \a color. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(const char *name, const QColor& color) -{ - setUniformValue(uniformLocation(name), color); -} - -/*! - Sets the uniform variable at \a location in the current context to - the x and y coordinates of \a point. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(int location, const QPoint& point) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) { - GLfloat values[4] = {GLfloat(point.x()), GLfloat(point.y())}; - d->glfuncs->glUniform2fv(location, 1, values); - } -} - -/*! - \overload - - Sets the uniform variable associated with \a name in the current - context to the x and y coordinates of \a point. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(const char *name, const QPoint& point) -{ - setUniformValue(uniformLocation(name), point); -} - -/*! - Sets the uniform variable at \a location in the current context to - the x and y coordinates of \a point. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(int location, const QPointF& point) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) { - GLfloat values[4] = {GLfloat(point.x()), GLfloat(point.y())}; - d->glfuncs->glUniform2fv(location, 1, values); - } -} - -/*! - \overload - - Sets the uniform variable associated with \a name in the current - context to the x and y coordinates of \a point. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(const char *name, const QPointF& point) -{ - setUniformValue(uniformLocation(name), point); -} - -/*! - Sets the uniform variable at \a location in the current context to - the width and height of the given \a size. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(int location, const QSize& size) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) { - GLfloat values[4] = {GLfloat(size.width()), GLfloat(size.height())}; - d->glfuncs->glUniform2fv(location, 1, values); - } -} - -/*! - \overload - - Sets the uniform variable associated with \a name in the current - context to the width and height of the given \a size. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(const char *name, const QSize& size) -{ - setUniformValue(uniformLocation(name), size); -} - -/*! - Sets the uniform variable at \a location in the current context to - the width and height of the given \a size. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(int location, const QSizeF& size) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) { - GLfloat values[4] = {GLfloat(size.width()), GLfloat(size.height())}; - d->glfuncs->glUniform2fv(location, 1, values); - } -} - -/*! - \overload - - Sets the uniform variable associated with \a name in the current - context to the width and height of the given \a size. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(const char *name, const QSizeF& size) -{ - setUniformValue(uniformLocation(name), size); -} - -/*! - Sets the uniform variable at \a location in the current context - to a 2x2 matrix \a value. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix2x2& value) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - d->glfuncs->glUniformMatrix2fv(location, 1, GL_FALSE, value.constData()); -} - -/*! - \overload - - Sets the uniform variable called \a name in the current context - to a 2x2 matrix \a value. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix2x2& value) -{ - setUniformValue(uniformLocation(name), value); -} - -/*! - Sets the uniform variable at \a location in the current context - to a 2x3 matrix \a value. - - \note This function is not aware of non square matrix support, - that is, GLSL types like mat2x3, that is present in modern OpenGL - versions. Instead, it treats the uniform as an array of vec3. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix2x3& value) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - d->glfuncs->glUniform3fv(location, 2, value.constData()); -} - -/*! - \overload - - Sets the uniform variable called \a name in the current context - to a 2x3 matrix \a value. - - \note This function is not aware of non square matrix support, - that is, GLSL types like mat2x3, that is present in modern OpenGL - versions. Instead, it treats the uniform as an array of vec3. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix2x3& value) -{ - setUniformValue(uniformLocation(name), value); -} - -/*! - Sets the uniform variable at \a location in the current context - to a 2x4 matrix \a value. - - \note This function is not aware of non square matrix support, - that is, GLSL types like mat2x4, that is present in modern OpenGL - versions. Instead, it treats the uniform as an array of vec4. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix2x4& value) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - d->glfuncs->glUniform4fv(location, 2, value.constData()); -} - -/*! - \overload - - Sets the uniform variable called \a name in the current context - to a 2x4 matrix \a value. - - \note This function is not aware of non square matrix support, - that is, GLSL types like mat2x4, that is present in modern OpenGL - versions. Instead, it treats the uniform as an array of vec4. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix2x4& value) -{ - setUniformValue(uniformLocation(name), value); -} - -/*! - Sets the uniform variable at \a location in the current context - to a 3x2 matrix \a value. - - \note This function is not aware of non square matrix support, - that is, GLSL types like mat3x2, that is present in modern OpenGL - versions. Instead, it treats the uniform as an array of vec2. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix3x2& value) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - d->glfuncs->glUniform2fv(location, 3, value.constData()); -} - -/*! - \overload - - Sets the uniform variable called \a name in the current context - to a 3x2 matrix \a value. - - \note This function is not aware of non square matrix support, - that is, GLSL types like mat3x2, that is present in modern OpenGL - versions. Instead, it treats the uniform as an array of vec2. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix3x2& value) -{ - setUniformValue(uniformLocation(name), value); -} - -/*! - Sets the uniform variable at \a location in the current context - to a 3x3 matrix \a value. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix3x3& value) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - d->glfuncs->glUniformMatrix3fv(location, 1, GL_FALSE, value.constData()); -} - -/*! - \overload - - Sets the uniform variable called \a name in the current context - to a 3x3 matrix \a value. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix3x3& value) -{ - setUniformValue(uniformLocation(name), value); -} - -/*! - Sets the uniform variable at \a location in the current context - to a 3x4 matrix \a value. - - \note This function is not aware of non square matrix support, - that is, GLSL types like mat3x4, that is present in modern OpenGL - versions. Instead, it treats the uniform as an array of vec4. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix3x4& value) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - d->glfuncs->glUniform4fv(location, 3, value.constData()); -} - -/*! - \overload - - Sets the uniform variable called \a name in the current context - to a 3x4 matrix \a value. - - \note This function is not aware of non square matrix support, - that is, GLSL types like mat3x4, that is present in modern OpenGL - versions. Instead, it treats the uniform as an array of vec4. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix3x4& value) -{ - setUniformValue(uniformLocation(name), value); -} - -/*! - Sets the uniform variable at \a location in the current context - to a 4x2 matrix \a value. - - \note This function is not aware of non square matrix support, - that is, GLSL types like mat4x2, that is present in modern OpenGL - versions. Instead, it treats the uniform as an array of vec2. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix4x2& value) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - d->glfuncs->glUniform2fv(location, 4, value.constData()); -} - -/*! - \overload - - Sets the uniform variable called \a name in the current context - to a 4x2 matrix \a value. - - \note This function is not aware of non square matrix support, - that is, GLSL types like mat4x2, that is present in modern OpenGL - versions. Instead, it treats the uniform as an array of vec2. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix4x2& value) -{ - setUniformValue(uniformLocation(name), value); -} - -/*! - Sets the uniform variable at \a location in the current context - to a 4x3 matrix \a value. - - \note This function is not aware of non square matrix support, - that is, GLSL types like mat4x3, that is present in modern OpenGL - versions. Instead, it treats the uniform as an array of vec3. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix4x3& value) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - d->glfuncs->glUniform3fv(location, 4, value.constData()); -} - -/*! - \overload - - Sets the uniform variable called \a name in the current context - to a 4x3 matrix \a value. - - \note This function is not aware of non square matrix support, - that is, GLSL types like mat4x3, that is present in modern OpenGL - versions. Instead, it treats the uniform as an array of vec3. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix4x3& value) -{ - setUniformValue(uniformLocation(name), value); -} - -/*! - Sets the uniform variable at \a location in the current context - to a 4x4 matrix \a value. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(int location, const QMatrix4x4& value) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - d->glfuncs->glUniformMatrix4fv(location, 1, GL_FALSE, value.constData()); -} - -/*! - \overload - - Sets the uniform variable called \a name in the current context - to a 4x4 matrix \a value. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(const char *name, const QMatrix4x4& value) -{ - setUniformValue(uniformLocation(name), value); -} - -/*! - \overload - - Sets the uniform variable at \a location in the current context - to a 2x2 matrix \a value. The matrix elements must be specified - in column-major order. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(int location, const GLfloat value[2][2]) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) - d->glfuncs->glUniformMatrix2fv(location, 1, GL_FALSE, value[0]); -} - -/*! - \overload - - Sets the uniform variable at \a location in the current context - to a 3x3 matrix \a value. The matrix elements must be specified - in column-major order. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(int location, const GLfloat value[3][3]) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) - d->glfuncs->glUniformMatrix3fv(location, 1, GL_FALSE, value[0]); -} - -/*! - \overload - - Sets the uniform variable at \a location in the current context - to a 4x4 matrix \a value. The matrix elements must be specified - in column-major order. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(int location, const GLfloat value[4][4]) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) - d->glfuncs->glUniformMatrix4fv(location, 1, GL_FALSE, value[0]); -} - - -/*! - \overload - - Sets the uniform variable called \a name in the current context - to a 2x2 matrix \a value. The matrix elements must be specified - in column-major order. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(const char *name, const GLfloat value[2][2]) -{ - setUniformValue(uniformLocation(name), value); -} - -/*! - \overload - - Sets the uniform variable called \a name in the current context - to a 3x3 matrix \a value. The matrix elements must be specified - in column-major order. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(const char *name, const GLfloat value[3][3]) -{ - setUniformValue(uniformLocation(name), value); -} - -/*! - \overload - - Sets the uniform variable called \a name in the current context - to a 4x4 matrix \a value. The matrix elements must be specified - in column-major order. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValue(const char *name, const GLfloat value[4][4]) -{ - setUniformValue(uniformLocation(name), value); -} - -/*! - Sets the uniform variable at \a location in the current context to a - 3x3 transformation matrix \a value that is specified as a QTransform value. - - To set a QTransform value as a 4x4 matrix in a shader, use - \c{setUniformValue(location, QMatrix4x4(value))}. -*/ -void QOpenGLShaderProgram::setUniformValue(int location, const QTransform& value) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) { - GLfloat mat[3][3] = { - {GLfloat(value.m11()), GLfloat(value.m12()), GLfloat(value.m13())}, - {GLfloat(value.m21()), GLfloat(value.m22()), GLfloat(value.m23())}, - {GLfloat(value.m31()), GLfloat(value.m32()), GLfloat(value.m33())} - }; - d->glfuncs->glUniformMatrix3fv(location, 1, GL_FALSE, mat[0]); - } -} - -/*! - \overload - - Sets the uniform variable called \a name in the current context to a - 3x3 transformation matrix \a value that is specified as a QTransform value. - - To set a QTransform value as a 4x4 matrix in a shader, use - \c{setUniformValue(name, QMatrix4x4(value))}. -*/ -void QOpenGLShaderProgram::setUniformValue - (const char *name, const QTransform& value) -{ - setUniformValue(uniformLocation(name), value); -} - -/*! - Sets the uniform variable array at \a location in the current - context to the \a count elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(int location, const GLint *values, int count) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) - d->glfuncs->glUniform1iv(location, count, values); -} - -/*! - \overload - - Sets the uniform variable array called \a name in the current - context to the \a count elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray - (const char *name, const GLint *values, int count) -{ - setUniformValueArray(uniformLocation(name), values, count); -} - -/*! - Sets the uniform variable array at \a location in the current - context to the \a count elements of \a values. This overload - should be used when setting an array of sampler values. - - \note This function is not aware of unsigned int support in modern OpenGL - versions and therefore treats \a values as a GLint and calls glUniform1iv. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(int location, const GLuint *values, int count) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) - d->glfuncs->glUniform1iv(location, count, reinterpret_cast<const GLint *>(values)); -} - -/*! - \overload - - Sets the uniform variable array called \a name in the current - context to the \a count elements of \a values. This overload - should be used when setting an array of sampler values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray - (const char *name, const GLuint *values, int count) -{ - setUniformValueArray(uniformLocation(name), values, count); -} - -/*! - Sets the uniform variable array at \a location in the current - context to the \a count elements of \a values. Each element - has \a tupleSize components. The \a tupleSize must be 1, 2, 3, or 4. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(int location, const GLfloat *values, int count, int tupleSize) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) { - if (tupleSize == 1) - d->glfuncs->glUniform1fv(location, count, values); - else if (tupleSize == 2) - d->glfuncs->glUniform2fv(location, count, values); - else if (tupleSize == 3) - d->glfuncs->glUniform3fv(location, count, values); - else if (tupleSize == 4) - d->glfuncs->glUniform4fv(location, count, values); - else - qWarning("QOpenGLShaderProgram::setUniformValue: size %d not supported", tupleSize); - } -} - -/*! - \overload - - Sets the uniform variable array called \a name in the current - context to the \a count elements of \a values. Each element - has \a tupleSize components. The \a tupleSize must be 1, 2, 3, or 4. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray - (const char *name, const GLfloat *values, int count, int tupleSize) -{ - setUniformValueArray(uniformLocation(name), values, count, tupleSize); -} - -/*! - Sets the uniform variable array at \a location in the current - context to the \a count 2D vector elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(int location, const QVector2D *values, int count) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) - d->glfuncs->glUniform2fv(location, count, reinterpret_cast<const GLfloat *>(values)); -} - -/*! - \overload - - Sets the uniform variable array called \a name in the current - context to the \a count 2D vector elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QVector2D *values, int count) -{ - setUniformValueArray(uniformLocation(name), values, count); -} - -/*! - Sets the uniform variable array at \a location in the current - context to the \a count 3D vector elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(int location, const QVector3D *values, int count) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) - d->glfuncs->glUniform3fv(location, count, reinterpret_cast<const GLfloat *>(values)); -} - -/*! - \overload - - Sets the uniform variable array called \a name in the current - context to the \a count 3D vector elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QVector3D *values, int count) -{ - setUniformValueArray(uniformLocation(name), values, count); -} - -/*! - Sets the uniform variable array at \a location in the current - context to the \a count 4D vector elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(int location, const QVector4D *values, int count) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - if (location != -1) - d->glfuncs->glUniform4fv(location, count, reinterpret_cast<const GLfloat *>(values)); -} - -/*! - \overload - - Sets the uniform variable array called \a name in the current - context to the \a count 4D vector elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QVector4D *values, int count) -{ - setUniformValueArray(uniformLocation(name), values, count); -} - -// We have to repack matrix arrays from qreal to GLfloat. -#define setUniformMatrixArray(func,location,values,count,type,cols,rows) \ - if (location == -1 || count <= 0) \ - return; \ - if (sizeof(type) == sizeof(GLfloat) * cols * rows) { \ - func(location, count, GL_FALSE, \ - reinterpret_cast<const GLfloat *>(values[0].constData())); \ - } else { \ - QVarLengthArray<GLfloat> temp(cols * rows * count); \ - for (int index = 0; index < count; ++index) { \ - for (int index2 = 0; index2 < (cols * rows); ++index2) { \ - temp.data()[cols * rows * index + index2] = \ - values[index].constData()[index2]; \ - } \ - } \ - func(location, count, GL_FALSE, temp.constData()); \ - } -#define setUniformGenericMatrixArray(colfunc,location,values,count,type,cols,rows) \ - if (location == -1 || count <= 0) \ - return; \ - if (sizeof(type) == sizeof(GLfloat) * cols * rows) { \ - const GLfloat *data = reinterpret_cast<const GLfloat *> \ - (values[0].constData()); \ - colfunc(location, count * cols, data); \ - } else { \ - QVarLengthArray<GLfloat> temp(cols * rows * count); \ - for (int index = 0; index < count; ++index) { \ - for (int index2 = 0; index2 < (cols * rows); ++index2) { \ - temp.data()[cols * rows * index + index2] = \ - values[index].constData()[index2]; \ - } \ - } \ - colfunc(location, count * cols, temp.constData()); \ - } - -/*! - Sets the uniform variable array at \a location in the current - context to the \a count 2x2 matrix elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix2x2 *values, int count) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - setUniformMatrixArray - (d->glfuncs->glUniformMatrix2fv, location, values, count, QMatrix2x2, 2, 2); -} - -/*! - \overload - - Sets the uniform variable array called \a name in the current - context to the \a count 2x2 matrix elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix2x2 *values, int count) -{ - setUniformValueArray(uniformLocation(name), values, count); -} - -/*! - Sets the uniform variable array at \a location in the current - context to the \a count 2x3 matrix elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix2x3 *values, int count) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - setUniformGenericMatrixArray - (d->glfuncs->glUniform3fv, location, values, count, - QMatrix2x3, 2, 3); -} - -/*! - \overload - - Sets the uniform variable array called \a name in the current - context to the \a count 2x3 matrix elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix2x3 *values, int count) -{ - setUniformValueArray(uniformLocation(name), values, count); -} - -/*! - Sets the uniform variable array at \a location in the current - context to the \a count 2x4 matrix elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix2x4 *values, int count) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - setUniformGenericMatrixArray - (d->glfuncs->glUniform4fv, location, values, count, - QMatrix2x4, 2, 4); -} - -/*! - \overload - - Sets the uniform variable array called \a name in the current - context to the \a count 2x4 matrix elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix2x4 *values, int count) -{ - setUniformValueArray(uniformLocation(name), values, count); -} - -/*! - Sets the uniform variable array at \a location in the current - context to the \a count 3x2 matrix elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix3x2 *values, int count) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - setUniformGenericMatrixArray - (d->glfuncs->glUniform2fv, location, values, count, - QMatrix3x2, 3, 2); -} - -/*! - \overload - - Sets the uniform variable array called \a name in the current - context to the \a count 3x2 matrix elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix3x2 *values, int count) -{ - setUniformValueArray(uniformLocation(name), values, count); -} - -/*! - Sets the uniform variable array at \a location in the current - context to the \a count 3x3 matrix elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix3x3 *values, int count) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - setUniformMatrixArray - (d->glfuncs->glUniformMatrix3fv, location, values, count, QMatrix3x3, 3, 3); -} - -/*! - \overload - - Sets the uniform variable array called \a name in the current - context to the \a count 3x3 matrix elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix3x3 *values, int count) -{ - setUniformValueArray(uniformLocation(name), values, count); -} - -/*! - Sets the uniform variable array at \a location in the current - context to the \a count 3x4 matrix elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix3x4 *values, int count) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - setUniformGenericMatrixArray - (d->glfuncs->glUniform4fv, location, values, count, - QMatrix3x4, 3, 4); -} - -/*! - \overload - - Sets the uniform variable array called \a name in the current - context to the \a count 3x4 matrix elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix3x4 *values, int count) -{ - setUniformValueArray(uniformLocation(name), values, count); -} - -/*! - Sets the uniform variable array at \a location in the current - context to the \a count 4x2 matrix elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix4x2 *values, int count) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - setUniformGenericMatrixArray - (d->glfuncs->glUniform2fv, location, values, count, - QMatrix4x2, 4, 2); -} - -/*! - \overload - - Sets the uniform variable array called \a name in the current - context to the \a count 4x2 matrix elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x2 *values, int count) -{ - setUniformValueArray(uniformLocation(name), values, count); -} - -/*! - Sets the uniform variable array at \a location in the current - context to the \a count 4x3 matrix elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix4x3 *values, int count) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - setUniformGenericMatrixArray - (d->glfuncs->glUniform3fv, location, values, count, - QMatrix4x3, 4, 3); -} - -/*! - \overload - - Sets the uniform variable array called \a name in the current - context to the \a count 4x3 matrix elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x3 *values, int count) -{ - setUniformValueArray(uniformLocation(name), values, count); -} - -/*! - Sets the uniform variable array at \a location in the current - context to the \a count 4x4 matrix elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(int location, const QMatrix4x4 *values, int count) -{ - Q_D(QOpenGLShaderProgram); - Q_UNUSED(d); - setUniformMatrixArray - (d->glfuncs->glUniformMatrix4fv, location, values, count, QMatrix4x4, 4, 4); -} - -/*! - \overload - - Sets the uniform variable array called \a name in the current - context to the \a count 4x4 matrix elements of \a values. - - \sa setAttributeValue() -*/ -void QOpenGLShaderProgram::setUniformValueArray(const char *name, const QMatrix4x4 *values, int count) -{ - setUniformValueArray(uniformLocation(name), values, count); -} - -/*! - Returns the hardware limit for how many vertices a geometry shader - can output. -*/ -int QOpenGLShaderProgram::maxGeometryOutputVertices() const -{ - GLint n = 0; - Q_D(const QOpenGLShaderProgram); - d->glfuncs->glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &n); - return n; -} - -/*! - Use this function to specify to OpenGL the number of vertices in - a patch to \a count. A patch is a custom OpenGL primitive whose interpretation - is entirely defined by the tessellation shader stages. Therefore, calling - this function only makes sense when using a QOpenGLShaderProgram - containing tessellation stage shaders. When using OpenGL tessellation, - the only primitive that can be rendered with \c{glDraw*()} functions is - \c{GL_PATCHES}. - - This is equivalent to calling glPatchParameteri(GL_PATCH_VERTICES, count). - - \note This modifies global OpenGL state and is not specific to this - QOpenGLShaderProgram instance. You should call this in your render - function when needed, as QOpenGLShaderProgram will not apply this for - you. This is purely a convenience function. - - \sa patchVertexCount() -*/ -void QOpenGLShaderProgram::setPatchVertexCount(int count) -{ - Q_D(QOpenGLShaderProgram); - d->glfuncs->glPatchParameteri(GL_PATCH_VERTICES, count); -} - -/*! - Returns the number of vertices per-patch to be used when rendering. - - \note This returns the global OpenGL state value. It is not specific to - this QOpenGLShaderProgram instance. - - \sa setPatchVertexCount() -*/ -int QOpenGLShaderProgram::patchVertexCount() const -{ - int patchVertices = 0; - Q_D(const QOpenGLShaderProgram); - d->glfuncs->glGetIntegerv(GL_PATCH_VERTICES, &patchVertices); - return patchVertices; -} - -/*! - Sets the default outer tessellation levels to be used by the tessellation - primitive generator in the event that the tessellation control shader - does not output them to \a levels. For more details on OpenGL and Tessellation - shaders see \l{OpenGL Tessellation Shaders}. - - The \a levels argument should be a QVector consisting of 4 floats. Not all - of the values make sense for all tessellation modes. If you specify a vector with - fewer than 4 elements, the remaining elements will be given a default value of 1. - - \note This modifies global OpenGL state and is not specific to this - QOpenGLShaderProgram instance. You should call this in your render - function when needed, as QOpenGLShaderProgram will not apply this for - you. This is purely a convenience function. - - \note This function is only available with OpenGL >= 4.0 and is not supported - with OpenGL ES 3.2. - - \sa defaultOuterTessellationLevels(), setDefaultInnerTessellationLevels() -*/ -void QOpenGLShaderProgram::setDefaultOuterTessellationLevels(const QVector<float> &levels) -{ -#ifndef QT_OPENGL_ES_2 - Q_D(QOpenGLShaderProgram); - if (d->tessellationFuncs) { - QVector<float> tessLevels = levels; - - // Ensure we have the required 4 outer tessellation levels - // Use default of 1 for missing entries (same as spec) - const int argCount = 4; - if (tessLevels.size() < argCount) { - tessLevels.reserve(argCount); - for (int i = tessLevels.size(); i < argCount; ++i) - tessLevels.append(1.0f); - } - d->tessellationFuncs->glPatchParameterfv(GL_PATCH_DEFAULT_OUTER_LEVEL, tessLevels.data()); - } -#else - Q_UNUSED(levels); -#endif -} - -/*! - Returns the default outer tessellation levels to be used by the tessellation - primitive generator in the event that the tessellation control shader - does not output them. For more details on OpenGL and Tessellation shaders see - \l{OpenGL Tessellation Shaders}. - - Returns a QVector of floats describing the outer tessellation levels. The vector - will always have four elements but not all of them make sense for every mode - of tessellation. - - \note This returns the global OpenGL state value. It is not specific to - this QOpenGLShaderProgram instance. - - \note This function is only supported with OpenGL >= 4.0 and will not - return valid results with OpenGL ES 3.2. - - \sa setDefaultOuterTessellationLevels(), defaultInnerTessellationLevels() -*/ -QVector<float> QOpenGLShaderProgram::defaultOuterTessellationLevels() const -{ -#ifndef QT_OPENGL_ES_2 - QVector<float> tessLevels(4, 1.0f); - Q_D(const QOpenGLShaderProgram); - if (d->tessellationFuncs) - d->tessellationFuncs->glGetFloatv(GL_PATCH_DEFAULT_OUTER_LEVEL, tessLevels.data()); - return tessLevels; -#else - return QVector<float>(); -#endif -} - -/*! - Sets the default outer tessellation levels to be used by the tessellation - primitive generator in the event that the tessellation control shader - does not output them to \a levels. For more details on OpenGL and Tessellation shaders see - \l{OpenGL Tessellation Shaders}. - - The \a levels argument should be a QVector consisting of 2 floats. Not all - of the values make sense for all tessellation modes. If you specify a vector with - fewer than 2 elements, the remaining elements will be given a default value of 1. - - \note This modifies global OpenGL state and is not specific to this - QOpenGLShaderProgram instance. You should call this in your render - function when needed, as QOpenGLShaderProgram will not apply this for - you. This is purely a convenience function. - - \note This function is only available with OpenGL >= 4.0 and is not supported - with OpenGL ES 3.2. - - \sa defaultInnerTessellationLevels(), setDefaultOuterTessellationLevels() -*/ -void QOpenGLShaderProgram::setDefaultInnerTessellationLevels(const QVector<float> &levels) -{ -#ifndef QT_OPENGL_ES_2 - Q_D(QOpenGLShaderProgram); - if (d->tessellationFuncs) { - QVector<float> tessLevels = levels; - - // Ensure we have the required 2 inner tessellation levels - // Use default of 1 for missing entries (same as spec) - const int argCount = 2; - if (tessLevels.size() < argCount) { - tessLevels.reserve(argCount); - for (int i = tessLevels.size(); i < argCount; ++i) - tessLevels.append(1.0f); - } - d->tessellationFuncs->glPatchParameterfv(GL_PATCH_DEFAULT_INNER_LEVEL, tessLevels.data()); - } -#else - Q_UNUSED(levels); -#endif -} - -/*! - Returns the default inner tessellation levels to be used by the tessellation - primitive generator in the event that the tessellation control shader - does not output them. For more details on OpenGL and Tessellation shaders see - \l{OpenGL Tessellation Shaders}. - - Returns a QVector of floats describing the inner tessellation levels. The vector - will always have two elements but not all of them make sense for every mode - of tessellation. - - \note This returns the global OpenGL state value. It is not specific to - this QOpenGLShaderProgram instance. - - \note This function is only supported with OpenGL >= 4.0 and will not - return valid results with OpenGL ES 3.2. - - \sa setDefaultInnerTessellationLevels(), defaultOuterTessellationLevels() -*/ -QVector<float> QOpenGLShaderProgram::defaultInnerTessellationLevels() const -{ -#ifndef QT_OPENGL_ES_2 - QVector<float> tessLevels(2, 1.0f); - Q_D(const QOpenGLShaderProgram); - if (d->tessellationFuncs) - d->tessellationFuncs->glGetFloatv(GL_PATCH_DEFAULT_INNER_LEVEL, tessLevels.data()); - return tessLevels; -#else - return QVector<float>(); -#endif -} - - -/*! - Returns \c true if shader programs written in the OpenGL Shading - Language (GLSL) are supported on this system; false otherwise. - - The \a context is used to resolve the GLSL extensions. - If \a context is \nullptr, then QOpenGLContext::currentContext() - is used. -*/ -bool QOpenGLShaderProgram::hasOpenGLShaderPrograms(QOpenGLContext *context) -{ - if (!context) - context = QOpenGLContext::currentContext(); - if (!context) - return false; - return QOpenGLFunctions(context).hasOpenGLFeature(QOpenGLFunctions::Shaders); -} - -/*! - \internal -*/ -void QOpenGLShaderProgram::shaderDestroyed() -{ - Q_D(QOpenGLShaderProgram); - QOpenGLShader *shader = qobject_cast<QOpenGLShader *>(sender()); - if (shader && !d->removingShaders) - removeShader(shader); -} - -/*! - Returns \c true if shader programs of type \a type are supported on - this system; false otherwise. - - The \a context is used to resolve the GLSL extensions. - If \a context is \nullptr, then QOpenGLContext::currentContext() - is used. -*/ -bool QOpenGLShader::hasOpenGLShaders(ShaderType type, QOpenGLContext *context) -{ - if (!context) - context = QOpenGLContext::currentContext(); - if (!context) - return false; - - if ((type & ~(Geometry | Vertex | Fragment | TessellationControl | TessellationEvaluation | Compute)) || type == 0) - return false; - - if (type & QOpenGLShader::Geometry) - return supportsGeometry(context->format()); - else if (type & (QOpenGLShader::TessellationControl | QOpenGLShader::TessellationEvaluation)) - return supportsTessellation(context->format()); - else if (type & QOpenGLShader::Compute) - return supportsCompute(context->format()); - - // Unconditional support of vertex and fragment shaders implicitly assumes - // a minimum OpenGL version of 2.0 - return true; -} - -bool QOpenGLShaderProgramPrivate::isCacheDisabled() const -{ - static QOpenGLProgramBinarySupportCheckWrapper binSupportCheck; - return !binSupportCheck.get(QOpenGLContext::currentContext())->isSupported(); -} - -bool QOpenGLShaderProgramPrivate::compileCacheable() -{ - Q_Q(QOpenGLShaderProgram); - for (const QOpenGLProgramBinaryCache::ShaderDesc &shader : qAsConst(binaryProgram.shaders)) { - QScopedPointer<QOpenGLShader> s(new QOpenGLShader(qt_shaderStageToType(shader.stage), q)); - if (!s->compileSourceCode(shader.source)) { - log = s->log(); - return false; - } - anonShaders.append(s.take()); - if (!q->addShader(anonShaders.last())) - return false; - } - return true; -} - -bool QOpenGLShaderProgramPrivate::linkBinary() -{ - static QOpenGLProgramBinaryCache binCache; - - Q_Q(QOpenGLShaderProgram); - - const QByteArray cacheKey = binaryProgram.cacheKey(); - if (lcOpenGLProgramDiskCache().isEnabled(QtDebugMsg)) - qCDebug(lcOpenGLProgramDiskCache, "program with %d shaders, cache key %s", - binaryProgram.shaders.count(), cacheKey.constData()); - - bool needsCompile = true; - if (binCache.load(cacheKey, q->programId())) { - qCDebug(lcOpenGLProgramDiskCache, "Program binary received from cache"); - needsCompile = false; - } - - bool needsSave = false; - if (needsCompile) { - qCDebug(lcOpenGLProgramDiskCache, "Program binary not in cache, compiling"); - if (compileCacheable()) - needsSave = true; - else - return false; - } - - linkBinaryRecursion = true; - bool ok = q->link(); - linkBinaryRecursion = false; - if (ok && needsSave) - binCache.save(cacheKey, q->programId()); - - return ok; -} - -QT_END_NAMESPACE 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 <QtGui/qtguiglobal.h> - -#ifndef QT_NO_OPENGL - -#include <QtGui/qopengl.h> -#include <QtGui/qvector2d.h> -#include <QtGui/qvector3d.h> -#include <QtGui/qvector4d.h> -#include <QtGui/qmatrix4x4.h> - -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<QOpenGLShader *> 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<float> &levels); - QVector<float> defaultOuterTessellationLevels() const; - - void setDefaultInnerTessellationLevels(const QVector<float> &levels); - QVector<float> 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/opengl/qopengltexture.cpp b/src/gui/opengl/qopengltexture.cpp deleted file mode 100644 index 5490ad8025..0000000000 --- a/src/gui/opengl/qopengltexture.cpp +++ /dev/null @@ -1,4988 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB). -** Copyright (C) 2020 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 "qopengltexture.h" -#include "qopengltexture_p.h" -#include "qopengltexturehelper_p.h" -#include "qopenglfunctions.h" -#include <QtGui/qcolor.h> -#include <QtGui/qopenglcontext.h> -#include <QtCore/qdebug.h> -#include <private/qobject_p.h> -#include <private/qopenglcontext_p.h> - -QT_BEGIN_NAMESPACE - -//this is to work around GL_TEXTURE_WRAP_R_OES which also has 0x8072 as value -#if !defined(GL_TEXTURE_WRAP_R) - #define GL_TEXTURE_WRAP_R 0x8072 -#endif - -QOpenGLTexturePrivate::QOpenGLTexturePrivate(QOpenGLTexture::Target textureTarget, - QOpenGLTexture *qq) - : q_ptr(qq), - context(nullptr), - target(textureTarget), - textureId(0), - format(QOpenGLTexture::NoFormat), - formatClass(QOpenGLTexture::NoFormatClass), - requestedMipLevels(1), - mipLevels(-1), - layers(1), - faces(1), - samples(0), - fixedSamplePositions(true), - baseLevel(0), - maxLevel(1000), - depthStencilMode(QOpenGLTexture::DepthMode), - comparisonFunction(QOpenGLTexture::CompareLessEqual), - comparisonMode(QOpenGLTexture::CompareNone), - minFilter(QOpenGLTexture::Nearest), - magFilter(QOpenGLTexture::Nearest), - maxAnisotropy(1.0f), - minLevelOfDetail(-1000.0f), - maxLevelOfDetail(1000.0f), - levelOfDetailBias(0.0f), - textureView(false), - autoGenerateMipMaps(true), - storageAllocated(false), - texFuncs(nullptr), - functions(nullptr) -{ - dimensions[0] = dimensions[1] = dimensions[2] = 1; - - switch (target) { - case QOpenGLTexture::Target1D: - bindingTarget = QOpenGLTexture::BindingTarget1D; - break; - case QOpenGLTexture::Target1DArray: - bindingTarget = QOpenGLTexture::BindingTarget1DArray; - break; - case QOpenGLTexture::Target2D: - bindingTarget = QOpenGLTexture::BindingTarget2D; - break; - case QOpenGLTexture::Target2DArray: - bindingTarget = QOpenGLTexture::BindingTarget2DArray; - break; - case QOpenGLTexture::Target3D: - bindingTarget = QOpenGLTexture::BindingTarget3D; - break; - case QOpenGLTexture::TargetCubeMap: - bindingTarget = QOpenGLTexture::BindingTargetCubeMap; - faces = 6; - break; - case QOpenGLTexture::TargetCubeMapArray: - bindingTarget = QOpenGLTexture::BindingTargetCubeMapArray; - faces = 6; - break; - case QOpenGLTexture::Target2DMultisample: - bindingTarget = QOpenGLTexture::BindingTarget2DMultisample; - break; - case QOpenGLTexture::Target2DMultisampleArray: - bindingTarget = QOpenGLTexture::BindingTarget2DMultisampleArray; - break; - case QOpenGLTexture::TargetRectangle: - bindingTarget = QOpenGLTexture::BindingTargetRectangle; - break; - case QOpenGLTexture::TargetBuffer: - bindingTarget = QOpenGLTexture::BindingTargetBuffer; - break; - } - - swizzleMask[0] = QOpenGLTexture::RedValue; - swizzleMask[1] = QOpenGLTexture::GreenValue; - swizzleMask[2] = QOpenGLTexture::BlueValue; - swizzleMask[3] = QOpenGLTexture::AlphaValue; - - wrapModes[0] = wrapModes[1] = wrapModes[2] = target == QOpenGLTexture::TargetRectangle - ? QOpenGLTexture::ClampToEdge : QOpenGLTexture::Repeat; -} - -QOpenGLTexturePrivate::~QOpenGLTexturePrivate() -{ - destroy(); -} - -void QOpenGLTexturePrivate::initializeOpenGLFunctions() -{ - // If we already have a functions object, there is nothing to do - if (texFuncs) - return; - - // See if the context already has a suitable resource we can use. - // If not create a functions object and add it to the context in case - // others wish to use it too - texFuncs = context->textureFunctions(); - if (!texFuncs) { - texFuncs = new QOpenGLTextureHelper(context); - context->setTextureFunctions(texFuncs); - } -} - -bool QOpenGLTexturePrivate::create() -{ - if (textureId != 0) - return true; - - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - if (!ctx) { - qWarning("Requires a valid current OpenGL context.\n" - "Texture has not been created"); - return false; - } - context = ctx; - functions = ctx->functions(); - - // Resolve any functions we will need based upon context version and create the texture - initializeOpenGLFunctions(); - - // What features do we have? - QOpenGLTexture::Feature feature = QOpenGLTexture::ImmutableStorage; - while (feature != QOpenGLTexture::MaxFeatureFlag) { - if (QOpenGLTexture::hasFeature(feature)) - features |= feature; - feature = static_cast<QOpenGLTexture::Feature>(feature << 1); - } - - functions->glGenTextures(1, &textureId); - return textureId != 0; -} - -void QOpenGLTexturePrivate::destroy() -{ - if (!textureId) { - // not created or already destroyed - return; - } - QOpenGLContext *currentContext = QOpenGLContext::currentContext(); - if (!currentContext) { - qWarning("QOpenGLTexturePrivate::destroy() called without a current context.\n" - "Texture has not been destroyed"); - return; - } - if (!QOpenGLContext::areSharing(currentContext, context)) { - - qWarning("QOpenGLTexturePrivate::destroy() called but texture context %p" - " is not shared with current context %p.\n" - "Texture has not been destroyed", - static_cast<const void *>(context), - static_cast<const void *>(currentContext)); - return; - } - - functions->glDeleteTextures(1, &textureId); - - context = nullptr; - functions = nullptr; - textureId = 0; - format = QOpenGLTexture::NoFormat; - formatClass = QOpenGLTexture::NoFormatClass; - requestedMipLevels = 1; - mipLevels = -1; - layers = 1; - faces = 1; - samples = 0; - fixedSamplePositions = true, - baseLevel = 0; - maxLevel = 1000; - depthStencilMode = QOpenGLTexture::DepthMode; - minFilter = QOpenGLTexture::Nearest; - magFilter = QOpenGLTexture::Nearest; - maxAnisotropy = 1.0f; - minLevelOfDetail = -1000.0f; - maxLevelOfDetail = 1000.0f; - levelOfDetailBias = 0.0f; - textureView = false; - autoGenerateMipMaps = true; - storageAllocated = false; - texFuncs = nullptr; - - swizzleMask[0] = QOpenGLTexture::RedValue; - swizzleMask[1] = QOpenGLTexture::GreenValue; - swizzleMask[2] = QOpenGLTexture::BlueValue; - swizzleMask[3] = QOpenGLTexture::AlphaValue; - - wrapModes[0] = wrapModes[1] = wrapModes[2] = target == QOpenGLTexture::TargetRectangle - ? QOpenGLTexture::ClampToEdge : QOpenGLTexture::Repeat; -} - -void QOpenGLTexturePrivate::bind() -{ - functions->glBindTexture(target, textureId); -} - -void QOpenGLTexturePrivate::bind(uint unit, QOpenGLTexture::TextureUnitReset reset) -{ - GLint oldTextureUnit = 0; - if (reset == QOpenGLTexture::ResetTextureUnit) - functions->glGetIntegerv(GL_ACTIVE_TEXTURE, &oldTextureUnit); - - texFuncs->glActiveTexture(GL_TEXTURE0 + unit); - functions->glBindTexture(target, textureId); - - if (reset == QOpenGLTexture::ResetTextureUnit) - texFuncs->glActiveTexture(GL_TEXTURE0 + oldTextureUnit); -} - -void QOpenGLTexturePrivate::release() -{ - functions->glBindTexture(target, 0); -} - -void QOpenGLTexturePrivate::release(uint unit, QOpenGLTexture::TextureUnitReset reset) -{ - GLint oldTextureUnit = 0; - if (reset == QOpenGLTexture::ResetTextureUnit) - functions->glGetIntegerv(GL_ACTIVE_TEXTURE, &oldTextureUnit); - - texFuncs->glActiveTexture(GL_TEXTURE0 + unit); - functions->glBindTexture(target, 0); - - if (reset == QOpenGLTexture::ResetTextureUnit) - texFuncs->glActiveTexture(GL_TEXTURE0 + oldTextureUnit); -} - -bool QOpenGLTexturePrivate::isBound() const -{ - GLint boundTextureId = 0; - functions->glGetIntegerv(bindingTarget, &boundTextureId); - return (static_cast<GLuint>(boundTextureId) == textureId); -} - -bool QOpenGLTexturePrivate::isBound(uint unit) const -{ - GLint oldTextureUnit = 0; - functions->glGetIntegerv(GL_ACTIVE_TEXTURE, &oldTextureUnit); - - GLint boundTextureId = 0; - texFuncs->glActiveTexture(GL_TEXTURE0 + unit); - functions->glGetIntegerv(bindingTarget, &boundTextureId); - bool result = (static_cast<GLuint>(boundTextureId) == textureId); - - texFuncs->glActiveTexture(GL_TEXTURE0 + oldTextureUnit); - return result; -} - -int QOpenGLTexturePrivate::evaluateMipLevels() const -{ - switch (target) { - case QOpenGLTexture::Target1D: - case QOpenGLTexture::Target1DArray: - case QOpenGLTexture::Target2D: - case QOpenGLTexture::Target2DArray: - case QOpenGLTexture::Target3D: - case QOpenGLTexture::TargetCubeMap: - case QOpenGLTexture::TargetCubeMapArray: - return qMin(maximumMipLevelCount(), qMax(1, requestedMipLevels)); - - case QOpenGLTexture::TargetRectangle: - case QOpenGLTexture::Target2DMultisample: - case QOpenGLTexture::Target2DMultisampleArray: - case QOpenGLTexture::TargetBuffer: - default: - return 1; - } -} - -static bool isSizedTextureFormat(QOpenGLTexture::TextureFormat internalFormat) -{ - switch (internalFormat) { - case QOpenGLTexture::NoFormat: - return false; - - case QOpenGLTexture::R8_UNorm: - case QOpenGLTexture::RG8_UNorm: - case QOpenGLTexture::RGB8_UNorm: - case QOpenGLTexture::RGBA8_UNorm: - case QOpenGLTexture::R16_UNorm: - case QOpenGLTexture::RG16_UNorm: - case QOpenGLTexture::RGB16_UNorm: - case QOpenGLTexture::RGBA16_UNorm: - case QOpenGLTexture::R8_SNorm: - case QOpenGLTexture::RG8_SNorm: - case QOpenGLTexture::RGB8_SNorm: - case QOpenGLTexture::RGBA8_SNorm: - case QOpenGLTexture::R16_SNorm: - case QOpenGLTexture::RG16_SNorm: - case QOpenGLTexture::RGB16_SNorm: - case QOpenGLTexture::RGBA16_SNorm: - case QOpenGLTexture::R8U: - case QOpenGLTexture::RG8U: - case QOpenGLTexture::RGB8U: - case QOpenGLTexture::RGBA8U: - case QOpenGLTexture::R16U: - case QOpenGLTexture::RG16U: - case QOpenGLTexture::RGB16U: - case QOpenGLTexture::RGBA16U: - case QOpenGLTexture::R32U: - case QOpenGLTexture::RG32U: - case QOpenGLTexture::RGB32U: - case QOpenGLTexture::RGBA32U: - case QOpenGLTexture::R8I: - case QOpenGLTexture::RG8I: - case QOpenGLTexture::RGB8I: - case QOpenGLTexture::RGBA8I: - case QOpenGLTexture::R16I: - case QOpenGLTexture::RG16I: - case QOpenGLTexture::RGB16I: - case QOpenGLTexture::RGBA16I: - case QOpenGLTexture::R32I: - case QOpenGLTexture::RG32I: - case QOpenGLTexture::RGB32I: - case QOpenGLTexture::RGBA32I: - case QOpenGLTexture::R16F: - case QOpenGLTexture::RG16F: - case QOpenGLTexture::RGB16F: - case QOpenGLTexture::RGBA16F: - case QOpenGLTexture::R32F: - case QOpenGLTexture::RG32F: - case QOpenGLTexture::RGB32F: - case QOpenGLTexture::RGBA32F: - case QOpenGLTexture::RGB9E5: - case QOpenGLTexture::RG11B10F: - case QOpenGLTexture::RG3B2: - case QOpenGLTexture::R5G6B5: - case QOpenGLTexture::RGB5A1: - case QOpenGLTexture::RGBA4: - case QOpenGLTexture::RGB10A2: - - case QOpenGLTexture::D16: - case QOpenGLTexture::D24: - case QOpenGLTexture::D32: - case QOpenGLTexture::D32F: - - case QOpenGLTexture::D24S8: - case QOpenGLTexture::D32FS8X24: - - case QOpenGLTexture::S8: - - case QOpenGLTexture::RGB_DXT1: - case QOpenGLTexture::RGBA_DXT1: - case QOpenGLTexture::RGBA_DXT3: - case QOpenGLTexture::RGBA_DXT5: - case QOpenGLTexture::R_ATI1N_UNorm: - case QOpenGLTexture::R_ATI1N_SNorm: - case QOpenGLTexture::RG_ATI2N_UNorm: - case QOpenGLTexture::RG_ATI2N_SNorm: - case QOpenGLTexture::RGB_BP_UNSIGNED_FLOAT: - case QOpenGLTexture::RGB_BP_SIGNED_FLOAT: - case QOpenGLTexture::RGB_BP_UNorm: - case QOpenGLTexture::SRGB8: - case QOpenGLTexture::SRGB8_Alpha8: - case QOpenGLTexture::SRGB_DXT1: - case QOpenGLTexture::SRGB_Alpha_DXT1: - case QOpenGLTexture::SRGB_Alpha_DXT3: - case QOpenGLTexture::SRGB_Alpha_DXT5: - case QOpenGLTexture::SRGB_BP_UNorm: - case QOpenGLTexture::R11_EAC_UNorm: - case QOpenGLTexture::R11_EAC_SNorm: - case QOpenGLTexture::RG11_EAC_UNorm: - case QOpenGLTexture::RG11_EAC_SNorm: - case QOpenGLTexture::RGB8_ETC2: - case QOpenGLTexture::SRGB8_ETC2: - case QOpenGLTexture::RGB8_PunchThrough_Alpha1_ETC2: - case QOpenGLTexture::SRGB8_PunchThrough_Alpha1_ETC2: - case QOpenGLTexture::RGBA8_ETC2_EAC: - case QOpenGLTexture::SRGB8_Alpha8_ETC2_EAC: - case QOpenGLTexture::RGBA_ASTC_4x4: - case QOpenGLTexture::RGBA_ASTC_5x4: - case QOpenGLTexture::RGBA_ASTC_5x5: - case QOpenGLTexture::RGBA_ASTC_6x5: - case QOpenGLTexture::RGBA_ASTC_6x6: - case QOpenGLTexture::RGBA_ASTC_8x5: - case QOpenGLTexture::RGBA_ASTC_8x6: - case QOpenGLTexture::RGBA_ASTC_8x8: - case QOpenGLTexture::RGBA_ASTC_10x5: - case QOpenGLTexture::RGBA_ASTC_10x6: - case QOpenGLTexture::RGBA_ASTC_10x8: - case QOpenGLTexture::RGBA_ASTC_10x10: - case QOpenGLTexture::RGBA_ASTC_12x10: - case QOpenGLTexture::RGBA_ASTC_12x12: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_4x4: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_5x4: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_5x5: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_6x5: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_6x6: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_8x5: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_8x6: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_8x8: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_10x5: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_10x6: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_10x8: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_10x10: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_12x10: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_12x12: - return true; - - case QOpenGLTexture::RGB8_ETC1: - return false; - - case QOpenGLTexture::DepthFormat: - case QOpenGLTexture::AlphaFormat: - - case QOpenGLTexture::RGBFormat: - case QOpenGLTexture::RGBAFormat: - - case QOpenGLTexture::LuminanceFormat: - - case QOpenGLTexture::LuminanceAlphaFormat: - return false; - } - - Q_UNREACHABLE(); - return false; -} - -static bool isTextureTargetMultisample(QOpenGLTexture::Target target) -{ - switch (target) { - case QOpenGLTexture::Target1D: - case QOpenGLTexture::Target1DArray: - case QOpenGLTexture::Target2D: - case QOpenGLTexture::Target2DArray: - case QOpenGLTexture::Target3D: - case QOpenGLTexture::TargetCubeMap: - case QOpenGLTexture::TargetCubeMapArray: - return false; - - case QOpenGLTexture::Target2DMultisample: - case QOpenGLTexture::Target2DMultisampleArray: - return true; - - case QOpenGLTexture::TargetRectangle: - case QOpenGLTexture::TargetBuffer: - return false; - } - - Q_UNREACHABLE(); - return false; -} - -bool QOpenGLTexturePrivate::isUsingImmutableStorage() const -{ - // Use immutable storage whenever possible, falling back to mutable - // Note that if multisample textures are not supported at all, we'll still fail into - // the mutable storage allocation - return isSizedTextureFormat(format) - && (isTextureTargetMultisample(target) - ? features.testFlag(QOpenGLTexture::ImmutableMultisampleStorage) - : features.testFlag(QOpenGLTexture::ImmutableStorage)); -} - -void QOpenGLTexturePrivate::allocateStorage(QOpenGLTexture::PixelFormat pixelFormat, QOpenGLTexture::PixelType pixelType) -{ - // Resolve the actual number of mipmap levels we can use - mipLevels = evaluateMipLevels(); - - if (isUsingImmutableStorage()) - allocateImmutableStorage(); - else - allocateMutableStorage(pixelFormat, pixelType); -} - -static QOpenGLTexture::PixelFormat pixelFormatCompatibleWithInternalFormat(QOpenGLTexture::TextureFormat internalFormat) -{ - switch (internalFormat) { - case QOpenGLTexture::NoFormat: - return QOpenGLTexture::NoSourceFormat; - - case QOpenGLTexture::R8_UNorm: - return QOpenGLTexture::Red; - - case QOpenGLTexture::RG8_UNorm: - return QOpenGLTexture::RG; - - case QOpenGLTexture::RGB8_UNorm: - return QOpenGLTexture::RGB; - - case QOpenGLTexture::RGBA8_UNorm: - return QOpenGLTexture::RGBA; - - case QOpenGLTexture::R16_UNorm: - return QOpenGLTexture::Red; - - case QOpenGLTexture::RG16_UNorm: - return QOpenGLTexture::RG; - - case QOpenGLTexture::RGB16_UNorm: - return QOpenGLTexture::RGB; - - case QOpenGLTexture::RGBA16_UNorm: - return QOpenGLTexture::RGBA; - - case QOpenGLTexture::R8_SNorm: - return QOpenGLTexture::Red; - - case QOpenGLTexture::RG8_SNorm: - return QOpenGLTexture::RG; - - case QOpenGLTexture::RGB8_SNorm: - return QOpenGLTexture::RGB; - - case QOpenGLTexture::RGBA8_SNorm: - return QOpenGLTexture::RGBA; - - case QOpenGLTexture::R16_SNorm: - return QOpenGLTexture::Red; - - case QOpenGLTexture::RG16_SNorm: - return QOpenGLTexture::RG; - - case QOpenGLTexture::RGB16_SNorm: - return QOpenGLTexture::RGB; - - case QOpenGLTexture::RGBA16_SNorm: - return QOpenGLTexture::RGBA; - - case QOpenGLTexture::R8U: - return QOpenGLTexture::Red_Integer; - - case QOpenGLTexture::RG8U: - return QOpenGLTexture::RG_Integer; - - case QOpenGLTexture::RGB8U: - return QOpenGLTexture::RGB_Integer; - - case QOpenGLTexture::RGBA8U: - return QOpenGLTexture::RGBA_Integer; - - case QOpenGLTexture::R16U: - return QOpenGLTexture::Red_Integer; - - case QOpenGLTexture::RG16U: - return QOpenGLTexture::RG_Integer; - - case QOpenGLTexture::RGB16U: - return QOpenGLTexture::RGB_Integer; - - case QOpenGLTexture::RGBA16U: - return QOpenGLTexture::RGBA_Integer; - - case QOpenGLTexture::R32U: - return QOpenGLTexture::Red_Integer; - - case QOpenGLTexture::RG32U: - return QOpenGLTexture::RG_Integer; - - case QOpenGLTexture::RGB32U: - return QOpenGLTexture::RGB_Integer; - - case QOpenGLTexture::RGBA32U: - return QOpenGLTexture::RGBA_Integer; - - case QOpenGLTexture::R8I: - return QOpenGLTexture::Red_Integer; - - case QOpenGLTexture::RG8I: - return QOpenGLTexture::RG_Integer; - - case QOpenGLTexture::RGB8I: - return QOpenGLTexture::RGB_Integer; - - case QOpenGLTexture::RGBA8I: - return QOpenGLTexture::RGBA_Integer; - - case QOpenGLTexture::R16I: - return QOpenGLTexture::Red_Integer; - - case QOpenGLTexture::RG16I: - return QOpenGLTexture::RG_Integer; - - case QOpenGLTexture::RGB16I: - return QOpenGLTexture::RGB_Integer; - - case QOpenGLTexture::RGBA16I: - return QOpenGLTexture::RGBA_Integer; - - case QOpenGLTexture::R32I: - return QOpenGLTexture::Red_Integer; - - case QOpenGLTexture::RG32I: - return QOpenGLTexture::RG_Integer; - - case QOpenGLTexture::RGB32I: - return QOpenGLTexture::RGB_Integer; - - case QOpenGLTexture::RGBA32I: - return QOpenGLTexture::RGBA_Integer; - - case QOpenGLTexture::R16F: - return QOpenGLTexture::Red; - - case QOpenGLTexture::RG16F: - return QOpenGLTexture::RG; - - case QOpenGLTexture::RGB16F: - return QOpenGLTexture::RGB; - - case QOpenGLTexture::RGBA16F: - return QOpenGLTexture::RGBA; - - case QOpenGLTexture::R32F: - return QOpenGLTexture::Red; - - case QOpenGLTexture::RG32F: - return QOpenGLTexture::RG; - - case QOpenGLTexture::RGB32F: - return QOpenGLTexture::RGB; - - case QOpenGLTexture::RGBA32F: - return QOpenGLTexture::RGBA; - - case QOpenGLTexture::RGB9E5: - return QOpenGLTexture::RGB; - - case QOpenGLTexture::RG11B10F: - return QOpenGLTexture::RGB; - - case QOpenGLTexture::RG3B2: - return QOpenGLTexture::RGB; - - case QOpenGLTexture::R5G6B5: - return QOpenGLTexture::RGB; - - case QOpenGLTexture::RGB5A1: - return QOpenGLTexture::RGBA; - - case QOpenGLTexture::RGBA4: - return QOpenGLTexture::RGBA; - - case QOpenGLTexture::RGB10A2: - return QOpenGLTexture::RGBA; - - case QOpenGLTexture::D16: - case QOpenGLTexture::D24: - case QOpenGLTexture::D32: - case QOpenGLTexture::D32F: - return QOpenGLTexture::Depth; - - case QOpenGLTexture::D24S8: - case QOpenGLTexture::D32FS8X24: - return QOpenGLTexture::DepthStencil; - - case QOpenGLTexture::S8: - return QOpenGLTexture::Stencil; - - case QOpenGLTexture::RGB_DXT1: - case QOpenGLTexture::RGBA_DXT1: - case QOpenGLTexture::RGBA_DXT3: - case QOpenGLTexture::RGBA_DXT5: - case QOpenGLTexture::R_ATI1N_UNorm: - case QOpenGLTexture::R_ATI1N_SNorm: - case QOpenGLTexture::RG_ATI2N_UNorm: - case QOpenGLTexture::RG_ATI2N_SNorm: - case QOpenGLTexture::RGB_BP_UNSIGNED_FLOAT: - case QOpenGLTexture::RGB_BP_SIGNED_FLOAT: - case QOpenGLTexture::RGB_BP_UNorm: - case QOpenGLTexture::SRGB8: - case QOpenGLTexture::SRGB8_Alpha8: - case QOpenGLTexture::SRGB_DXT1: - case QOpenGLTexture::SRGB_Alpha_DXT1: - case QOpenGLTexture::SRGB_Alpha_DXT3: - case QOpenGLTexture::SRGB_Alpha_DXT5: - case QOpenGLTexture::SRGB_BP_UNorm: - case QOpenGLTexture::RGB8_ETC1: - return QOpenGLTexture::RGBA; - - case QOpenGLTexture::R11_EAC_UNorm: - case QOpenGLTexture::R11_EAC_SNorm: - return QOpenGLTexture::Red; - - case QOpenGLTexture::RG11_EAC_UNorm: - case QOpenGLTexture::RG11_EAC_SNorm: - return QOpenGLTexture::RG; - - case QOpenGLTexture::RGB8_ETC2: - case QOpenGLTexture::SRGB8_ETC2: - return QOpenGLTexture::RGB; - - case QOpenGLTexture::RGB8_PunchThrough_Alpha1_ETC2: - case QOpenGLTexture::SRGB8_PunchThrough_Alpha1_ETC2: - return QOpenGLTexture::RGBA; - - case QOpenGLTexture::RGBA8_ETC2_EAC: - case QOpenGLTexture::SRGB8_Alpha8_ETC2_EAC: - return QOpenGLTexture::RGBA; - - case QOpenGLTexture::RGBA_ASTC_4x4: - case QOpenGLTexture::RGBA_ASTC_5x4: - case QOpenGLTexture::RGBA_ASTC_5x5: - case QOpenGLTexture::RGBA_ASTC_6x5: - case QOpenGLTexture::RGBA_ASTC_6x6: - case QOpenGLTexture::RGBA_ASTC_8x5: - case QOpenGLTexture::RGBA_ASTC_8x6: - case QOpenGLTexture::RGBA_ASTC_8x8: - case QOpenGLTexture::RGBA_ASTC_10x5: - case QOpenGLTexture::RGBA_ASTC_10x6: - case QOpenGLTexture::RGBA_ASTC_10x8: - case QOpenGLTexture::RGBA_ASTC_10x10: - case QOpenGLTexture::RGBA_ASTC_12x10: - case QOpenGLTexture::RGBA_ASTC_12x12: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_4x4: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_5x4: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_5x5: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_6x5: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_6x6: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_8x5: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_8x6: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_8x8: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_10x5: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_10x6: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_10x8: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_10x10: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_12x10: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_12x12: - return QOpenGLTexture::RGBA; - - case QOpenGLTexture::DepthFormat: - return QOpenGLTexture::Depth; - - case QOpenGLTexture::AlphaFormat: - return QOpenGLTexture::Alpha; - - case QOpenGLTexture::RGBFormat: - return QOpenGLTexture::RGB; - - case QOpenGLTexture::RGBAFormat: - return QOpenGLTexture::RGBA; - - case QOpenGLTexture::LuminanceFormat: - return QOpenGLTexture::Luminance; - - case QOpenGLTexture::LuminanceAlphaFormat: - return QOpenGLTexture::LuminanceAlpha; - } - - Q_UNREACHABLE(); - return QOpenGLTexture::NoSourceFormat; -} - -static QOpenGLTexture::PixelType pixelTypeCompatibleWithInternalFormat(QOpenGLTexture::TextureFormat internalFormat) -{ - switch (internalFormat) { - case QOpenGLTexture::NoFormat: - return QOpenGLTexture::NoPixelType; - - case QOpenGLTexture::R8_UNorm: - case QOpenGLTexture::RG8_UNorm: - case QOpenGLTexture::RGB8_UNorm: - case QOpenGLTexture::RGBA8_UNorm: - case QOpenGLTexture::R16_UNorm: - case QOpenGLTexture::RG16_UNorm: - case QOpenGLTexture::RGB16_UNorm: - case QOpenGLTexture::RGBA16_UNorm: - return QOpenGLTexture::UInt8; - - case QOpenGLTexture::R8_SNorm: - case QOpenGLTexture::RG8_SNorm: - case QOpenGLTexture::RGB8_SNorm: - case QOpenGLTexture::RGBA8_SNorm: - case QOpenGLTexture::R16_SNorm: - case QOpenGLTexture::RG16_SNorm: - case QOpenGLTexture::RGB16_SNorm: - case QOpenGLTexture::RGBA16_SNorm: - return QOpenGLTexture::Int8; - - case QOpenGLTexture::R8U: - case QOpenGLTexture::RG8U: - case QOpenGLTexture::RGB8U: - case QOpenGLTexture::RGBA8U: - case QOpenGLTexture::R16U: - case QOpenGLTexture::RG16U: - case QOpenGLTexture::RGB16U: - case QOpenGLTexture::RGBA16U: - case QOpenGLTexture::R32U: - case QOpenGLTexture::RG32U: - case QOpenGLTexture::RGB32U: - case QOpenGLTexture::RGBA32U: - return QOpenGLTexture::UInt8; - - case QOpenGLTexture::R8I: - case QOpenGLTexture::RG8I: - case QOpenGLTexture::RGB8I: - case QOpenGLTexture::RGBA8I: - case QOpenGLTexture::R16I: - case QOpenGLTexture::RG16I: - case QOpenGLTexture::RGB16I: - case QOpenGLTexture::RGBA16I: - case QOpenGLTexture::R32I: - case QOpenGLTexture::RG32I: - case QOpenGLTexture::RGB32I: - case QOpenGLTexture::RGBA32I: - return QOpenGLTexture::Int8; - - case QOpenGLTexture::R16F: - case QOpenGLTexture::RG16F: - case QOpenGLTexture::RGB16F: - case QOpenGLTexture::RGBA16F: - return QOpenGLTexture::Float16; - - case QOpenGLTexture::R32F: - case QOpenGLTexture::RG32F: - case QOpenGLTexture::RGB32F: - case QOpenGLTexture::RGBA32F: - return QOpenGLTexture::Float32; - - case QOpenGLTexture::RGB9E5: - return QOpenGLTexture::UInt16_RGB5A1_Rev; - - case QOpenGLTexture::RG11B10F: - return QOpenGLTexture::UInt32_RG11B10F; - - case QOpenGLTexture::RG3B2: - return QOpenGLTexture::UInt8_RG3B2; - - case QOpenGLTexture::R5G6B5: - return QOpenGLTexture::UInt16_R5G6B5; - - case QOpenGLTexture::RGB5A1: - return QOpenGLTexture::UInt16_RGB5A1; - - case QOpenGLTexture::RGBA4: - return QOpenGLTexture::UInt16_RGBA4; - - case QOpenGLTexture::RGB10A2: - return QOpenGLTexture::UInt32_RGB10A2; - - case QOpenGLTexture::D16: - return QOpenGLTexture::UInt16; - - case QOpenGLTexture::D24: - case QOpenGLTexture::D32: - return QOpenGLTexture::UInt32; - - case QOpenGLTexture::D32F: - return QOpenGLTexture::Float32; - - case QOpenGLTexture::D24S8: - return QOpenGLTexture::UInt32_D24S8; - - case QOpenGLTexture::D32FS8X24: - return QOpenGLTexture::Float32_D32_UInt32_S8_X24; - - case QOpenGLTexture::S8: - return QOpenGLTexture::UInt8; - - case QOpenGLTexture::RGB_DXT1: - case QOpenGLTexture::RGBA_DXT1: - case QOpenGLTexture::RGBA_DXT3: - case QOpenGLTexture::RGBA_DXT5: - case QOpenGLTexture::R_ATI1N_UNorm: - case QOpenGLTexture::R_ATI1N_SNorm: - case QOpenGLTexture::RG_ATI2N_UNorm: - case QOpenGLTexture::RG_ATI2N_SNorm: - case QOpenGLTexture::RGB_BP_UNSIGNED_FLOAT: - case QOpenGLTexture::RGB_BP_SIGNED_FLOAT: - case QOpenGLTexture::RGB_BP_UNorm: - case QOpenGLTexture::SRGB8: - case QOpenGLTexture::SRGB8_Alpha8: - case QOpenGLTexture::SRGB_DXT1: - case QOpenGLTexture::SRGB_Alpha_DXT1: - case QOpenGLTexture::SRGB_Alpha_DXT3: - case QOpenGLTexture::SRGB_Alpha_DXT5: - case QOpenGLTexture::SRGB_BP_UNorm: - case QOpenGLTexture::R11_EAC_UNorm: - case QOpenGLTexture::R11_EAC_SNorm: - case QOpenGLTexture::RG11_EAC_UNorm: - case QOpenGLTexture::RG11_EAC_SNorm: - case QOpenGLTexture::RGB8_ETC2: - case QOpenGLTexture::SRGB8_ETC2: - case QOpenGLTexture::RGB8_PunchThrough_Alpha1_ETC2: - case QOpenGLTexture::SRGB8_PunchThrough_Alpha1_ETC2: - case QOpenGLTexture::RGBA8_ETC2_EAC: - case QOpenGLTexture::SRGB8_Alpha8_ETC2_EAC: - case QOpenGLTexture::RGB8_ETC1: - case QOpenGLTexture::RGBA_ASTC_4x4: - case QOpenGLTexture::RGBA_ASTC_5x4: - case QOpenGLTexture::RGBA_ASTC_5x5: - case QOpenGLTexture::RGBA_ASTC_6x5: - case QOpenGLTexture::RGBA_ASTC_6x6: - case QOpenGLTexture::RGBA_ASTC_8x5: - case QOpenGLTexture::RGBA_ASTC_8x6: - case QOpenGLTexture::RGBA_ASTC_8x8: - case QOpenGLTexture::RGBA_ASTC_10x5: - case QOpenGLTexture::RGBA_ASTC_10x6: - case QOpenGLTexture::RGBA_ASTC_10x8: - case QOpenGLTexture::RGBA_ASTC_10x10: - case QOpenGLTexture::RGBA_ASTC_12x10: - case QOpenGLTexture::RGBA_ASTC_12x12: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_4x4: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_5x4: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_5x5: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_6x5: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_6x6: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_8x5: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_8x6: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_8x8: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_10x5: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_10x6: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_10x8: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_10x10: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_12x10: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_12x12: - return QOpenGLTexture::UInt8; - - case QOpenGLTexture::DepthFormat: - return QOpenGLTexture::UInt32; - - case QOpenGLTexture::AlphaFormat: - case QOpenGLTexture::RGBFormat: - case QOpenGLTexture::RGBAFormat: - case QOpenGLTexture::LuminanceFormat: - case QOpenGLTexture::LuminanceAlphaFormat: - return QOpenGLTexture::UInt8; - } - - Q_UNREACHABLE(); - return QOpenGLTexture::NoPixelType; -} - -static bool isCompressedFormat(QOpenGLTexture::TextureFormat internalFormat) -{ - switch (internalFormat) { - case QOpenGLTexture::NoFormat: - - case QOpenGLTexture::R8_UNorm: - case QOpenGLTexture::RG8_UNorm: - case QOpenGLTexture::RGB8_UNorm: - case QOpenGLTexture::RGBA8_UNorm: - case QOpenGLTexture::R16_UNorm: - case QOpenGLTexture::RG16_UNorm: - case QOpenGLTexture::RGB16_UNorm: - case QOpenGLTexture::RGBA16_UNorm: - case QOpenGLTexture::R8_SNorm: - case QOpenGLTexture::RG8_SNorm: - case QOpenGLTexture::RGB8_SNorm: - case QOpenGLTexture::RGBA8_SNorm: - case QOpenGLTexture::R16_SNorm: - case QOpenGLTexture::RG16_SNorm: - case QOpenGLTexture::RGB16_SNorm: - case QOpenGLTexture::RGBA16_SNorm: - case QOpenGLTexture::R8U: - case QOpenGLTexture::RG8U: - case QOpenGLTexture::RGB8U: - case QOpenGLTexture::RGBA8U: - case QOpenGLTexture::R16U: - case QOpenGLTexture::RG16U: - case QOpenGLTexture::RGB16U: - case QOpenGLTexture::RGBA16U: - case QOpenGLTexture::R32U: - case QOpenGLTexture::RG32U: - case QOpenGLTexture::RGB32U: - case QOpenGLTexture::RGBA32U: - case QOpenGLTexture::R8I: - case QOpenGLTexture::RG8I: - case QOpenGLTexture::RGB8I: - case QOpenGLTexture::RGBA8I: - case QOpenGLTexture::R16I: - case QOpenGLTexture::RG16I: - case QOpenGLTexture::RGB16I: - case QOpenGLTexture::RGBA16I: - case QOpenGLTexture::R32I: - case QOpenGLTexture::RG32I: - case QOpenGLTexture::RGB32I: - case QOpenGLTexture::RGBA32I: - case QOpenGLTexture::R16F: - case QOpenGLTexture::RG16F: - case QOpenGLTexture::RGB16F: - case QOpenGLTexture::RGBA16F: - case QOpenGLTexture::R32F: - case QOpenGLTexture::RG32F: - case QOpenGLTexture::RGB32F: - case QOpenGLTexture::RGBA32F: - case QOpenGLTexture::RGB9E5: - case QOpenGLTexture::RG11B10F: - case QOpenGLTexture::RG3B2: - case QOpenGLTexture::R5G6B5: - case QOpenGLTexture::RGB5A1: - case QOpenGLTexture::RGBA4: - case QOpenGLTexture::RGB10A2: - - case QOpenGLTexture::D16: - case QOpenGLTexture::D24: - case QOpenGLTexture::D32: - case QOpenGLTexture::D32F: - - case QOpenGLTexture::D24S8: - case QOpenGLTexture::D32FS8X24: - - case QOpenGLTexture::S8: - return false; - - case QOpenGLTexture::RGB_DXT1: - case QOpenGLTexture::RGBA_DXT1: - case QOpenGLTexture::RGBA_DXT3: - case QOpenGLTexture::RGBA_DXT5: - case QOpenGLTexture::R_ATI1N_UNorm: - case QOpenGLTexture::R_ATI1N_SNorm: - case QOpenGLTexture::RG_ATI2N_UNorm: - case QOpenGLTexture::RG_ATI2N_SNorm: - case QOpenGLTexture::RGB_BP_UNSIGNED_FLOAT: - case QOpenGLTexture::RGB_BP_SIGNED_FLOAT: - case QOpenGLTexture::RGB_BP_UNorm: - case QOpenGLTexture::SRGB8: - case QOpenGLTexture::SRGB8_Alpha8: - case QOpenGLTexture::SRGB_DXT1: - case QOpenGLTexture::SRGB_Alpha_DXT1: - case QOpenGLTexture::SRGB_Alpha_DXT3: - case QOpenGLTexture::SRGB_Alpha_DXT5: - case QOpenGLTexture::SRGB_BP_UNorm: - case QOpenGLTexture::R11_EAC_UNorm: - case QOpenGLTexture::R11_EAC_SNorm: - case QOpenGLTexture::RG11_EAC_UNorm: - case QOpenGLTexture::RG11_EAC_SNorm: - case QOpenGLTexture::RGB8_ETC2: - case QOpenGLTexture::SRGB8_ETC2: - case QOpenGLTexture::RGB8_PunchThrough_Alpha1_ETC2: - case QOpenGLTexture::SRGB8_PunchThrough_Alpha1_ETC2: - case QOpenGLTexture::RGBA8_ETC2_EAC: - case QOpenGLTexture::SRGB8_Alpha8_ETC2_EAC: - case QOpenGLTexture::RGB8_ETC1: - case QOpenGLTexture::RGBA_ASTC_4x4: - case QOpenGLTexture::RGBA_ASTC_5x4: - case QOpenGLTexture::RGBA_ASTC_5x5: - case QOpenGLTexture::RGBA_ASTC_6x5: - case QOpenGLTexture::RGBA_ASTC_6x6: - case QOpenGLTexture::RGBA_ASTC_8x5: - case QOpenGLTexture::RGBA_ASTC_8x6: - case QOpenGLTexture::RGBA_ASTC_8x8: - case QOpenGLTexture::RGBA_ASTC_10x5: - case QOpenGLTexture::RGBA_ASTC_10x6: - case QOpenGLTexture::RGBA_ASTC_10x8: - case QOpenGLTexture::RGBA_ASTC_10x10: - case QOpenGLTexture::RGBA_ASTC_12x10: - case QOpenGLTexture::RGBA_ASTC_12x12: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_4x4: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_5x4: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_5x5: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_6x5: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_6x6: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_8x5: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_8x6: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_8x8: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_10x5: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_10x6: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_10x8: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_10x10: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_12x10: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_12x12: - return true; - - case QOpenGLTexture::DepthFormat: - case QOpenGLTexture::AlphaFormat: - case QOpenGLTexture::RGBFormat: - case QOpenGLTexture::RGBAFormat: - case QOpenGLTexture::LuminanceFormat: - case QOpenGLTexture::LuminanceAlphaFormat: - return false; - } - - Q_UNREACHABLE(); - return false; -} - -void QOpenGLTexturePrivate::allocateMutableStorage(QOpenGLTexture::PixelFormat pixelFormat, QOpenGLTexture::PixelType pixelType) -{ - // There is no way to allocate mutable storage for compressed textures in in - // versions older than OpenGL 3.1 and OpenGL ES 3.0, because the older specs - // do not mandate accepting null data pointers for glCompressedTexImage*D, - // unlike glTexImage*D (which in turn does not accept compressed formats). - if (isCompressedFormat(format)) { - storageAllocated = true; - return; - } - - switch (target) { - case QOpenGLTexture::TargetBuffer: - // Buffer textures get their storage from an external OpenGL buffer - qWarning("Buffer textures do not allocate storage"); - return; - - case QOpenGLTexture::Target1D: - if (features.testFlag(QOpenGLTexture::Texture1D)) { - for (int level = 0; level < mipLevels; ++level) - texFuncs->glTextureImage1D(textureId, target, bindingTarget, level, format, - mipLevelSize(level, dimensions[0]), - 0, - pixelFormat, pixelType, nullptr); - } else { - qWarning("1D textures are not supported"); - return; - } - break; - - case QOpenGLTexture::Target1DArray: - if (features.testFlag(QOpenGLTexture::Texture1D) - && features.testFlag(QOpenGLTexture::TextureArrays)) { - for (int level = 0; level < mipLevels; ++level) - texFuncs->glTextureImage2D(textureId, target, bindingTarget, level, format, - mipLevelSize(level, dimensions[0]), - layers, - 0, - pixelFormat, pixelType, nullptr); - } else { - qWarning("1D array textures are not supported"); - return; - } - break; - - case QOpenGLTexture::Target2D: - case QOpenGLTexture::TargetRectangle: - for (int level = 0; level < mipLevels; ++level) - texFuncs->glTextureImage2D(textureId, target, bindingTarget, level, format, - mipLevelSize(level, dimensions[0]), - mipLevelSize(level, dimensions[1]), - 0, - pixelFormat, pixelType, nullptr); - break; - - case QOpenGLTexture::TargetCubeMap: { - // Cubemaps are the odd one out. We have to allocate storage for each - // face and miplevel using the special cubemap face targets rather than - // GL_TARGET_CUBEMAP. - const QOpenGLTexture::CubeMapFace faceTargets[] = { - QOpenGLTexture::CubeMapPositiveX, QOpenGLTexture::CubeMapNegativeX, - QOpenGLTexture::CubeMapPositiveY, QOpenGLTexture::CubeMapNegativeY, - QOpenGLTexture::CubeMapPositiveZ, QOpenGLTexture::CubeMapNegativeZ - }; - - for (int faceTarget = 0; faceTarget < 6; ++faceTarget) { - for (int level = 0; level < mipLevels; ++level) { - texFuncs->glTextureImage2D(textureId, faceTargets[faceTarget], bindingTarget, - level, format, - mipLevelSize(level, dimensions[0]), - mipLevelSize(level, dimensions[1]), - 0, - pixelFormat, pixelType, nullptr); - } - } - break; - } - - case QOpenGLTexture::Target2DArray: - if (features.testFlag(QOpenGLTexture::TextureArrays)) { - for (int level = 0; level < mipLevels; ++level) - texFuncs->glTextureImage3D(textureId, target, bindingTarget, level, format, - mipLevelSize(level, dimensions[0]), - mipLevelSize(level, dimensions[1]), - layers, - 0, - pixelFormat, pixelType, nullptr); - } else { - qWarning("Array textures are not supported"); - return; - } - break; - - case QOpenGLTexture::TargetCubeMapArray: - // Cubemap arrays must specify number of layer-faces (6 * layers) as depth parameter - if (features.testFlag(QOpenGLTexture::TextureCubeMapArrays)) { - for (int level = 0; level < mipLevels; ++level) - texFuncs->glTextureImage3D(textureId, target, bindingTarget, level, format, - mipLevelSize(level, dimensions[0]), - mipLevelSize(level, dimensions[1]), - 6 * layers, - 0, - pixelFormat, pixelType, nullptr); - } else { - qWarning("Cubemap Array textures are not supported"); - return; - } - break; - - case QOpenGLTexture::Target3D: - if (features.testFlag(QOpenGLTexture::Texture3D)) { - for (int level = 0; level < mipLevels; ++level) - texFuncs->glTextureImage3D(textureId, target, bindingTarget, level, format, - mipLevelSize(level, dimensions[0]), - mipLevelSize(level, dimensions[1]), - mipLevelSize(level, dimensions[2]), - 0, - pixelFormat, pixelType, nullptr); - } else { - qWarning("3D textures are not supported"); - return; - } - break; - - case QOpenGLTexture::Target2DMultisample: - if (features.testFlag(QOpenGLTexture::TextureMultisample)) { - texFuncs->glTextureImage2DMultisample(textureId, target, bindingTarget, samples, format, - dimensions[0], dimensions[1], - fixedSamplePositions); - } else { - qWarning("Multisample textures are not supported"); - return; - } - break; - - case QOpenGLTexture::Target2DMultisampleArray: - if (features.testFlag(QOpenGLTexture::TextureMultisample) - && features.testFlag(QOpenGLTexture::TextureArrays)) { - texFuncs->glTextureImage3DMultisample(textureId, target, bindingTarget, samples, format, - dimensions[0], dimensions[1], layers, - fixedSamplePositions); - } else { - qWarning("Multisample array textures are not supported"); - return; - } - break; - } - - storageAllocated = true; -} - -void QOpenGLTexturePrivate::allocateImmutableStorage() -{ - switch (target) { - case QOpenGLTexture::TargetBuffer: - // Buffer textures get their storage from an external OpenGL buffer - qWarning("Buffer textures do not allocate storage"); - return; - - case QOpenGLTexture::Target1D: - if (features.testFlag(QOpenGLTexture::Texture1D)) { - texFuncs->glTextureStorage1D(textureId, target, bindingTarget, mipLevels, format, - dimensions[0]); - } else { - qWarning("1D textures are not supported"); - return; - } - break; - - case QOpenGLTexture::Target1DArray: - if (features.testFlag(QOpenGLTexture::Texture1D) - && features.testFlag(QOpenGLTexture::TextureArrays)) { - texFuncs->glTextureStorage2D(textureId, target, bindingTarget, mipLevels, format, - dimensions[0], layers); - } else { - qWarning("1D array textures are not supported"); - return; - } - break; - - case QOpenGLTexture::Target2D: - case QOpenGLTexture::TargetCubeMap: - case QOpenGLTexture::TargetRectangle: - texFuncs->glTextureStorage2D(textureId, target, bindingTarget, mipLevels, format, - dimensions[0], dimensions[1]); - break; - - case QOpenGLTexture::Target2DArray: - if (features.testFlag(QOpenGLTexture::TextureArrays)) { - texFuncs->glTextureStorage3D(textureId, target, bindingTarget, mipLevels, format, - dimensions[0], dimensions[1], layers); - } else { - qWarning("Array textures are not supported"); - return; - } - break; - - case QOpenGLTexture::TargetCubeMapArray: - // Cubemap arrays must specify number of layer-faces (6 * layers) as depth parameter - if (features.testFlag(QOpenGLTexture::TextureCubeMapArrays)) { - texFuncs->glTextureStorage3D(textureId, target, bindingTarget, mipLevels, format, - dimensions[0], dimensions[1], 6 * layers); - } else { - qWarning("Cubemap Array textures are not supported"); - return; - } - break; - - case QOpenGLTexture::Target3D: - if (features.testFlag(QOpenGLTexture::Texture3D)) { - texFuncs->glTextureStorage3D(textureId, target, bindingTarget, mipLevels, format, - dimensions[0], dimensions[1], dimensions[2]); - } else { - qWarning("3D textures are not supported"); - return; - } - break; - - case QOpenGLTexture::Target2DMultisample: - if (features.testFlag(QOpenGLTexture::ImmutableMultisampleStorage)) { - texFuncs->glTextureStorage2DMultisample(textureId, target, bindingTarget, samples, format, - dimensions[0], dimensions[1], - fixedSamplePositions); - } else { - qWarning("Multisample textures are not supported"); - return; - } - break; - - case QOpenGLTexture::Target2DMultisampleArray: - if (features.testFlag(QOpenGLTexture::ImmutableMultisampleStorage) - && features.testFlag(QOpenGLTexture::TextureArrays)) { - texFuncs->glTextureStorage3DMultisample(textureId, target, bindingTarget, samples, format, - dimensions[0], dimensions[1], layers, - fixedSamplePositions); - } else { - qWarning("Multisample array textures are not supported"); - return; - } - break; - } - - storageAllocated = true; -} - -void QOpenGLTexturePrivate::setData(int mipLevel, int layer, int layerCount, QOpenGLTexture::CubeMapFace cubeFace, - QOpenGLTexture::PixelFormat sourceFormat, QOpenGLTexture::PixelType sourceType, - const void *data, const QOpenGLPixelTransferOptions * const options) -{ - switch (target) { - case QOpenGLTexture::Target1D: - Q_UNUSED(layer); - Q_UNUSED(cubeFace); - Q_UNUSED(layerCount); - texFuncs->glTextureSubImage1D(textureId, target, bindingTarget, mipLevel, - 0, mipLevelSize( mipLevel, dimensions[0] ), - sourceFormat, sourceType, data, options); - break; - - case QOpenGLTexture::Target1DArray: - Q_UNUSED(cubeFace); - texFuncs->glTextureSubImage2D(textureId, target, bindingTarget, mipLevel, - 0, layer, - mipLevelSize(mipLevel, dimensions[0]), - layerCount, - sourceFormat, sourceType, data, options); - break; - - case QOpenGLTexture::Target2D: - Q_UNUSED(layer); - Q_UNUSED(cubeFace); - Q_UNUSED(layerCount); - texFuncs->glTextureSubImage2D(textureId, target, bindingTarget, mipLevel, - 0, 0, - mipLevelSize(mipLevel, dimensions[0]), - mipLevelSize(mipLevel, dimensions[1]), - sourceFormat, sourceType, data, options); - break; - - case QOpenGLTexture::Target2DArray: - Q_UNUSED(cubeFace); - texFuncs->glTextureSubImage3D(textureId, target, bindingTarget, mipLevel, - 0, 0, layer, - mipLevelSize(mipLevel, dimensions[0]), - mipLevelSize(mipLevel, dimensions[1]), - layerCount, - sourceFormat, sourceType, data, options); - break; - - case QOpenGLTexture::Target3D: - Q_UNUSED(cubeFace); - Q_UNUSED(layerCount); - texFuncs->glTextureSubImage3D(textureId, target, bindingTarget, mipLevel, - 0, 0, layer, - mipLevelSize(mipLevel, dimensions[0]), - mipLevelSize(mipLevel, dimensions[1]), - mipLevelSize(mipLevel, dimensions[2]), - sourceFormat, sourceType, data, options); - break; - - case QOpenGLTexture::TargetCubeMap: - Q_UNUSED(layer); - Q_UNUSED(layerCount); - texFuncs->glTextureSubImage2D(textureId, cubeFace, bindingTarget, mipLevel, - 0, 0, - mipLevelSize(mipLevel, dimensions[0]), - mipLevelSize(mipLevel, dimensions[1]), - sourceFormat, sourceType, data, options); - break; - - case QOpenGLTexture::TargetCubeMapArray: { - int faceIndex = cubeFace - QOpenGLTexture::CubeMapPositiveX; - int layerFace = 6 * layer + faceIndex; - texFuncs->glTextureSubImage3D(textureId, target, bindingTarget, mipLevel, - 0, 0, layerFace, - mipLevelSize(mipLevel, dimensions[0]), - mipLevelSize(mipLevel, dimensions[1]), - layerCount, - sourceFormat, sourceType, data, options); - break; - } - - case QOpenGLTexture::TargetRectangle: - Q_UNUSED(mipLevel); - Q_UNUSED(layer); - Q_UNUSED(cubeFace); - Q_UNUSED(layerCount); - texFuncs->glTextureSubImage2D(textureId, target, bindingTarget, 0, - 0, 0, - dimensions[0], - dimensions[1], - sourceFormat, sourceType, data, options); - break; - - case QOpenGLTexture::Target2DMultisample: - case QOpenGLTexture::Target2DMultisampleArray: - case QOpenGLTexture::TargetBuffer: - // We don't upload pixel data for these targets - qWarning("QOpenGLTexture::setData(): Texture target does not support pixel data upload"); - break; - } - - // If requested perform automatic mip map generation - if (mipLevel == 0 && autoGenerateMipMaps && mipLevels > 1) { - Q_Q(QOpenGLTexture); - q->generateMipMaps(); - } -} - -void QOpenGLTexturePrivate::setData(int xOffset, int yOffset, int zOffset, int width, int height, int depth, - int mipLevel, int layer, int layerCount, QOpenGLTexture::CubeMapFace cubeFace, - QOpenGLTexture::PixelFormat sourceFormat, QOpenGLTexture::PixelType sourceType, - const void *data, const QOpenGLPixelTransferOptions * const options) -{ - switch (target) { - case QOpenGLTexture::Target1D: - Q_UNUSED(layer); - Q_UNUSED(cubeFace); - Q_UNUSED(layerCount); - Q_UNUSED(yOffset); - Q_UNUSED(zOffset); - Q_UNUSED(height); - Q_UNUSED(depth); - texFuncs->glTextureSubImage1D(textureId, target, bindingTarget, mipLevel, - xOffset, width, - sourceFormat, sourceType, data, options); - break; - - case QOpenGLTexture::Target1DArray: - Q_UNUSED(cubeFace); - Q_UNUSED(yOffset); - Q_UNUSED(zOffset); - Q_UNUSED(height); - Q_UNUSED(depth); - texFuncs->glTextureSubImage2D(textureId, target, bindingTarget, mipLevel, - xOffset, layer, - width, - layerCount, - sourceFormat, sourceType, data, options); - break; - - case QOpenGLTexture::Target2D: - Q_UNUSED(layer); - Q_UNUSED(cubeFace); - Q_UNUSED(layerCount); - Q_UNUSED(zOffset); - Q_UNUSED(depth); - texFuncs->glTextureSubImage2D(textureId, target, bindingTarget, mipLevel, - xOffset, yOffset, - width, height, - sourceFormat, sourceType, data, options); - break; - - case QOpenGLTexture::Target2DArray: - Q_UNUSED(cubeFace); - Q_UNUSED(zOffset); - Q_UNUSED(depth); - texFuncs->glTextureSubImage3D(textureId, target, bindingTarget, mipLevel, - xOffset, yOffset, layer, - width, height, layerCount, - sourceFormat, sourceType, data, options); - break; - - case QOpenGLTexture::Target3D: - Q_UNUSED(cubeFace); - Q_UNUSED(layerCount); - texFuncs->glTextureSubImage3D(textureId, target, bindingTarget, mipLevel, - xOffset, yOffset, zOffset, - width, height, depth, - sourceFormat, sourceType, data, options); - break; - - case QOpenGLTexture::TargetCubeMap: - Q_UNUSED(layer); - Q_UNUSED(layerCount); - Q_UNUSED(zOffset); - Q_UNUSED(depth); - texFuncs->glTextureSubImage2D(textureId, cubeFace, bindingTarget, mipLevel, - xOffset, yOffset, - width, height, - sourceFormat, sourceType, data, options); - break; - - case QOpenGLTexture::TargetCubeMapArray: { - Q_UNUSED(zOffset); - Q_UNUSED(depth); - int faceIndex = cubeFace - QOpenGLTexture::CubeMapPositiveX; - int layerFace = 6 * layer + faceIndex; - texFuncs->glTextureSubImage3D(textureId, target, bindingTarget, mipLevel, - xOffset, yOffset, layerFace, - width, height, - layerCount, - sourceFormat, sourceType, data, options); - break; - } - - case QOpenGLTexture::TargetRectangle: - Q_UNUSED(mipLevel); - Q_UNUSED(layer); - Q_UNUSED(cubeFace); - Q_UNUSED(layerCount); - Q_UNUSED(zOffset); - Q_UNUSED(depth); - texFuncs->glTextureSubImage2D(textureId, target, bindingTarget, 0, - xOffset, yOffset, - width, height, - sourceFormat, sourceType, data, options); - break; - - case QOpenGLTexture::Target2DMultisample: - case QOpenGLTexture::Target2DMultisampleArray: - case QOpenGLTexture::TargetBuffer: - // We don't upload pixel data for these targets - qWarning("QOpenGLTexture::setData(): Texture target does not support pixel data upload"); - break; - } - - // If requested perform automatic mip map generation - if (mipLevel == 0 && autoGenerateMipMaps && mipLevels > 1) { - Q_Q(QOpenGLTexture); - q->generateMipMaps(); - } -} - - -void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, int layerCount, - QOpenGLTexture::CubeMapFace cubeFace, - int dataSize, const void *data, - const QOpenGLPixelTransferOptions * const options) -{ - if (!isCompressedFormat(format)) { - qWarning("Cannot set compressed data for non-compressed format 0x%x", format); - return; - } - - const bool needsFullSpec = !isUsingImmutableStorage(); // was allocateStorage() a no-op? - - switch (target) { - case QOpenGLTexture::Target1D: - Q_UNUSED(layer); - Q_UNUSED(cubeFace); - Q_UNUSED(layerCount); - if (needsFullSpec) { - texFuncs->glCompressedTextureImage1D(textureId, target, bindingTarget, mipLevel, - format, - mipLevelSize(mipLevel, dimensions[0]), - 0, dataSize, data, options); - } else { - texFuncs->glCompressedTextureSubImage1D(textureId, target, bindingTarget, mipLevel, - 0, mipLevelSize( mipLevel, dimensions[0] ), - format, dataSize, data, options); - } - break; - - case QOpenGLTexture::Target1DArray: - Q_UNUSED(cubeFace); - if (!needsFullSpec) { - texFuncs->glCompressedTextureSubImage2D(textureId, target, bindingTarget, mipLevel, - 0, layer, - mipLevelSize(mipLevel, dimensions[0]), - layerCount, - format, dataSize, data, options); - } - break; - - case QOpenGLTexture::Target2D: - Q_UNUSED(layer); - Q_UNUSED(cubeFace); - Q_UNUSED(layerCount); - if (needsFullSpec) { - texFuncs->glCompressedTextureImage2D(textureId, target, bindingTarget, mipLevel, - format, - mipLevelSize(mipLevel, dimensions[0]), - mipLevelSize(mipLevel, dimensions[1]), - 0, dataSize, data, options); - } else { - texFuncs->glCompressedTextureSubImage2D(textureId, target, bindingTarget, mipLevel, - 0, 0, - mipLevelSize(mipLevel, dimensions[0]), - mipLevelSize(mipLevel, dimensions[1]), - format, dataSize, data, options); - } - break; - - case QOpenGLTexture::Target2DArray: - Q_UNUSED(cubeFace); - if (!needsFullSpec) { - texFuncs->glCompressedTextureSubImage3D(textureId, target, bindingTarget, mipLevel, - 0, 0, layer, - mipLevelSize(mipLevel, dimensions[0]), - mipLevelSize(mipLevel, dimensions[1]), - layerCount, - format, dataSize, data, options); - } - break; - - case QOpenGLTexture::Target3D: - Q_UNUSED(cubeFace); - Q_UNUSED(layerCount); - if (needsFullSpec) { - texFuncs->glCompressedTextureImage3D(textureId, target, bindingTarget, mipLevel, - format, - mipLevelSize(mipLevel, dimensions[0]), - mipLevelSize(mipLevel, dimensions[1]), - mipLevelSize(mipLevel, dimensions[2]), - 0, dataSize, data, options); - } else { - texFuncs->glCompressedTextureSubImage3D(textureId, target, bindingTarget, mipLevel, - 0, 0, layer, - mipLevelSize(mipLevel, dimensions[0]), - mipLevelSize(mipLevel, dimensions[1]), - mipLevelSize(mipLevel, dimensions[2]), - format, dataSize, data, options); - } - break; - - case QOpenGLTexture::TargetCubeMap: - Q_UNUSED(layer); - Q_UNUSED(layerCount); - if (needsFullSpec) { - texFuncs->glCompressedTextureImage2D(textureId, cubeFace, bindingTarget, mipLevel, - format, - mipLevelSize(mipLevel, dimensions[0]), - mipLevelSize(mipLevel, dimensions[1]), - 0, dataSize, data, options); - } else { - texFuncs->glCompressedTextureSubImage2D(textureId, cubeFace, bindingTarget, mipLevel, - 0, 0, - mipLevelSize(mipLevel, dimensions[0]), - mipLevelSize(mipLevel, dimensions[1]), - format, dataSize, data, options); - } - break; - - case QOpenGLTexture::TargetCubeMapArray: { - int faceIndex = cubeFace - QOpenGLTexture::CubeMapPositiveX; - int layerFace = 6 * layer + faceIndex; - if (!needsFullSpec) { - texFuncs->glCompressedTextureSubImage3D(textureId, target, bindingTarget, mipLevel, - 0, 0, layerFace, - mipLevelSize(mipLevel, dimensions[0]), - mipLevelSize(mipLevel, dimensions[1]), - layerCount, - format, dataSize, data, options); - } - break; - } - - case QOpenGLTexture::TargetRectangle: - case QOpenGLTexture::Target2DMultisample: - case QOpenGLTexture::Target2DMultisampleArray: - case QOpenGLTexture::TargetBuffer: - // We don't upload pixel data for these targets - qWarning("QOpenGLTexture::setCompressedData(): Texture target does not support pixel data upload"); - break; - } - - // If requested perform automatic mip map generation - if (mipLevel == 0 && autoGenerateMipMaps && mipLevels > 1) { - Q_Q(QOpenGLTexture); - q->generateMipMaps(); - } -} - -void QOpenGLTexturePrivate::setWrapMode(QOpenGLTexture::WrapMode mode) -{ - switch (target) { - case QOpenGLTexture::Target1D: - case QOpenGLTexture::Target1DArray: - case QOpenGLTexture::TargetBuffer: - wrapModes[0] = mode; - texFuncs->glTextureParameteri(textureId, target, bindingTarget, GL_TEXTURE_WRAP_S, mode); - break; - - case QOpenGLTexture::Target2D: - case QOpenGLTexture::Target2DArray: - case QOpenGLTexture::TargetCubeMap: - case QOpenGLTexture::TargetCubeMapArray: - case QOpenGLTexture::Target2DMultisample: - case QOpenGLTexture::Target2DMultisampleArray: - case QOpenGLTexture::TargetRectangle: - wrapModes[0] = wrapModes[1] = mode; - texFuncs->glTextureParameteri(textureId, target, bindingTarget, GL_TEXTURE_WRAP_S, mode); - texFuncs->glTextureParameteri(textureId, target, bindingTarget, GL_TEXTURE_WRAP_T, mode); - break; - - case QOpenGLTexture::Target3D: - wrapModes[0] = wrapModes[1] = wrapModes[2] = mode; - texFuncs->glTextureParameteri(textureId, target, bindingTarget, GL_TEXTURE_WRAP_S, mode); - texFuncs->glTextureParameteri(textureId, target, bindingTarget, GL_TEXTURE_WRAP_T, mode); - texFuncs->glTextureParameteri(textureId, target, bindingTarget, GL_TEXTURE_WRAP_R, mode); - break; - } -} - -void QOpenGLTexturePrivate::setWrapMode(QOpenGLTexture::CoordinateDirection direction, QOpenGLTexture::WrapMode mode) -{ - switch (target) { - case QOpenGLTexture::Target1D: - case QOpenGLTexture::Target1DArray: - case QOpenGLTexture::TargetBuffer: - switch (direction) { - case QOpenGLTexture::DirectionS: - wrapModes[0] = mode; - texFuncs->glTextureParameteri(textureId, target, bindingTarget, GL_TEXTURE_WRAP_S, mode); - break; - - case QOpenGLTexture::DirectionT: - case QOpenGLTexture::DirectionR: - qWarning("QOpenGLTexture::setWrapMode() direction not valid for this texture target"); - break; - } - break; - - case QOpenGLTexture::Target2D: - case QOpenGLTexture::Target2DArray: - case QOpenGLTexture::TargetCubeMap: - case QOpenGLTexture::TargetCubeMapArray: - case QOpenGLTexture::Target2DMultisample: - case QOpenGLTexture::Target2DMultisampleArray: - case QOpenGLTexture::TargetRectangle: - switch (direction) { - case QOpenGLTexture::DirectionS: - wrapModes[0] = mode; - texFuncs->glTextureParameteri(textureId, target, bindingTarget, GL_TEXTURE_WRAP_S, mode); - break; - - case QOpenGLTexture::DirectionT: - wrapModes[1] = mode; - texFuncs->glTextureParameteri(textureId, target, bindingTarget, GL_TEXTURE_WRAP_T, mode); - break; - - case QOpenGLTexture::DirectionR: - qWarning("QOpenGLTexture::setWrapMode() direction not valid for this texture target"); - break; - } - break; - - case QOpenGLTexture::Target3D: - switch (direction) { - case QOpenGLTexture::DirectionS: - wrapModes[0] = mode; - texFuncs->glTextureParameteri(textureId, target, bindingTarget, direction, mode); - break; - - case QOpenGLTexture::DirectionT: - wrapModes[1] = mode; - texFuncs->glTextureParameteri(textureId, target, bindingTarget, direction, mode); - break; - - case QOpenGLTexture::DirectionR: - wrapModes[2] = mode; - texFuncs->glTextureParameteri(textureId, target, bindingTarget, direction, mode); - break; - } - break; - } -} - -QOpenGLTexture::WrapMode QOpenGLTexturePrivate::wrapMode(QOpenGLTexture::CoordinateDirection direction) const -{ - switch (target) { - case QOpenGLTexture::Target1D: - case QOpenGLTexture::Target1DArray: - case QOpenGLTexture::TargetBuffer: - switch (direction) { - case QOpenGLTexture::DirectionS: - return wrapModes[0]; - - case QOpenGLTexture::DirectionT: - case QOpenGLTexture::DirectionR: - qWarning("QOpenGLTexture::wrapMode() direction not valid for this texture target"); - return QOpenGLTexture::Repeat; - } - break; - - case QOpenGLTexture::Target2D: - case QOpenGLTexture::Target2DArray: - case QOpenGLTexture::TargetCubeMap: - case QOpenGLTexture::TargetCubeMapArray: - case QOpenGLTexture::Target2DMultisample: - case QOpenGLTexture::Target2DMultisampleArray: - case QOpenGLTexture::TargetRectangle: - switch (direction) { - case QOpenGLTexture::DirectionS: - return wrapModes[0]; - - case QOpenGLTexture::DirectionT: - return wrapModes[1]; - - case QOpenGLTexture::DirectionR: - qWarning("QOpenGLTexture::wrapMode() direction not valid for this texture target"); - return QOpenGLTexture::Repeat; - } - break; - - case QOpenGLTexture::Target3D: - switch (direction) { - case QOpenGLTexture::DirectionS: - return wrapModes[0]; - - case QOpenGLTexture::DirectionT: - return wrapModes[1]; - - case QOpenGLTexture::DirectionR: - return wrapModes[2]; - } - break; - } - // Should never get here - Q_ASSERT(false); - return QOpenGLTexture::Repeat; -} - -QOpenGLTexture *QOpenGLTexturePrivate::createTextureView(QOpenGLTexture::Target viewTarget, - QOpenGLTexture::TextureFormat viewFormat, - int minimumMipmapLevel, int maximumMipmapLevel, - int minimumLayer, int maximumLayer) const -{ - // Do sanity checks - see http://www.opengl.org/wiki/GLAPI/glTextureView - - // Check the targets are compatible - bool viewTargetCompatible = false; - switch (target) { - case QOpenGLTexture::Target1D: - case QOpenGLTexture::Target1DArray: - viewTargetCompatible = (viewTarget == QOpenGLTexture::Target1D - || viewTarget == QOpenGLTexture::Target1DArray); - break; - - - case QOpenGLTexture::Target2D: - case QOpenGLTexture::Target2DArray: - viewTargetCompatible = (viewTarget == QOpenGLTexture::Target2D - || viewTarget == QOpenGLTexture::Target2DArray); - break; - - case QOpenGLTexture::Target3D: - viewTargetCompatible = (viewTarget == QOpenGLTexture::Target3D); - break; - - case QOpenGLTexture::TargetCubeMap: - case QOpenGLTexture::TargetCubeMapArray: - viewTargetCompatible = (viewTarget == QOpenGLTexture::TargetCubeMap - || viewTarget == QOpenGLTexture::Target2D - || viewTarget == QOpenGLTexture::Target2DArray - || viewTarget == QOpenGLTexture::TargetCubeMapArray); - break; - - case QOpenGLTexture::Target2DMultisample: - case QOpenGLTexture::Target2DMultisampleArray: - viewTargetCompatible = (viewTarget == QOpenGLTexture::Target2DMultisample - || viewTarget == QOpenGLTexture::Target2DMultisampleArray); - break; - - case QOpenGLTexture::TargetRectangle: - viewTargetCompatible = (viewTarget == QOpenGLTexture::TargetRectangle); - break; - - case QOpenGLTexture::TargetBuffer: - // Cannot be used with texture views - break; - } - - if (!viewTargetCompatible) { - qWarning("QOpenGLTexture::createTextureView(): Incompatible source and view targets"); - return nullptr; - } - - // Check the formats are compatible - bool viewFormatCompatible = false; - switch (formatClass) { - case QOpenGLTexture::NoFormatClass: - break; - - case QOpenGLTexture::FormatClass_128Bit: - viewFormatCompatible = (viewFormat == QOpenGLTexture::RGBA32F - || viewFormat == QOpenGLTexture::RGBA32U - || viewFormat == QOpenGLTexture::RGBA32I); - break; - - case QOpenGLTexture::FormatClass_96Bit: - viewFormatCompatible = (viewFormat == QOpenGLTexture::RGB32F - || viewFormat == QOpenGLTexture::RGB32U - || viewFormat == QOpenGLTexture::RGB32I); - break; - - case QOpenGLTexture::FormatClass_64Bit: - viewFormatCompatible = (viewFormat == QOpenGLTexture::RGBA16F - || viewFormat == QOpenGLTexture::RG32F - || viewFormat == QOpenGLTexture::RGBA16U - || viewFormat == QOpenGLTexture::RG32U - || viewFormat == QOpenGLTexture::RGBA16I - || viewFormat == QOpenGLTexture::RG32I - || viewFormat == QOpenGLTexture::RGBA16_UNorm - || viewFormat == QOpenGLTexture::RGBA16_SNorm); - break; - - case QOpenGLTexture::FormatClass_48Bit: - viewFormatCompatible = (viewFormat == QOpenGLTexture::RGB16_UNorm - || viewFormat == QOpenGLTexture::RGB16_SNorm - || viewFormat == QOpenGLTexture::RGB16F - || viewFormat == QOpenGLTexture::RGB16U - || viewFormat == QOpenGLTexture::RGB16I); - break; - - case QOpenGLTexture::FormatClass_32Bit: - viewFormatCompatible = (viewFormat == QOpenGLTexture::RG16F - || viewFormat == QOpenGLTexture::RG11B10F - || viewFormat == QOpenGLTexture::R32F - || viewFormat == QOpenGLTexture::RGB10A2 - || viewFormat == QOpenGLTexture::RGBA8U - || viewFormat == QOpenGLTexture::RG16U - || viewFormat == QOpenGLTexture::R32U - || viewFormat == QOpenGLTexture::RGBA8I - || viewFormat == QOpenGLTexture::RG16I - || viewFormat == QOpenGLTexture::R32I - || viewFormat == QOpenGLTexture::RGBA8_UNorm - || viewFormat == QOpenGLTexture::RG16_UNorm - || viewFormat == QOpenGLTexture::RGBA8_SNorm - || viewFormat == QOpenGLTexture::RG16_SNorm - || viewFormat == QOpenGLTexture::SRGB8_Alpha8 - || viewFormat == QOpenGLTexture::RGB9E5); - break; - - case QOpenGLTexture::FormatClass_24Bit: - viewFormatCompatible = (viewFormat == QOpenGLTexture::RGB8_UNorm - || viewFormat == QOpenGLTexture::RGB8_SNorm - || viewFormat == QOpenGLTexture::SRGB8 - || viewFormat == QOpenGLTexture::RGB8U - || viewFormat == QOpenGLTexture::RGB8I); - break; - - case QOpenGLTexture::FormatClass_16Bit: - viewFormatCompatible = (viewFormat == QOpenGLTexture::R16F - || viewFormat == QOpenGLTexture::RG8U - || viewFormat == QOpenGLTexture::R16U - || viewFormat == QOpenGLTexture::RG8I - || viewFormat == QOpenGLTexture::R16I - || viewFormat == QOpenGLTexture::RG8_UNorm - || viewFormat == QOpenGLTexture::R16_UNorm - || viewFormat == QOpenGLTexture::RG8_SNorm - || viewFormat == QOpenGLTexture::R16_SNorm); - break; - - case QOpenGLTexture::FormatClass_8Bit: - viewFormatCompatible = (viewFormat == QOpenGLTexture::R8U - || viewFormat == QOpenGLTexture::R8I - || viewFormat == QOpenGLTexture::R8_UNorm - || viewFormat == QOpenGLTexture::R8_SNorm); - break; - - case QOpenGLTexture::FormatClass_RGTC1_R: - viewFormatCompatible = (viewFormat == QOpenGLTexture::R_ATI1N_UNorm - || viewFormat == QOpenGLTexture::R_ATI1N_SNorm); - break; - - case QOpenGLTexture::FormatClass_RGTC2_RG: - viewFormatCompatible = (viewFormat == QOpenGLTexture::RG_ATI2N_UNorm - || viewFormat == QOpenGLTexture::RG_ATI2N_SNorm); - break; - - case QOpenGLTexture::FormatClass_BPTC_Unorm: - viewFormatCompatible = (viewFormat == QOpenGLTexture::RGB_BP_UNorm - || viewFormat == QOpenGLTexture::SRGB_BP_UNorm); - break; - - case QOpenGLTexture::FormatClass_BPTC_Float: - viewFormatCompatible = (viewFormat == QOpenGLTexture::RGB_BP_UNSIGNED_FLOAT - || viewFormat == QOpenGLTexture::RGB_BP_SIGNED_FLOAT); - break; - - case QOpenGLTexture::FormatClass_S3TC_DXT1_RGB: - viewFormatCompatible = (viewFormat == QOpenGLTexture::RGB_DXT1 - || viewFormat == QOpenGLTexture::SRGB_DXT1); - break; - - case QOpenGLTexture::FormatClass_S3TC_DXT1_RGBA: - viewFormatCompatible = (viewFormat == QOpenGLTexture::RGBA_DXT1 - || viewFormat == QOpenGLTexture::SRGB_Alpha_DXT1); - break; - - case QOpenGLTexture::FormatClass_S3TC_DXT3_RGBA: - viewFormatCompatible = (viewFormat == QOpenGLTexture::RGBA_DXT3 - || viewFormat == QOpenGLTexture::SRGB_Alpha_DXT3); - break; - - case QOpenGLTexture::FormatClass_S3TC_DXT5_RGBA: - viewFormatCompatible = (viewFormat == QOpenGLTexture::RGBA_DXT5 - || viewFormat == QOpenGLTexture::SRGB_Alpha_DXT5); - break; - - case QOpenGLTexture::FormatClass_Unique: - viewFormatCompatible = (viewFormat == format); - break; - } - - if (!viewFormatCompatible) { - qWarning("QOpenGLTexture::createTextureView(): Incompatible source and view formats"); - return nullptr; - } - - - // Create a view - QOpenGLTexture *view = new QOpenGLTexture(viewTarget); - view->setFormat(viewFormat); - view->create(); - view->d_ptr->textureView = true; - texFuncs->glTextureView(view->textureId(), viewTarget, textureId, viewFormat, - minimumMipmapLevel, maximumMipmapLevel - minimumMipmapLevel + 1, - minimumLayer, maximumLayer - minimumLayer + 1); - return view; -} - - -/*! - \class QOpenGLTexture - \inmodule QtGui - \since 5.2 - \wrapper - \brief The QOpenGLTexture class encapsulates an OpenGL texture object. - - QOpenGLTexture makes it easy to work with OpenGL textures and the myriad features - and targets that they offer depending upon the capabilities of your OpenGL implementation. - - The typical usage pattern for QOpenGLTexture is - \list - \li Instantiate the object specifying the texture target type - \li Set properties that affect the storage requirements e.g. storage format, dimensions - \li Allocate the server-side storage - \li Optionally upload pixel data - \li Optionally set any additional properties e.g. filtering and border options - \li Render with texture or render to texture - \endlist - - In the common case of simply using a QImage as the source of texture pixel data - most of the above steps are performed automatically. - - \code - // Prepare texture - QOpenGLTexture *texture = new QOpenGLTexture(QImage(fileName).mirrored()); - texture->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); - texture->setMagnificationFilter(QOpenGLTexture::Linear); - ... - // Render with texture - texture->bind(); - glDrawArrays(...); - \endcode - - Note that the QImage is mirrored vertically to account for the fact that - OpenGL and QImage use opposite directions for the y axis. Another option - would be to transform your texture coordinates. -*/ - -/*! - \enum QOpenGLTexture::Filter - This enum defines the filtering parameters for a QOpenGLTexture object. - \value Nearest Equivalent to GL_NEAREST - \value Linear Equivalent to GL_LINEAR - \value NearestMipMapNearest Equivalent to GL_NEAREST_MIPMAP_NEAREST - \value NearestMipMapLinear Equivalent to GL_NEAREST_MIPMAP_LINEAR - \value LinearMipMapNearest Equivalent to GL_LINEAR_MIPMAP_NEAREST - \value LinearMipMapLinear Equivalent to GL_LINEAR_MIPMAP_LINEAR -*/ - -/*! - \enum QOpenGLTexture::Target - This enum defines the texture target of a QOpenGLTexture object. - For more information on creating array textures, see \l{Array Texture}. - - \value Target1D A 1-dimensional texture. - Equivalent to GL_TEXTURE_1D. - \value Target1DArray An array of 1-dimensional textures. - Equivalent to GL_TEXTURE_1D_ARRAY - \value Target2D A 2-dimensional texture. - Equivalent to GL_TEXTURE_2D - \value Target2DArray An array of 2-dimensional textures. - Equivalent to GL_TEXTURE_2D_ARRAY - \value Target3D A 3-dimensional texture. - Equivalent to GL_TEXTURE_3D - \value TargetCubeMap A cubemap texture. - Equivalent to GL_TEXTURE_CUBE_MAP - \value TargetCubeMapArray An array of cubemap textures. - Equivalent to GL_TEXTURE_CUBE_MAP_ARRAY - \value Target2DMultisample A 2-dimensional texture with multisample support. - Equivalent to GL_TEXTURE_2D_MULTISAMPLE - \value Target2DMultisampleArray An array of 2-dimensional textures with multisample support. - Equivalent to GL_TEXTURE_2D_MULTISAMPLE_ARRAY - \value TargetRectangle A rectangular 2-dimensional texture. - Equivalent to GL_TEXTURE_RECTANGLE - \value TargetBuffer A texture with data from an OpenGL buffer object. - Equivalent to GL_TEXTURE_BUFFER -*/ - -/*! - \enum QOpenGLTexture::BindingTarget - This enum defines the possible binding targets of texture units. - - \value BindingTarget1D Equivalent to GL_TEXTURE_BINDING_1D - \value BindingTarget1DArray Equivalent to GL_TEXTURE_BINDING_1D_ARRAY - \value BindingTarget2D Equivalent to GL_TEXTURE_BINDING_2D - \value BindingTarget2DArray Equivalent to GL_TEXTURE_BINDING_2D_ARRAY - \value BindingTarget3D Equivalent to GL_TEXTURE_BINDING_3D - \value BindingTargetCubeMap Equivalent to GL_TEXTURE_BINDING_CUBE_MAP - \value BindingTargetCubeMapArray Equivalent to GL_TEXTURE_BINDING_CUBE_MAP_ARRAY - \value BindingTarget2DMultisample Equivalent to GL_TEXTURE_BINDING_2D_MULTISAMPLE - \value BindingTarget2DMultisampleArray Equivalent to GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY - \value BindingTargetRectangle Equivalent to GL_TEXTURE_BINDING_RECTANGLE - \value BindingTargetBuffer Equivalent to GL_TEXTURE_BINDING_BUFFER -*/ - -/*! - \enum QOpenGLTexture::MipMapGeneration - This enum defines the options to control mipmap generation. - - \value GenerateMipMaps Mipmaps should be generated - \value DontGenerateMipMaps Mipmaps should not be generated -*/ - -/*! - \enum QOpenGLTexture::TextureUnitReset - This enum defines options ot control texture unit activation. - - \value ResetTextureUnit The previous active texture unit will be reset - \value DontResetTextureUnit The previous active texture unit will not be rest -*/ - -/*! - \enum QOpenGLTexture::TextureFormat - This enum defines the possible texture formats. Depending upon your OpenGL - implementation only a subset of these may be supported. - - \value NoFormat Equivalent to GL_NONE - - \value R8_UNorm Equivalent to GL_R8 - \value RG8_UNorm Equivalent to GL_RG8 - \value RGB8_UNorm Equivalent to GL_RGB8 - \value RGBA8_UNorm Equivalent to GL_RGBA8 - - \value R16_UNorm Equivalent to GL_R16 - \value RG16_UNorm Equivalent to GL_RG16 - \value RGB16_UNorm Equivalent to GL_RGB16 - \value RGBA16_UNorm Equivalent to GL_RGBA16 - - \value R8_SNorm Equivalent to GL_R8_SNORM - \value RG8_SNorm Equivalent to GL_RG8_SNORM - \value RGB8_SNorm Equivalent to GL_RGB8_SNORM - \value RGBA8_SNorm Equivalent to GL_RGBA8_SNORM - - \value R16_SNorm Equivalent to GL_R16_SNORM - \value RG16_SNorm Equivalent to GL_RG16_SNORM - \value RGB16_SNorm Equivalent to GL_RGB16_SNORM - \value RGBA16_SNorm Equivalent to GL_RGBA16_SNORM - - \value R8U Equivalent to GL_R8UI - \value RG8U Equivalent to GL_RG8UI - \value RGB8U Equivalent to GL_RGB8UI - \value RGBA8U Equivalent to GL_RGBA8UI - - \value R16U Equivalent to GL_R16UI - \value RG16U Equivalent to GL_RG16UI - \value RGB16U Equivalent to GL_RGB16UI - \value RGBA16U Equivalent to GL_RGBA16UI - - \value R32U Equivalent to GL_R32UI - \value RG32U Equivalent to GL_RG32UI - \value RGB32U Equivalent to GL_RGB32UI - \value RGBA32U Equivalent to GL_RGBA32UI - - \value R8I Equivalent to GL_R8I - \value RG8I Equivalent to GL_RG8I - \value RGB8I Equivalent to GL_RGB8I - \value RGBA8I Equivalent to GL_RGBA8I - - \value R16I Equivalent to GL_R16I - \value RG16I Equivalent to GL_RG16I - \value RGB16I Equivalent to GL_RGB16I - \value RGBA16I Equivalent to GL_RGBA16I - - \value R32I Equivalent to GL_R32I - \value RG32I Equivalent to GL_RG32I - \value RGB32I Equivalent to GL_RGB32I - \value RGBA32I Equivalent to GL_RGBA32I - - \value R16F Equivalent to GL_R16F - \value RG16F Equivalent to GL_RG16F - \value RGB16F Equivalent to GL_RGB16F - \value RGBA16F Equivalent to GL_RGBA16F - - \value R32F Equivalent to GL_R32F - \value RG32F Equivalent to GL_RG32F - \value RGB32F Equivalent to GL_RGB32F - \value RGBA32F Equivalent to GL_RGBA32F - - \value RGB9E5 Equivalent to GL_RGB9_E5 - \value RG11B10F Equivalent to GL_R11F_G11F_B10F - \value RG3B2 Equivalent to GL_R3_G3_B2 - \value R5G6B5 Equivalent to GL_RGB565 - \value RGB5A1 Equivalent to GL_RGB5_A1 - \value RGBA4 Equivalent to GL_RGBA4 - \value RGB10A2 Equivalent to GL_RGB10_A2UI - - \value D16 Equivalent to GL_DEPTH_COMPONENT16 - \value D24 Equivalent to GL_DEPTH_COMPONENT24 - \value D24S8 Equivalent to GL_DEPTH24_STENCIL8 - \value D32 Equivalent to GL_DEPTH_COMPONENT32 - \value D32F Equivalent to GL_DEPTH_COMPONENT32F - \value D32FS8X24 Equivalent to GL_DEPTH32F_STENCIL8 - \value S8 Equivalent to GL_STENCIL_INDEX8. Introduced in Qt 5.4 - - \value RGB_DXT1 Equivalent to GL_COMPRESSED_RGB_S3TC_DXT1_EXT - \value RGBA_DXT1 Equivalent to GL_COMPRESSED_RGBA_S3TC_DXT1_EXT - \value RGBA_DXT3 Equivalent to GL_COMPRESSED_RGBA_S3TC_DXT3_EXT - \value RGBA_DXT5 Equivalent to GL_COMPRESSED_RGBA_S3TC_DXT5_EXT - \value R_ATI1N_UNorm Equivalent to GL_COMPRESSED_RED_RGTC1 - \value R_ATI1N_SNorm Equivalent to GL_COMPRESSED_SIGNED_RED_RGTC1 - \value RG_ATI2N_UNorm Equivalent to GL_COMPRESSED_RG_RGTC2 - \value RG_ATI2N_SNorm Equivalent to GL_COMPRESSED_SIGNED_RG_RGTC2 - \value RGB_BP_UNSIGNED_FLOAT Equivalent to GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB - \value RGB_BP_SIGNED_FLOAT Equivalent to GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB - \value RGB_BP_UNorm Equivalent to GL_COMPRESSED_RGBA_BPTC_UNORM_ARB - \value R11_EAC_UNorm Equivalent to GL_COMPRESSED_R11_EAC - \value R11_EAC_SNorm Equivalent to GL_COMPRESSED_SIGNED_R11_EAC - \value RG11_EAC_UNorm Equivalent to GL_COMPRESSED_RG11_EAC - \value RG11_EAC_SNorm Equivalent to GL_COMPRESSED_SIGNED_RG11_EAC - \value RGB8_ETC2 Equivalent to GL_COMPRESSED_RGB8_ETC2 - \value SRGB8_ETC2 Equivalent to GL_COMPRESSED_SRGB8_ETC2 - \value RGB8_PunchThrough_Alpha1_ETC2 Equivalent to GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 - \value SRGB8_PunchThrough_Alpha1_ETC2 Equivalent to GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 - \value RGBA8_ETC2_EAC Equivalent to GL_COMPRESSED_RGBA8_ETC2_EAC - \value SRGB8_Alpha8_ETC2_EAC Equivalent to GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC - \value RGB8_ETC1 Equivalent to GL_ETC1_RGB8_OES - \value RGBA_ASTC_4x4 Equivalent to GL_COMPRESSED_RGBA_ASTC_4x4_KHR - \value RGBA_ASTC_5x4 Equivalent to GL_COMPRESSED_RGBA_ASTC_5x4_KHR - \value RGBA_ASTC_5x5 Equivalent to GL_COMPRESSED_RGBA_ASTC_5x5_KHR - \value RGBA_ASTC_6x5 Equivalent to GL_COMPRESSED_RGBA_ASTC_6x5_KHR - \value RGBA_ASTC_6x6 Equivalent to GL_COMPRESSED_RGBA_ASTC_6x6_KHR - \value RGBA_ASTC_8x5 Equivalent to GL_COMPRESSED_RGBA_ASTC_8x5_KHR - \value RGBA_ASTC_8x6 Equivalent to GL_COMPRESSED_RGBA_ASTC_8x6_KHR - \value RGBA_ASTC_8x8 Equivalent to GL_COMPRESSED_RGBA_ASTC_8x8_KHR - \value RGBA_ASTC_10x5 Equivalent to GL_COMPRESSED_RGBA_ASTC_10x5_KHR - \value RGBA_ASTC_10x6 Equivalent to GL_COMPRESSED_RGBA_ASTC_10x6_KHR - \value RGBA_ASTC_10x8 Equivalent to GL_COMPRESSED_RGBA_ASTC_10x8_KHR - \value RGBA_ASTC_10x10 Equivalent to GL_COMPRESSED_RGBA_ASTC_10x10_KHR - \value RGBA_ASTC_12x10 Equivalent to GL_COMPRESSED_RGBA_ASTC_12x10_KHR - \value RGBA_ASTC_12x12 Equivalent to GL_COMPRESSED_RGBA_ASTC_12x12_KHR - \value SRGB8_Alpha8_ASTC_4x4 Equivalent to GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR - \value SRGB8_Alpha8_ASTC_5x4 Equivalent to GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR - \value SRGB8_Alpha8_ASTC_5x5 Equivalent to GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR - \value SRGB8_Alpha8_ASTC_6x5 Equivalent to GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR - \value SRGB8_Alpha8_ASTC_6x6 Equivalent to GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR - \value SRGB8_Alpha8_ASTC_8x5 Equivalent to GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR - \value SRGB8_Alpha8_ASTC_8x6 Equivalent to GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR - \value SRGB8_Alpha8_ASTC_8x8 Equivalent to GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR - \value SRGB8_Alpha8_ASTC_10x5 Equivalent to GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR - \value SRGB8_Alpha8_ASTC_10x6 Equivalent to GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR - \value SRGB8_Alpha8_ASTC_10x8 Equivalent to GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR - \value SRGB8_Alpha8_ASTC_10x10 Equivalent to GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR - \value SRGB8_Alpha8_ASTC_12x10 Equivalent to GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR - \value SRGB8_Alpha8_ASTC_12x12 Equivalent to GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR - - \value SRGB8 Equivalent to GL_SRGB8 - \value SRGB8_Alpha8 Equivalent to GL_SRGB8_ALPHA8 - \value SRGB_DXT1 Equivalent to GL_COMPRESSED_SRGB_S3TC_DXT1_EXT - \value SRGB_Alpha_DXT1 Equivalent to GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT - \value SRGB_Alpha_DXT3 Equivalent to GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT - \value SRGB_Alpha_DXT5 Equivalent to GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT - \value SRGB_BP_UNorm Equivalent to GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB - - \value DepthFormat Equivalent to GL_DEPTH_COMPONENT (only OpenGL ES 3 or ES 2 with OES_depth_texture) - \value AlphaFormat Equivalent to GL_ALPHA (OpenGL ES 2 only) - \value RGBFormat Equivalent to GL_RGB (OpenGL ES 2 only) - \value RGBAFormat Equivalent to GL_RGBA (OpenGL ES 2 only) - \value LuminanceFormat Equivalent to GL_LUMINANCE (OpenGL ES 2 only) - \value LuminanceAlphaFormat Equivalent to GL_LUMINANCE_ALPHA (OpenGL ES 2 only) -*/ - -/*! - \enum QOpenGLTexture::CubeMapFace - This enum defines the possible CubeMap faces. - - \value CubeMapPositiveX Equivalent to GL_TEXTURE_CUBE_MAP_POSITIVE_X - \value CubeMapNegativeX Equivalent to GL_TEXTURE_CUBE_MAP_NEGATIVE_X - \value CubeMapPositiveY Equivalent to GL_TEXTURE_CUBE_MAP_POSITIVE_Y - \value CubeMapNegativeY Equivalent to GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - \value CubeMapPositiveZ Equivalent to GL_TEXTURE_CUBE_MAP_POSITIVE_Z - \value CubeMapNegativeZ Equivalent to GL_TEXTURE_CUBE_MAP_NEGATIVE_Z -*/ - -/*! - \enum QOpenGLTexture::PixelFormat - This enum defines the possible client-side pixel formats for a pixel - transfer operation. - - \value NoSourceFormat Equivalent to GL_NONE - \value Red Equivalent to GL_RED - \value RG Equivalent to GL_RG - \value RGB Equivalent to GL_RGB - \value BGR Equivalent to GL_BGR - \value RGBA Equivalent to GL_RGBA - \value BGRA Equivalent to GL_BGRA - \value Red_Integer Equivalent to GL_RED_INTEGER - \value RG_Integer Equivalent to GL_RG_INTEGER - \value RGB_Integer Equivalent to GL_RGB_INTEGER - \value BGR_Integer Equivalent to GL_BGR_INTEGER - \value RGBA_Integer Equivalent to GL_RGBA_INTEGER - \value BGRA_Integer Equivalent to GL_BGRA_INTEGER - \value Stencil Equivalent to GL_STENCIL_INDEX. Introduced in Qt 5.4 - \value Depth Equivalent to GL_DEPTH_COMPONENT - \value DepthStencil Equivalent to GL_DEPTH_STENCIL - \value Alpha Equivalent to GL_ALPHA (OpenGL ES 2 only) - \value Luminance Equivalent to GL_LUMINANCE (OpenGL ES 2 only) - \value LuminanceAlpha Equivalent to GL_LUMINANCE_ALPHA (OpenGL ES 2 only) - -*/ - -/*! - \enum QOpenGLTexture::PixelType - This enum defines the possible pixel data types for a pixel transfer operation - - \value NoPixelType Equivalent to GL_NONE - \value Int8 Equivalent to GL_BYTE - \value UInt8 Equivalent to GL_UNSIGNED_BYTE - \value Int16 Equivalent to GL_SHORT - \value UInt16 Equivalent to GL_UNSIGNED_SHORT - \value Int32 Equivalent to GL_INT - \value UInt32 Equivalent to GL_UNSIGNED_INT - \value Float16 Equivalent to GL_HALF_FLOAT - \value Float16OES Equivalent to GL_HALF_FLOAT_OES - \value Float32 Equivalent to GL_FLOAT - \value UInt32_RGB9_E5 Equivalent to GL_UNSIGNED_INT_5_9_9_9_REV - \value UInt32_RG11B10F Equivalent to GL_UNSIGNED_INT_10F_11F_11F_REV - \value UInt8_RG3B2 Equivalent to GL_UNSIGNED_BYTE_3_3_2 - \value UInt8_RG3B2_Rev Equivalent to GL_UNSIGNED_BYTE_2_3_3_REV - \value UInt16_RGB5A1 Equivalent to GL_UNSIGNED_SHORT_5_5_5_1 - \value UInt16_RGB5A1_Rev Equivalent to GL_UNSIGNED_SHORT_1_5_5_5_REV - \value UInt16_R5G6B5 Equivalent to GL_UNSIGNED_SHORT_5_6_5 - \value UInt16_R5G6B5_Rev Equivalent to GL_UNSIGNED_SHORT_5_6_5_REV - \value UInt16_RGBA4 Equivalent to GL_UNSIGNED_SHORT_4_4_4_4 - \value UInt16_RGBA4_Rev Equivalent to GL_UNSIGNED_SHORT_4_4_4_4_REV - \value UInt32_RGBA8 Equivalent to GL_UNSIGNED_INT_8_8_8_8 - \value UInt32_RGBA8_Rev Equivalent to GL_UNSIGNED_INT_8_8_8_8_REV - \value UInt32_RGB10A2 Equivalent to GL_UNSIGNED_INT_10_10_10_2 - \value UInt32_RGB10A2_Rev Equivalent to GL_UNSIGNED_INT_2_10_10_10_REV - \value UInt32_D24S8 Equivalent to GL_UNSIGNED_INT_24_8. Introduced in Qt 5.4 - \value Float32_D32_UInt32_S8_X24 Equivalent to GL_FLOAT_32_UNSIGNED_INT_24_8_REV. Introduced in Qt 5.4 -*/ - -/*! - \enum QOpenGLTexture::Feature - This enum defines the OpenGL texture-related features that can be tested for. - - \value ImmutableStorage Support for immutable texture storage - \value ImmutableMultisampleStorage Support for immutable texture storage with - multisample targets - \value TextureRectangle Support for the GL_TEXTURE_RECTANGLE target - \value TextureArrays Support for texture targets with array layers - \value Texture3D Support for the 3 dimensional texture target - \value TextureMultisample Support for texture targets that have multisample capabilities - \value TextureBuffer Support for textures that use OpenGL buffer objects - as their data source - \value TextureCubeMapArrays Support for cubemap array texture target - \value Swizzle Support for texture component swizzle masks - \value StencilTexturing Support for stencil texturing (i.e. looking up depth or stencil - components of a combined depth/stencil format texture in GLSL shaders). - \value AnisotropicFiltering Support for anisotropic texture filtering - \value NPOTTextures Basic support for non-power-of-two textures - \value NPOTTextureRepeat Full support for non-power-of-two textures including texture - repeat modes - \value Texture1D Support for the 1 dimensional texture target - \value TextureComparisonOperators Support for texture comparison operators - \value TextureMipMapLevel Support for setting the base and maximum mipmap levels -*/ - -/*! - \enum QOpenGLTexture::SwizzleComponent - This enum defines the texture color components that can be assigned a swizzle mask. - - \value SwizzleRed The red component. Equivalent to GL_TEXTURE_SWIZZLE_R - \value SwizzleGreen The green component. Equivalent to GL_TEXTURE_SWIZZLE_G - \value SwizzleBlue The blue component. Equivalent to GL_TEXTURE_SWIZZLE_B - \value SwizzleAlpha The alpha component. Equivalent to GL_TEXTURE_SWIZZLE_A -*/ - -/*! - \enum QOpenGLTexture::SwizzleValue - This enum defines the possible mask values for texture swizzling. - - \value RedValue Maps the component to the red channel. Equivalent to GL_RED - \value GreenValue Maps the component to the green channel. Equivalent to GL_GREEN - \value BlueValue Maps the component to the blue channel. Equivalent to GL_BLUE - \value AlphaValue Maps the component to the alpha channel. Equivalent to GL_ALPHA - \value ZeroValue Maps the component to a fixed value of 0. Equivalent to GL_ZERO - \value OneValue Maps the component to a fixed value of 1. Equivalent to GL_ONE -*/ - -/*! - \enum QOpenGLTexture::WrapMode - This enum defines the possible texture coordinate wrapping modes. - - \value Repeat Texture coordinate is repeated. Equivalent to GL_REPEAT - \value MirroredRepeat Texture coordinate is reflected about 0 and 1. Equivalent to GL_MIRRORED_REPEAT - \value ClampToEdge Clamps the texture coordinates to [0,1]. Equivalent to GL_CLAMP_TO_EDGE - \value ClampToBorder As for ClampToEdge but also blends samples at 0 and 1 with a - fixed border color. Equivalent to GL_CLAMP_TO_BORDER -*/ - -/*! - \enum QOpenGLTexture::CoordinateDirection - This enum defines the possible texture coordinate directions - - \value DirectionS The horizontal direction. Equivalent to GL_TEXTURE_WRAP_S - \value DirectionT The vertical direction. Equivalent to GL_TEXTURE_WRAP_T - \value DirectionR The depth direction. Equivalent to GL_TEXTURE_WRAP_R -*/ - -/*! - Creates a QOpenGLTexture object that can later be bound to \a target. - - This does not create the underlying OpenGL texture object. Therefore, - construction using this constructor does not require a valid current - OpenGL context. -*/ -QOpenGLTexture::QOpenGLTexture(Target target) - : d_ptr(new QOpenGLTexturePrivate(target, this)) -{ -} - -/*! - Creates a QOpenGLTexture object that can later be bound to the 2D texture - target and contains the pixel data contained in \a image. If you wish - to have a chain of mipmaps generated then set \a genMipMaps to \c true (this - is the default). - - This does create the underlying OpenGL texture object. Therefore, - construction using this constructor does require a valid current - OpenGL context. -*/ -QOpenGLTexture::QOpenGLTexture(const QImage& image, MipMapGeneration genMipMaps) - : QOpenGLTexture(QOpenGLTexture::Target2D) -{ - setData(image, genMipMaps); -} - -QOpenGLTexture::~QOpenGLTexture() -{ -} - -/*! - Returns the binding target of this texture. - - \since 5.4 -*/ -QOpenGLTexture::Target QOpenGLTexture::target() const -{ - Q_D(const QOpenGLTexture); - return d->target; -} - -/*! - Creates the underlying OpenGL texture object. This requires a current valid - OpenGL context. If the texture object already exists, this function does - nothing. - - Once the texture object is created you can obtain the object - name from the textureId() function. This may be useful if you wish to make - some raw OpenGL calls related to this texture. - - Normally it should not be necessary to call this function directly as all - functions that set properties of the texture object implicitly call create() - on your behalf. - - Returns \c true if the creation succeeded, otherwise returns \c false. - - \sa destroy(), isCreated(), textureId() -*/ -bool QOpenGLTexture::create() -{ - Q_D(QOpenGLTexture); - return d->create(); -} - -/*! - Destroys the underlying OpenGL texture object. This requires a current valid - OpenGL context. - - \sa create(), isCreated(), textureId() -*/ -void QOpenGLTexture::destroy() -{ - Q_D(QOpenGLTexture); - return d->destroy(); -} - -/*! - Returns \c true if the underlying OpenGL texture object has been created. - - \sa create(), destroy(), textureId() -*/ -bool QOpenGLTexture::isCreated() const -{ - Q_D(const QOpenGLTexture); - return d->textureId != 0; -} - -/*! - Returns the name of the underlying OpenGL texture object or 0 if it has - not yet been created. - - \sa create(), destroy(), isCreated() -*/ -GLuint QOpenGLTexture::textureId() const -{ - Q_D(const QOpenGLTexture); - return d->textureId; -} - -/*! - Binds this texture to the currently active texture unit ready for - rendering. Note that you do not need to bind QOpenGLTexture objects - in order to modify them as the implementation makes use of the - EXT_direct_state_access extension where available and simulates it - where it is not. - - \sa release() -*/ -void QOpenGLTexture::bind() -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - d->bind(); -} - -/*! - Binds this texture to texture unit \a unit ready for - rendering. Note that you do not need to bind QOpenGLTexture objects - in order to modify them as the implementation makes use of the - EXT_direct_state_access extension where available and simulates it - where it is not. - - If parameter \a reset is \c true then this function will restore - the active unit to the texture unit that was active upon entry. - - \sa release() -*/ -void QOpenGLTexture::bind(uint unit, TextureUnitReset reset) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - d->bind(unit, reset); -} - -/*! - Unbinds this texture from the currently active texture unit. - - \sa bind() -*/ -void QOpenGLTexture::release() -{ - Q_D(QOpenGLTexture); - d->release(); -} - -/*! - Unbinds this texture from texture unit \a unit. - - If parameter \a reset is \c true then this function - will restore the active unit to the texture unit that was active - upon entry. -*/ -void QOpenGLTexture::release(uint unit, TextureUnitReset reset) -{ - Q_D(QOpenGLTexture); - d->release(unit, reset); -} - -/*! - Returns \c true if this texture is bound to the corresponding target - of the currently active texture unit. - - \sa bind(), release() -*/ -bool QOpenGLTexture::isBound() const -{ - Q_D(const QOpenGLTexture); - Q_ASSERT(d->textureId); - return d->isBound(); -} - -/*! - Returns \c true if this texture is bound to the corresponding target - of texture unit \a unit. - - \sa bind(), release() -*/ -bool QOpenGLTexture::isBound(uint unit) -{ - Q_D(const QOpenGLTexture); - Q_ASSERT(d->textureId); - return d->isBound(unit); -} - -/*! - Returns the textureId of the texture that is bound to the \a target - of the currently active texture unit. -*/ -GLuint QOpenGLTexture::boundTextureId(BindingTarget target) -{ - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - if (!ctx) { - qWarning("QOpenGLTexture::boundTextureId() requires a valid current context"); - return 0; - } - - GLint textureId = 0; - ctx->functions()->glGetIntegerv(target, &textureId); - return static_cast<GLuint>(textureId); -} - -/*! - Returns the textureId of the texture that is bound to the \a target - of the texture unit \a unit. -*/ -GLuint QOpenGLTexture::boundTextureId(uint unit, BindingTarget target) -{ - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - if (!ctx) { - qWarning("QOpenGLTexture::boundTextureId() requires a valid current context"); - return 0; - } - - QOpenGLFunctions *funcs = ctx->functions(); - funcs->initializeOpenGLFunctions(); - - GLint oldTextureUnit = 0; - funcs->glGetIntegerv(GL_ACTIVE_TEXTURE, &oldTextureUnit); - - funcs->glActiveTexture(unit); - GLint textureId = 0; - funcs->glGetIntegerv(target, &textureId); - funcs->glActiveTexture(oldTextureUnit); - - return static_cast<GLuint>(textureId); -} - -/*! - Sets the format of this texture object to \a format. This function - must be called before texture storage is allocated. - - Note that all formats may not be supported. The exact set of supported - formats is dependent upon your OpenGL implementation and version. - - \sa format(), allocateStorage() -*/ -void QOpenGLTexture::setFormat(TextureFormat format) -{ - Q_D(QOpenGLTexture); - d->create(); - if (isStorageAllocated()) { - qWarning("QOpenGLTexture::setFormat(): Cannot change format once storage has been allocated"); - return; - } - - d->format = format; - - switch (format) { - case NoFormat: - d->formatClass = NoFormatClass; - break; - - case RGBA32F: - case RGBA32U: - case RGBA32I: - d->formatClass = FormatClass_128Bit; - break; - - case RGB32F: - case RGB32U: - case RGB32I: - d->formatClass = FormatClass_96Bit; - break; - - case RGBA16F: - case RG32F: - case RGBA16U: - case RG32U: - case RGBA16I: - case RG32I: - case RGBA16_UNorm: - case RGBA16_SNorm: - d->formatClass = FormatClass_64Bit; - break; - - case RGB16_UNorm: - case RGB16_SNorm: - case RGB16F: - case RGB16U: - case RGB16I: - d->formatClass = FormatClass_48Bit; - break; - - case RG16F: - case RG11B10F: - case R32F: - case RGB10A2: - case RGBA8U: - case RG16U: - case R32U: - case RGBA8I: - case RG16I: - case R32I: - case RGBA8_UNorm: - case RG16_UNorm: - case RGBA8_SNorm: - case RG16_SNorm: - case SRGB8_Alpha8: - case RGB9E5: - d->formatClass = FormatClass_32Bit; - break; - - case RGB8_UNorm: - case RGB8_SNorm: - case SRGB8: - case RGB8U: - case RGB8I: - d->formatClass = FormatClass_24Bit; - break; - - case R16F: - case RG8U: - case R16U: - case RG8I: - case R16I: - case RG8_UNorm: - case R16_UNorm: - case RG8_SNorm: - case R16_SNorm: - d->formatClass = FormatClass_16Bit; - break; - - case R8U: - case R8I: - case R8_UNorm: - case R8_SNorm: - d->formatClass = FormatClass_8Bit; - break; - - case R_ATI1N_UNorm: - case R_ATI1N_SNorm: - d->formatClass = FormatClass_RGTC1_R; - break; - - case RG_ATI2N_UNorm: - case RG_ATI2N_SNorm: - d->formatClass = FormatClass_RGTC2_RG; - break; - - case RGB_BP_UNorm: - case SRGB_BP_UNorm: - d->formatClass = FormatClass_BPTC_Unorm; - break; - - case RGB_BP_UNSIGNED_FLOAT: - case RGB_BP_SIGNED_FLOAT: - d->formatClass = FormatClass_BPTC_Float; - break; - - case RGB_DXT1: - case SRGB_DXT1: - d->formatClass = FormatClass_S3TC_DXT1_RGB; - break; - - case RGBA_DXT1: - case SRGB_Alpha_DXT1: - d->formatClass = FormatClass_S3TC_DXT1_RGBA; - break; - - case RGBA_DXT3: - case SRGB_Alpha_DXT3: - d->formatClass = FormatClass_S3TC_DXT3_RGBA; - break; - - case RGBA_DXT5: - case SRGB_Alpha_DXT5: - d->formatClass = FormatClass_S3TC_DXT5_RGBA; - break; - - case QOpenGLTexture::R11_EAC_UNorm: - case QOpenGLTexture::R11_EAC_SNorm: - case QOpenGLTexture::RG11_EAC_UNorm: - case QOpenGLTexture::RG11_EAC_SNorm: - case QOpenGLTexture::RGB8_ETC2: - case QOpenGLTexture::SRGB8_ETC2: - case QOpenGLTexture::RGB8_PunchThrough_Alpha1_ETC2: - case QOpenGLTexture::SRGB8_PunchThrough_Alpha1_ETC2: - case QOpenGLTexture::RGBA8_ETC2_EAC: - case QOpenGLTexture::SRGB8_Alpha8_ETC2_EAC: - case QOpenGLTexture::RGB8_ETC1: - case RG3B2: - case R5G6B5: - case RGB5A1: - case RGBA4: - case D16: - case D24: - case D24S8: - case D32: - case D32F: - case D32FS8X24: - case S8: - case DepthFormat: - case AlphaFormat: - case RGBFormat: - case RGBAFormat: - case LuminanceFormat: - case LuminanceAlphaFormat: - case QOpenGLTexture::RGBA_ASTC_4x4: - case QOpenGLTexture::RGBA_ASTC_5x4: - case QOpenGLTexture::RGBA_ASTC_5x5: - case QOpenGLTexture::RGBA_ASTC_6x5: - case QOpenGLTexture::RGBA_ASTC_6x6: - case QOpenGLTexture::RGBA_ASTC_8x5: - case QOpenGLTexture::RGBA_ASTC_8x6: - case QOpenGLTexture::RGBA_ASTC_8x8: - case QOpenGLTexture::RGBA_ASTC_10x5: - case QOpenGLTexture::RGBA_ASTC_10x6: - case QOpenGLTexture::RGBA_ASTC_10x8: - case QOpenGLTexture::RGBA_ASTC_10x10: - case QOpenGLTexture::RGBA_ASTC_12x10: - case QOpenGLTexture::RGBA_ASTC_12x12: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_4x4: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_5x4: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_5x5: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_6x5: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_6x6: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_8x5: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_8x6: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_8x8: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_10x5: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_10x6: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_10x8: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_10x10: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_12x10: - case QOpenGLTexture::SRGB8_Alpha8_ASTC_12x12: - d->formatClass = FormatClass_Unique; - break; - } -} - -/*! - Returns the format of this texture object. - - \sa setFormat() -*/ -QOpenGLTexture::TextureFormat QOpenGLTexture::format() const -{ - Q_D(const QOpenGLTexture); - return d->format; -} - -static bool isNpot(int width, int height = 1, int depth = 1) -{ - return width & (width-1) || height & (height-1) || depth & (depth-1); -} - -/*! - Sets the dimensions of this texture object to \a width, - \a height, and \a depth. The default for each dimension is 1. - The maximum allowable texture size is dependent upon your OpenGL - implementation. Allocating storage for a texture less than the - maximum size can still fail if your system is low on resources. - - If a non-power-of-two \a width, \a height or \a depth is provided and your - OpenGL implementation doesn't have support for repeating non-power-of-two - textures, then the wrap mode is automatically set to ClampToEdge. - - \sa width(), height(), depth() -*/ -void QOpenGLTexture::setSize(int width, int height, int depth) -{ - Q_D(QOpenGLTexture); - d->create(); - if (isStorageAllocated()) { - qWarning("Cannot resize a texture that already has storage allocated.\n" - "To do so, destroy() the texture and then create() and setSize()"); - return; - } - - if (isNpot(width, height, depth) && !hasFeature(Feature::NPOTTextureRepeat) && d->target != Target::TargetRectangle) - d->setWrapMode(WrapMode::ClampToEdge); - - switch (d->target) { - case QOpenGLTexture::Target1D: - case QOpenGLTexture::Target1DArray: - case QOpenGLTexture::TargetBuffer: - d->dimensions[0] = width; - Q_UNUSED(height); - Q_UNUSED(depth); - break; - - case QOpenGLTexture::Target2D: - case QOpenGLTexture::Target2DArray: - case QOpenGLTexture::TargetRectangle: - case QOpenGLTexture::Target2DMultisample: - case QOpenGLTexture::Target2DMultisampleArray: - d->dimensions[0] = width; - d->dimensions[1] = height; - Q_UNUSED(depth); - break; - - case QOpenGLTexture::TargetCubeMap: - case QOpenGLTexture::TargetCubeMapArray: - if (width != height) - qWarning("QAbstractOpenGLTexture::setSize(): Cube map textures must be square"); - d->dimensions[0] = d->dimensions[1] = width; - Q_UNUSED(depth); - break; - - case QOpenGLTexture::Target3D: - d->dimensions[0] = width; - d->dimensions[1] = height; - d->dimensions[2] = depth; - break; - } -} - -/*! - Returns the width of a 1D, 2D or 3D texture. - - \sa height(), depth(), setSize() -*/ -int QOpenGLTexture::width() const -{ - Q_D(const QOpenGLTexture); - return d->dimensions[0]; -} - -/*! - Returns the height of a 2D or 3D texture. - - \sa width(), depth(), setSize() -*/ -int QOpenGLTexture::height() const -{ - Q_D(const QOpenGLTexture); - return d->dimensions[1]; -} - -/*! - Returns the depth of a 3D texture. - - \sa width(), height(), setSize() -*/ -int QOpenGLTexture::depth() const -{ - Q_D(const QOpenGLTexture); - return d->dimensions[2]; -} - -/*! - For texture targets that support mipmaps, this function - sets the requested number of mipmap \a levels to allocate storage - for. This function should be called before storage is allocated - for the texture. - - If the texture target does not support mipmaps this function - has no effect. - - \sa mipLevels(), maximumMipLevels(), isStorageAllocated() -*/ -void QOpenGLTexture::setMipLevels(int levels) -{ - Q_D(QOpenGLTexture); - d->create(); - if (isStorageAllocated()) { - qWarning("Cannot set mip levels on a texture that already has storage allocated.\n" - "To do so, destroy() the texture and then create() and setMipLevels()"); - return; - } - - switch (d->target) { - case QOpenGLTexture::Target1D: - case QOpenGLTexture::Target1DArray: - case QOpenGLTexture::Target2D: - case QOpenGLTexture::Target2DArray: - case QOpenGLTexture::TargetCubeMap: - case QOpenGLTexture::TargetCubeMapArray: - case QOpenGLTexture::Target3D: - d->requestedMipLevels = levels; - break; - - case QOpenGLTexture::TargetBuffer: - case QOpenGLTexture::TargetRectangle: - case QOpenGLTexture::Target2DMultisample: - case QOpenGLTexture::Target2DMultisampleArray: - qWarning("QAbstractOpenGLTexture::setMipLevels(): This texture target does not support mipmaps"); - break; - } -} - -/*! - Returns the number of mipmap levels for this texture. If storage - has not yet been allocated for this texture it returns the - requested number of mipmap levels. - - \sa setMipLevels(), maximumMipLevels(), isStorageAllocated() -*/ -int QOpenGLTexture::mipLevels() const -{ - Q_D(const QOpenGLTexture); - return isStorageAllocated() ? d->mipLevels : d->requestedMipLevels; -} - -/*! - Returns the maximum number of mipmap levels that this texture - can have given the current dimensions. - - \sa setMipLevels(), mipLevels(), setSize() -*/ -int QOpenGLTexture::maximumMipLevels() const -{ - Q_D(const QOpenGLTexture); - return d->maximumMipLevelCount(); -} - -/*! - Sets the number of array \a layers to allocate storage for. This - function should be called before storage is allocated for the texture. - - For targets that do not support array layers this function has - no effect. - - \sa layers(), isStorageAllocated() -*/ -void QOpenGLTexture::setLayers(int layers) -{ - Q_D(QOpenGLTexture); - d->create(); - if (isStorageAllocated()) { - qWarning("Cannot set layers on a texture that already has storage allocated.\n" - "To do so, destroy() the texture and then create() and setLayers()"); - return; - } - - switch (d->target) { - case QOpenGLTexture::Target1DArray: - case QOpenGLTexture::Target2DArray: - case QOpenGLTexture::TargetCubeMapArray: - case QOpenGLTexture::Target2DMultisampleArray: - d->layers = layers; - break; - - case QOpenGLTexture::Target1D: - case QOpenGLTexture::Target2D: - case QOpenGLTexture::Target3D: - case QOpenGLTexture::TargetCubeMap: - case QOpenGLTexture::TargetBuffer: - case QOpenGLTexture::TargetRectangle: - case QOpenGLTexture::Target2DMultisample: - qWarning("Texture target does not support array layers"); - break; - } -} - -/*! - Returns the number of array layers for this texture. If - storage has not yet been allocated for this texture then - this function returns the requested number of array layers. - - For texture targets that do not support array layers this - will return 1. - - \sa setLayers(), isStorageAllocated() -*/ -int QOpenGLTexture::layers() const -{ - Q_D(const QOpenGLTexture); - return d->layers; -} - -/*! - Returns the number of faces for this texture. For cubemap - and cubemap array type targets this will be 6. - - For non-cubemap type targets this will return 1. -*/ -int QOpenGLTexture::faces() const -{ - Q_D(const QOpenGLTexture); - return d->faces; -} - -/*! - Sets the number of \a samples to allocate storage for when rendering to - a multisample capable texture target. This function should - be called before storage is allocated for the texture. - - For targets that do not support multisampling this function has - no effect. - - \sa samples(), isStorageAllocated() -*/ -void QOpenGLTexture::setSamples(int samples) -{ - Q_D(QOpenGLTexture); - d->create(); - if (isStorageAllocated()) { - qWarning("Cannot set sample count on a texture that already has storage allocated.\n" - "To do so, destroy() the texture and then create() and setSamples()"); - return; - } - - switch (d->target) { - case QOpenGLTexture::Target2DMultisample: - case QOpenGLTexture::Target2DMultisampleArray: - d->samples = samples; - break; - - case QOpenGLTexture::Target1D: - case QOpenGLTexture::Target2D: - case QOpenGLTexture::Target3D: - case QOpenGLTexture::Target1DArray: - case QOpenGLTexture::Target2DArray: - case QOpenGLTexture::TargetCubeMap: - case QOpenGLTexture::TargetCubeMapArray: - case QOpenGLTexture::TargetBuffer: - case QOpenGLTexture::TargetRectangle: - - qWarning("Texture target does not support multisampling"); - break; - } -} - -/*! - Returns the number of multisample sample points for this texture. - If storage has not yet been allocated for this texture then - this function returns the requested number of samples. - - For texture targets that do not support multisampling this - will return 0. - - \sa setSamples(), isStorageAllocated() -*/ -int QOpenGLTexture::samples() const -{ - Q_D(const QOpenGLTexture); - return d->samples; -} - -/*! - Sets whether the sample positions and number of samples used with - a multisample capable texture target to \a fixed. If set to \c true - the sample positions and number of samples used are the same for - all texels in the image and will not depend upon the image size or - internal format. This function should be called before storage is allocated - for the texture. - - For targets that do not support multisampling this function has - no effect. - - The default value is \c true. - - \sa isFixedSamplePositions(), isStorageAllocated() -*/ -void QOpenGLTexture::setFixedSamplePositions(bool fixed) -{ - Q_D(QOpenGLTexture); - d->create(); - if (isStorageAllocated()) { - qWarning("Cannot set sample positions on a texture that already has storage allocated.\n" - "To do so, destroy() the texture and then create() and setFixedSamplePositions()"); - return; - } - - switch (d->target) { - case QOpenGLTexture::Target2DMultisample: - case QOpenGLTexture::Target2DMultisampleArray: - d->fixedSamplePositions = fixed; - break; - - case QOpenGLTexture::Target1D: - case QOpenGLTexture::Target2D: - case QOpenGLTexture::Target3D: - case QOpenGLTexture::Target1DArray: - case QOpenGLTexture::Target2DArray: - case QOpenGLTexture::TargetCubeMap: - case QOpenGLTexture::TargetCubeMapArray: - case QOpenGLTexture::TargetBuffer: - case QOpenGLTexture::TargetRectangle: - - qWarning("Texture target does not support multisampling"); - break; - } -} - -/*! - Returns whether this texture uses a fixed pattern of multisample - samples. If storage has not yet been allocated for this texture then - this function returns the requested fixed sample position setting. - - For texture targets that do not support multisampling this - will return \c true. - - \sa setFixedSamplePositions(), isStorageAllocated() -*/ -bool QOpenGLTexture::isFixedSamplePositions() const -{ - Q_D(const QOpenGLTexture); - return d->fixedSamplePositions; -} - -/*! - Allocates server-side storage for this texture object taking - into account, the format, dimensions, mipmap levels, array - layers and cubemap faces. - - Once storage has been allocated it is no longer possible to change - these properties. - - If supported QOpenGLTexture makes use of immutable texture - storage. - - Once storage has been allocated for the texture then pixel data - can be uploaded via one of the setData() overloads. - - \note If immutable texture storage is not available, - then a default pixel format and pixel type will be used to - create the mutable storage. You can use the other - allocateStorage() overload to specify exactly the pixel format - and the pixel type to use when allocating mutable storage; - this is particulary useful under certain OpenGL ES implementations - (notably, OpenGL ES 2), where the pixel format and the pixel type - used at allocation time must perfectly match the format - and the type passed to any subsequent setData() call. - - \sa isStorageAllocated(), setData() -*/ -void QOpenGLTexture::allocateStorage() -{ - Q_D(QOpenGLTexture); - if (d->create()) { - const QOpenGLTexture::PixelFormat pixelFormat = pixelFormatCompatibleWithInternalFormat(d->format); - const QOpenGLTexture::PixelType pixelType = pixelTypeCompatibleWithInternalFormat(d->format); - d->allocateStorage(pixelFormat, pixelType); - } -} - -/*! - \since 5.5 - - Allocates server-side storage for this texture object taking - into account, the format, dimensions, mipmap levels, array - layers and cubemap faces. - - Once storage has been allocated it is no longer possible to change - these properties. - - If supported QOpenGLTexture makes use of immutable texture - storage. However, if immutable texture storage is not available, - then the specified \a pixelFormat and \a pixelType will be used - to allocate mutable storage; note that in certain OpenGL implementations - (notably, OpenGL ES 2) they must perfectly match the format - and the type passed to any subsequent setData() call. - - Once storage has been allocated for the texture then pixel data - can be uploaded via one of the setData() overloads. - - \sa isStorageAllocated(), setData() -*/ -void QOpenGLTexture::allocateStorage(QOpenGLTexture::PixelFormat pixelFormat, QOpenGLTexture::PixelType pixelType) -{ - Q_D(QOpenGLTexture); - if (d->create()) - d->allocateStorage(pixelFormat, pixelType); -} - -/*! - Returns \c true if server-side storage for this texture as been - allocated. - - The texture format, dimensions, mipmap levels and array layers - cannot be altered once storage ihas been allocated. - - \sa allocateStorage(), setSize(), setMipLevels(), setLayers(), setFormat() -*/ -bool QOpenGLTexture::isStorageAllocated() const -{ - Q_D(const QOpenGLTexture); - return d->storageAllocated; -} - -/*! - Attempts to create a texture view onto this texture. A texture - view is somewhat analogous to a view in SQL in that it presents - a restricted or reinterpreted view of the original data. Texture - views do not allocate any more server-side storage, insted relying - on the storage buffer of the source texture. - - Texture views are only available when using immutable storage. For - more information on texture views see - http://www.opengl.org/wiki/Texture_Storage#Texture_views. - - The \a target argument specifies the target to use for the view. - Only some targets can be used depending upon the target of the original - target. For e.g. a view onto a Target1DArray texture can specify - either Target1DArray or Target1D but for the latter the number of - array layers specified with \a minimumLayer and \a maximumLayer must - be exactly 1. - - Simpliar constraints apply for the \a viewFormat. See the above link - and the specification for more details. - - The \a minimumMipmapLevel, \a maximumMipmapLevel, \a minimumLayer, - and \a maximumLayer arguments serve to restrict the parts of the - texture accessible by the texture view. - - If creation of the texture view fails this function will return - 0. If the function succeeds it will return a pointer to a new - QOpenGLTexture object that will return \c true from its isTextureView() - function. - - \sa isTextureView() -*/ -QOpenGLTexture *QOpenGLTexture::createTextureView(Target target, - TextureFormat viewFormat, - int minimumMipmapLevel, int maximumMipmapLevel, - int minimumLayer, int maximumLayer) const -{ - Q_D(const QOpenGLTexture); - if (!isStorageAllocated()) { - qWarning("Cannot set create a texture view of a texture that does not have storage allocated."); - return nullptr; - } - Q_ASSERT(maximumMipmapLevel >= minimumMipmapLevel); - Q_ASSERT(maximumLayer >= minimumLayer); - return d->createTextureView(target, viewFormat, - minimumMipmapLevel, maximumMipmapLevel, - minimumLayer, maximumLayer); -} - -/*! - Returns \c true if this texture object is actually a view onto another - texture object. - - \sa createTextureView() -*/ -bool QOpenGLTexture::isTextureView() const -{ - Q_D(const QOpenGLTexture); - Q_ASSERT(d->textureId); - return d->textureView; -} - -/*! - Uploads pixel \a data for this texture object \a mipLevel, array \a layer, and \a cubeFace. - Storage must have been allocated before uploading pixel data. Some overloads of setData() - will set appropriate dimensions, mipmap levels, and array layers and then allocate storage - for you if they have enough information to do so. This will be noted in the function - documentation. - - The structure of the pixel data pointed to by \a data is specified by \a sourceFormat - and \a sourceType. The pixel data upload can optionally be controlled by \a options. - - If using a compressed format() then you should use setCompressedData() instead of this - function. - - \since 5.3 - \sa setCompressedData() -*/ -void QOpenGLTexture::setData(int mipLevel, int layer, CubeMapFace cubeFace, - PixelFormat sourceFormat, PixelType sourceType, - const void *data, const QOpenGLPixelTransferOptions * const options) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - if (!isStorageAllocated()) { - qWarning("Cannot set data on a texture that does not have storage allocated.\n" - "To do so call allocateStorage() before this function"); - return; - } - d->setData(mipLevel, layer, 1, cubeFace, sourceFormat, sourceType, data, options); -} - -/*! - \since 5.9 - \overload - - Parameter \a layerCount is the number of layers in a texture array - that are being uploaded/populated by this call. -*/ -void QOpenGLTexture::setData(int mipLevel, int layer, int layerCount, QOpenGLTexture::CubeMapFace cubeFace, QOpenGLTexture::PixelFormat sourceFormat, QOpenGLTexture::PixelType sourceType, const void *data, const QOpenGLPixelTransferOptions * const options) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - if (!isStorageAllocated()) { - qWarning("Cannot set data on a texture that does not have storage allocated.\n" - "To do so call allocateStorage() before this function"); - return; - } - d->setData(mipLevel, layer, layerCount, cubeFace, sourceFormat, sourceType, data, options); -} - -/*! - \since 5.3 - \overload -*/ -void QOpenGLTexture::setData(int mipLevel, int layer, - PixelFormat sourceFormat, PixelType sourceType, - const void *data, const QOpenGLPixelTransferOptions * const options) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - d->setData(mipLevel, layer, 1, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options); -} - -/*! - \since 5.3 - \overload -*/ -void QOpenGLTexture::setData(int mipLevel, - PixelFormat sourceFormat, PixelType sourceType, - const void *data, const QOpenGLPixelTransferOptions * const options) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - d->setData(mipLevel, 0, 1, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options); -} - -/*! - \since 5.3 - \overload -*/ -void QOpenGLTexture::setData(PixelFormat sourceFormat, PixelType sourceType, - const void *data, const QOpenGLPixelTransferOptions * const options) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - d->setData(0, 0, 1, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options); -} - -/*! - \since 5.14 - \overload - - This overload is to be used to update a part of the texture. Parameters \a - xOffset, \a yOffset, \a zOffset specify the texel offsets within the - texture. Parameters \a width, \a height and \a depth specify the dimensions - of the sub image. - - The structure of the pixel data pointed to by \a data is specified by \a - sourceFormat and \a sourceType. The pixel data upload can optionally be - controlled by \a options. -*/ -void QOpenGLTexture::setData(int xOffset, int yOffset, int zOffset, - int width, int height, int depth, - PixelFormat sourceFormat, PixelType sourceType, - const void *data, const QOpenGLPixelTransferOptions * const options) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - d->setData(xOffset, yOffset, zOffset, - width, height, depth, - 0, 0, 1, - QOpenGLTexture::CubeMapPositiveX, sourceFormat, - sourceType, data, options); -} - -/*! - \since 5.14 - \overload - - This overload is to be used to update a part of the texture. Parameters \a - xOffset, \a yOffset, \a zOffset specify the texel offsets within the - texture. Parameters \a width, \a height and \a depth specify the dimensions - of the sub image. The mip map level the sub image we want to - update is specified with \a mipLevel. - - The structure of the pixel data pointed to by \a data is specified by \a - sourceFormat and \a sourceType. The pixel data upload can optionally be - controlled by \a options. -*/ -void QOpenGLTexture::setData(int xOffset, int yOffset, int zOffset, - int width, int height, int depth, - int mipLevel, - PixelFormat sourceFormat, PixelType sourceType, - const void *data, const QOpenGLPixelTransferOptions * const options) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - d->setData(xOffset, yOffset, zOffset, - width, height, depth, - mipLevel, 0, 1, - QOpenGLTexture::CubeMapPositiveX, sourceFormat, - sourceType, data, options); -} - -/*! - \since 5.14 - \overload - - This overload is to be used to update a part of the texture. Parameters \a - xOffset, \a yOffset, \a zOffset specify the texel offsets within the - texture. Parameters \a width, \a height and \a depth specify the dimensions - of the sub image. The mip map level and layerof the sub image we want to - update are specified with \a mipLevel and \a layer. - - The structure of the pixel data pointed to by \a data is specified by \a - sourceFormat and \a sourceType. The pixel data upload can optionally be - controlled by \a options. -*/ -void QOpenGLTexture::setData(int xOffset, int yOffset, int zOffset, - int width, int height, int depth, - int mipLevel, int layer, - PixelFormat sourceFormat, PixelType sourceType, - const void *data, const QOpenGLPixelTransferOptions * const options) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - d->setData(xOffset, yOffset, zOffset, - width, height, depth, - mipLevel, layer, 1, - QOpenGLTexture::CubeMapPositiveX, sourceFormat, - sourceType, data, options); -} - -/*! - \since 5.14 - \overload - - This overload is to be used to update a part of the texture. Parameters \a - xOffset, \a yOffset, \a zOffset specify the texel offsets within the - texture. Parameters \a width, \a height and \a depth specify the dimensions - of the sub image.The mip map level, layer and cube map face of the sub - image we want to update are specified with \a mipLevel, \a layer and \a - face. - - The structure of the pixel data pointed to by \a data is specified by \a - sourceFormat and \a sourceType. The pixel data upload can optionally be - controlled by \a options. -*/ -void QOpenGLTexture::setData(int xOffset, int yOffset, int zOffset, - int width, int height, int depth, - int mipLevel, int layer, - CubeMapFace face, - PixelFormat sourceFormat, PixelType sourceType, - const void *data, const QOpenGLPixelTransferOptions * const options) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - d->setData(xOffset, yOffset, zOffset, - width, height, depth, - mipLevel, layer, 1, - face, sourceFormat, - sourceType, data, options); -} - -/*! - \since 5.14 - \overload - - This overload is to be used to update a part of the texture. Parameters \a - xOffset, \a yOffset, \a zOffset specify the texel offsets within the - texture. Parameters \a width, \a height and \a depth specify the dimensions - of the sub image.The mip map level, starting layer, cube map face and - number of layers of the sub image we want to update are specified with \a - mipLevel, \a layer, \a face and \a layerCount. - - The structure of the pixel data pointed to by \a data is specified by \a - sourceFormat and \a sourceType. The pixel data upload can optionally be - controlled by \a options. -*/ -void QOpenGLTexture::setData(int xOffset, int yOffset, int zOffset, - int width, int height, int depth, - int mipLevel, int layer, - CubeMapFace face, int layerCount, - PixelFormat sourceFormat, PixelType sourceType, - const void *data, const QOpenGLPixelTransferOptions * const options) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - d->setData(xOffset, yOffset, zOffset, - width, height, depth, - mipLevel, layer, layerCount, - face, sourceFormat, - sourceType, data, options); -} - -#if QT_DEPRECATED_SINCE(5, 3) -/*! - \obsolete - \overload - - \sa setCompressedData() -*/ -void QOpenGLTexture::setData(int mipLevel, int layer, CubeMapFace cubeFace, - PixelFormat sourceFormat, PixelType sourceType, - void *data, const QOpenGLPixelTransferOptions * const options) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - if (!isStorageAllocated()) { - qWarning("Cannot set data on a texture that does not have storage allocated.\n" - "To do so call allocateStorage() before this function"); - return; - } - d->setData(mipLevel, layer, 1, cubeFace, sourceFormat, sourceType, data, options); -} - -/*! - \obsolete - \overload -*/ -void QOpenGLTexture::setData(int mipLevel, int layer, - PixelFormat sourceFormat, PixelType sourceType, - void *data, const QOpenGLPixelTransferOptions * const options) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - d->setData(mipLevel, layer, 1, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options); -} - -/*! - \obsolete - \overload -*/ -void QOpenGLTexture::setData(int mipLevel, - PixelFormat sourceFormat, PixelType sourceType, - void *data, const QOpenGLPixelTransferOptions * const options) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - d->setData(mipLevel, 0, 1, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options); -} - -/*! - \obsolete - \overload -*/ -void QOpenGLTexture::setData(PixelFormat sourceFormat, PixelType sourceType, - void *data, const QOpenGLPixelTransferOptions * const options) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - d->setData(0, 0, 1, QOpenGLTexture::CubeMapPositiveX, sourceFormat, sourceType, data, options); -} -#endif - -/*! - This overload of setData() will allocate storage for you. - The pixel data is contained in \a image. Mipmaps are generated by default. - Set \a genMipMaps to \l DontGenerateMipMaps to turn off mipmap generation. - - \overload -*/ -void QOpenGLTexture::setData(const QImage& image, MipMapGeneration genMipMaps) -{ - QOpenGLContext *context = QOpenGLContext::currentContext(); - if (!context) { - qWarning("QOpenGLTexture::setData() requires a valid current context"); - return; - } - - if (image.isNull()) { - qWarning("QOpenGLTexture::setData() tried to set a null image"); - return; - } - - if (context->isOpenGLES() && context->format().majorVersion() < 3) - setFormat(QOpenGLTexture::RGBAFormat); - else - setFormat(QOpenGLTexture::RGBA8_UNorm); - - setSize(image.width(), image.height()); - setMipLevels(genMipMaps == GenerateMipMaps ? maximumMipLevels() : 1); - allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8); - - // Upload pixel data and generate mipmaps - QImage glImage = image.convertToFormat(QImage::Format_RGBA8888); - QOpenGLPixelTransferOptions uploadOptions; - uploadOptions.setAlignment(1); - setData(0, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, glImage.constBits(), &uploadOptions); -} - -/*! - Uploads compressed pixel \a data to \a mipLevel, array \a layer, and \a cubeFace. - The pixel transfer can optionally be controlled with \a options. The \a dataSize - argument should specify the size of the data pointed to by \a data. - - If not using a compressed format() then you should use setData() instead of this - function. - - \since 5.3 -*/ -void QOpenGLTexture::setCompressedData(int mipLevel, int layer, CubeMapFace cubeFace, - int dataSize, const void *data, - const QOpenGLPixelTransferOptions * const options) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - if (!isStorageAllocated()) { - qWarning("Cannot set data on a texture that does not have storage allocated.\n" - "To do so call allocateStorage() before this function"); - return; - } - d->setCompressedData(mipLevel, layer, 1, cubeFace, dataSize, data, options); -} - -/*! - \since 5.9 - \overload - - Parameter \a layerCount is the number of layers in a texture array - that are being uploaded/populated by this call. -*/ -void QOpenGLTexture::setCompressedData(int mipLevel, int layer, int layerCount, QOpenGLTexture::CubeMapFace cubeFace, int dataSize, const void *data, const QOpenGLPixelTransferOptions * const options) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - if (!isStorageAllocated()) { - qWarning("Cannot set data on a texture that does not have storage allocated.\n" - "To do so call allocateStorage() before this function"); - return; - } - d->setCompressedData(mipLevel, layer, layerCount, cubeFace, dataSize, data, options); -} - -/*! - \overload -*/ -void QOpenGLTexture::setCompressedData(int mipLevel, int layer, int dataSize, const void *data, - const QOpenGLPixelTransferOptions * const options) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - d->setCompressedData(mipLevel, layer, 1, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options); -} - -/*! - \overload -*/ -void QOpenGLTexture::setCompressedData(int mipLevel, int dataSize, const void *data, - const QOpenGLPixelTransferOptions * const options) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - d->setCompressedData(mipLevel, 0, 1, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options); -} - -/*! - \overload -*/ -void QOpenGLTexture::setCompressedData(int dataSize, const void *data, - const QOpenGLPixelTransferOptions * const options) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - d->setCompressedData(0, 0, 1, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options); -} - -#if QT_DEPRECATED_SINCE(5, 3) -/*! - \obsolete - \overload -*/ -void QOpenGLTexture::setCompressedData(int mipLevel, int layer, CubeMapFace cubeFace, - int dataSize, void *data, - const QOpenGLPixelTransferOptions * const options) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - if (!isStorageAllocated()) { - qWarning("Cannot set data on a texture that does not have storage allocated.\n" - "To do so call allocateStorage() before this function"); - return; - } - d->setCompressedData(mipLevel, layer, 1, cubeFace, dataSize, data, options); -} - -/*! - \obsolete - \overload -*/ -void QOpenGLTexture::setCompressedData(int mipLevel, int layer, int dataSize, void *data, - const QOpenGLPixelTransferOptions * const options) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - d->setCompressedData(mipLevel, layer, 1, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options); -} - -/*! - \obsolete - \overload -*/ -void QOpenGLTexture::setCompressedData(int mipLevel, int dataSize, void *data, - const QOpenGLPixelTransferOptions * const options) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - d->setCompressedData(mipLevel, 0, 1, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options); -} - -/*! - \obsolete - \overload -*/ -void QOpenGLTexture::setCompressedData(int dataSize, void *data, - const QOpenGLPixelTransferOptions * const options) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->textureId); - d->setCompressedData(0, 0, 1, QOpenGLTexture::CubeMapPositiveX, dataSize, data, options); -} -#endif - -/*! - Returns \c true if your OpenGL implementation and version supports the texture - feature \a feature. -*/ -bool QOpenGLTexture::hasFeature(Feature feature) -{ - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - if (!ctx) { - qWarning("QOpenGLTexture::hasFeature() requires a valid current context"); - return false; - } - - QSurfaceFormat f = ctx->format(); - - bool supported = false; - -#if !defined(QT_OPENGL_ES_2) - if (!ctx->isOpenGLES()) { - switch (feature) { - case ImmutableMultisampleStorage: - supported = f.version() >= qMakePair(4, 3) - || ctx->hasExtension(QByteArrayLiteral("GL_ARB_texture_storage_multisample")); - break; - - case TextureBuffer: - supported = f.version() >= qMakePair(3, 0) - || ctx->hasExtension(QByteArrayLiteral("GL_ARB_texture_buffer_object")); - break; - - case StencilTexturing: - supported = f.version() >= qMakePair(4, 3) - || ctx->hasExtension(QByteArrayLiteral("GL_ARB_stencil_texturing")); - break; - - case ImmutableStorage: - supported = f.version() >= qMakePair(4, 2) - || ctx->hasExtension(QByteArrayLiteral("GL_ARB_texture_storage")) - || ctx->hasExtension(QByteArrayLiteral("GL_EXT_texture_storage")); - break; - - case TextureCubeMapArrays: - supported = f.version() >= qMakePair(4, 0) - || ctx->hasExtension(QByteArrayLiteral("ARB_texture_cube_map_array")); - break; - - case Swizzle: - supported = f.version() >= qMakePair(3, 3) - || ctx->hasExtension(QByteArrayLiteral("GL_ARB_texture_swizzle")); - break; - - case TextureMultisample: - supported = f.version() >= qMakePair(3, 2) - || ctx->hasExtension(QByteArrayLiteral("GL_ARB_texture_multisample")); - break; - - case TextureArrays: - supported = f.version() >= qMakePair(3, 0) - || ctx->hasExtension(QByteArrayLiteral("GL_EXT_texture_array")); - break; - - case TextureRectangle: - supported = f.version() >= qMakePair(2, 1) - || ctx->hasExtension(QByteArrayLiteral("ARB_texture_rectangle")); - break; - - case Texture3D: - supported = f.version() >= qMakePair(1, 3); - break; - - case AnisotropicFiltering: - supported = ctx->hasExtension(QByteArrayLiteral("GL_EXT_texture_filter_anisotropic")); - break; - - case NPOTTextures: - case NPOTTextureRepeat: - supported = ctx->hasExtension(QByteArrayLiteral("GL_ARB_texture_non_power_of_two")); - break; - - case Texture1D: - supported = f.version() >= qMakePair(1, 1); - break; - - case TextureComparisonOperators: - // GL 1.4 and GL_ARB_shadow alone support only LEQUAL and GEQUAL; - // since we're talking about history anyhow avoid to be extra pedantic - // in the feature set, and simply claim supported if we have the full set of operators - // (which has been added into 1.5 / GL_EXT_shadow_funcs). - supported = f.version() >= qMakePair(1, 5) - || (ctx->hasExtension(QByteArrayLiteral("GL_ARB_shadow")) - && ctx->hasExtension(QByteArrayLiteral("GL_EXT_shadow_funcs"))); - break; - - case TextureMipMapLevel: - supported = f.version() >= qMakePair(1, 2); - break; - - case MaxFeatureFlag: - break; - } - } - - if (ctx->isOpenGLES()) -#endif - { - const char *renderer = reinterpret_cast<const char *>(ctx->functions()->glGetString(GL_RENDERER)); - switch (feature) { - case ImmutableStorage: - supported = (f.version() >= qMakePair(3, 0) || ctx->hasExtension(QByteArrayLiteral("GL_EXT_texture_storage"))) - && !(renderer && strstr(renderer, "Mali")); // do not use on Mali: QTBUG-45106 - break; - - case ImmutableMultisampleStorage: - supported = f.version() >= qMakePair(3, 1); - break; - - case TextureRectangle: - break; - - case TextureArrays: - supported = f.version() >= qMakePair(3, 0); - break; - - case Texture3D: - supported = f.version() >= qMakePair(3, 0) - || ctx->hasExtension(QByteArrayLiteral("GL_OES_texture_3D")); - break; - - case TextureMultisample: - supported = f.version() >= qMakePair(3, 1); - break; - - case TextureBuffer: - break; - - case TextureCubeMapArrays: - break; - - case Swizzle: - supported = f.version() >= qMakePair(3, 0); - break; - - case StencilTexturing: - break; - - case AnisotropicFiltering: - supported = ctx->hasExtension(QByteArrayLiteral("GL_EXT_texture_filter_anisotropic")); - break; - - case NPOTTextures: - case NPOTTextureRepeat: - supported = f.version() >= qMakePair(3,0) - || ctx->hasExtension(QByteArrayLiteral("GL_OES_texture_npot")) - || ctx->hasExtension(QByteArrayLiteral("GL_ARB_texture_non_power_of_two")); - break; - - case Texture1D: - break; - - case TextureComparisonOperators: - supported = f.version() >= qMakePair(3, 0) - || ctx->hasExtension(QByteArrayLiteral("GL_EXT_shadow_samplers")); - break; - - case TextureMipMapLevel: - supported = f.version() >= qMakePair(3, 0); - break; - - case MaxFeatureFlag: - break; - } - } - - return supported; -} - -/*! - Sets the base mipmap level used for all texture lookups with this texture to \a baseLevel. - - \note This function has no effect on Qt built for OpenGL ES 2. - \sa mipBaseLevel(), setMipMaxLevel(), setMipLevelRange() -*/ -void QOpenGLTexture::setMipBaseLevel(int baseLevel) -{ - Q_D(QOpenGLTexture); - d->create(); - if (!d->features.testFlag(TextureMipMapLevel)) { - qWarning("QOpenGLTexture::setMipBaseLevel: requires OpenGL >= 1.2 or OpenGL ES >= 3.0"); - return; - } - Q_ASSERT(d->textureId); - Q_ASSERT(d->texFuncs); - Q_ASSERT(baseLevel <= d->maxLevel); - d->baseLevel = baseLevel; - d->texFuncs->glTextureParameteri(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_BASE_LEVEL, baseLevel); -} - -/*! - Returns the mipmap base level used for all texture lookups with this texture. - The default is 0. - - \sa setMipBaseLevel(), mipMaxLevel(), mipLevelRange() -*/ -int QOpenGLTexture::mipBaseLevel() const -{ - Q_D(const QOpenGLTexture); - return d->baseLevel; -} - -/*! - Sets the maximum mipmap level used for all texture lookups with this texture to \a maxLevel. - - \note This function has no effect on Qt built for OpenGL ES 2. - \sa mipMaxLevel(), setMipBaseLevel(), setMipLevelRange() -*/ -void QOpenGLTexture::setMipMaxLevel(int maxLevel) -{ - Q_D(QOpenGLTexture); - d->create(); - if (!d->features.testFlag(TextureMipMapLevel)) { - qWarning("QOpenGLTexture::setMipMaxLevel: requires OpenGL >= 1.2 or OpenGL ES >= 3.0"); - return; - } - Q_ASSERT(d->textureId); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->baseLevel <= maxLevel); - d->maxLevel = maxLevel; - d->texFuncs->glTextureParameteri(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_MAX_LEVEL, maxLevel); -} - -/*! - Returns the mipmap maximum level used for all texture lookups with this texture. - - \sa setMipMaxLevel(), mipBaseLevel(), mipLevelRange() -*/ -int QOpenGLTexture::mipMaxLevel() const -{ - Q_D(const QOpenGLTexture); - return d->maxLevel; -} - -/*! - Sets the range of mipmap levels that can be used for texture lookups with this texture - to range from \a baseLevel to \a maxLevel. - - \note This function has no effect on Qt built for OpenGL ES 2. - \sa setMipBaseLevel(), setMipMaxLevel(), mipLevelRange() -*/ -void QOpenGLTexture::setMipLevelRange(int baseLevel, int maxLevel) -{ - Q_D(QOpenGLTexture); - d->create(); - if (!d->features.testFlag(TextureMipMapLevel)) { - qWarning("QOpenGLTexture::setMipLevelRange: requires OpenGL >= 1.2 or OpenGL ES >= 3.0"); - return; - } - Q_ASSERT(d->textureId); - Q_ASSERT(d->texFuncs); - Q_ASSERT(baseLevel <= maxLevel); - d->texFuncs->glTextureParameteri(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_BASE_LEVEL, baseLevel); - d->texFuncs->glTextureParameteri(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_MAX_LEVEL, maxLevel); -} - -/*! - Returns the range of mipmap levels that can be used for texture lookups with this texture. - - \sa mipBaseLevel(), mipMaxLevel() -*/ -QPair<int, int> QOpenGLTexture::mipLevelRange() const -{ - Q_D(const QOpenGLTexture); - return qMakePair(d->baseLevel, d->maxLevel); -} - -/*! - If \a enabled is \c true, enables automatic mipmap generation for this texture object - to occur whenever the level 0 mipmap data is set via setData(). - - The automatic mipmap generation is enabled by default. - - \note Mipmap generation is not supported for compressed textures with OpenGL ES 2.0. - - \sa isAutoMipMapGenerationEnabled(), generateMipMaps() -*/ -void QOpenGLTexture::setAutoMipMapGenerationEnabled(bool enabled) -{ - Q_D(QOpenGLTexture); - d->autoGenerateMipMaps = enabled; -} - -/*! - Returns whether auto mipmap generation is enabled for this texture object. - - \sa setAutoMipMapGenerationEnabled(), generateMipMaps() -*/ -bool QOpenGLTexture::isAutoMipMapGenerationEnabled() const -{ - Q_D(const QOpenGLTexture); - return d->autoGenerateMipMaps; -} - -/*! - Generates mipmaps for this texture object from mipmap level 0. If you are - using a texture target and filtering option that requires mipmaps and you - have disabled automatic mipmap generation then you need to call this function - or the overload to create the mipmap chain. - - \note Mipmap generation is not supported for compressed textures with OpenGL ES. - - \sa setAutoMipMapGenerationEnabled(), setMipLevels(), mipLevels() -*/ -void QOpenGLTexture::generateMipMaps() -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - if (isCompressedFormat(d->format)) { - if (QOpenGLContext *ctx = QOpenGLContext::currentContext()) - if (ctx->isOpenGLES()) - return; - } - d->texFuncs->glGenerateTextureMipmap(d->textureId, d->target, d->bindingTarget); -} - -/*! - Generates mipmaps for this texture object from mipmap level \a baseLevel. If you are - using a texture target and filtering option that requires mipmaps and you - have disabled automatic mipmap generation then you need to call this function - or the overload to create the mipmap chain. - - The generation of mipmaps to above \a baseLevel is achieved by setting the mipmap - base level to \a baseLevel and then generating the mipmap chain. If \a resetBaseLevel - is \c true, then the baseLevel of the texture will be reset to its previous value. - - \sa setAutoMipMapGenerationEnabled(), setMipLevels(), mipLevels() -*/ -void QOpenGLTexture::generateMipMaps(int baseLevel, bool resetBaseLevel) -{ - Q_D(QOpenGLTexture); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - if (isCompressedFormat(d->format)) { - if (QOpenGLContext *ctx = QOpenGLContext::currentContext()) - if (ctx->isOpenGLES()) - return; - } - int oldBaseLevel; - if (resetBaseLevel) - oldBaseLevel = mipBaseLevel(); - setMipBaseLevel(baseLevel); - d->texFuncs->glGenerateTextureMipmap(d->textureId, d->target, d->bindingTarget); - if (resetBaseLevel) - setMipBaseLevel(oldBaseLevel); -} - -/*! - GLSL shaders are able to reorder the components of the vec4 returned by texture - functions. It is also desirable to be able to control this reordering from CPU - side code. This is made possible by swizzle masks since OpenGL 3.3. - - Each component of the texture can be mapped to one of the SwizzleValue options. - - This function maps \a component to the output \a value. - - \note This function has no effect on Mac and Qt built for OpenGL ES 2. - \sa swizzleMask() -*/ -void QOpenGLTexture::setSwizzleMask(SwizzleComponent component, SwizzleValue value) -{ -#if !defined(Q_OS_MAC) && !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isOpenGLES()) { - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - if (!d->features.testFlag(Swizzle)) { - qWarning("QOpenGLTexture::setSwizzleMask() requires OpenGL >= 3.3"); - return; - } - d->swizzleMask[component - SwizzleRed] = value; - d->texFuncs->glTextureParameteri(d->textureId, d->target, d->bindingTarget, component, value); - return; - } -#else - Q_UNUSED(component); - Q_UNUSED(value); -#endif - qWarning("QOpenGLTexture: Texture swizzling is not supported"); -} - -/*! - Parameters \a {r}, \a {g}, \a {b}, and \a {a} are values used for setting - the colors red, green, blue, and the alpha value. - \overload -*/ -void QOpenGLTexture::setSwizzleMask(SwizzleValue r, SwizzleValue g, - SwizzleValue b, SwizzleValue a) -{ -#if !defined(Q_OS_MAC) && !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isOpenGLES()) { - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - if (!d->features.testFlag(Swizzle)) { - qWarning("QOpenGLTexture::setSwizzleMask() requires OpenGL >= 3.3"); - return; - } - GLint swizzleMask[] = {GLint(r), GLint(g), GLint(b), GLint(a)}; - d->swizzleMask[0] = r; - d->swizzleMask[1] = g; - d->swizzleMask[2] = b; - d->swizzleMask[3] = a; - d->texFuncs->glTextureParameteriv(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask); - return; - } -#else - Q_UNUSED(r); - Q_UNUSED(g); - Q_UNUSED(b); - Q_UNUSED(a); -#endif - qWarning("QOpenGLTexture: Texture swizzling is not supported"); -} - -/*! - Returns the swizzle mask for texture \a component. -*/ -QOpenGLTexture::SwizzleValue QOpenGLTexture::swizzleMask(SwizzleComponent component) const -{ - Q_D(const QOpenGLTexture); - return d->swizzleMask[component - SwizzleRed]; -} - -/*! - \enum QOpenGLTexture::DepthStencilMode - \since 5.4 - This enum specifies which component of a depth/stencil texture is - accessed when the texture is sampled. - - \value DepthMode Equivalent to GL_DEPTH_COMPONENT. - \value StencilMode Equivalent to GL_STENCIL_INDEX. -*/ - -/*! - If using a texture that has a combined depth/stencil format this function sets - which component of the texture is accessed to \a mode. - - When the parameter is set to DepthMode, then accessing it from the - shader will access the depth component as a single float, as normal. But when - the parameter is set to StencilMode, the shader will access the stencil component. - - \note This function has no effect on Mac and Qt built for OpenGL ES 2. - \since 5.4 - \sa depthStencilMode() -*/ -void QOpenGLTexture::setDepthStencilMode(QOpenGLTexture::DepthStencilMode mode) -{ -#if !defined(Q_OS_MAC) && !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isOpenGLES()) { - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - if (!d->features.testFlag(StencilTexturing)) { - qWarning("QOpenGLTexture::setDepthStencilMode() requires OpenGL >= 4.3 or GL_ARB_stencil_texturing"); - return; - } - d->depthStencilMode = mode; - d->texFuncs->glTextureParameteri(d->textureId, d->target, d->bindingTarget, GL_DEPTH_STENCIL_TEXTURE_MODE, mode); - return; - } -#else - Q_UNUSED(mode); -#endif - qWarning("QOpenGLTexture: DepthStencil Mode is not supported"); -} - -/*! - Returns the depth stencil mode for textures using a combined depth/stencil format. - - \since 5.4 - \sa setDepthStencilMode() -*/ -QOpenGLTexture::DepthStencilMode QOpenGLTexture::depthStencilMode() const -{ - Q_D(const QOpenGLTexture); - return d->depthStencilMode; -} - -/*! - \enum QOpenGLTexture::ComparisonFunction - \since 5.5 - This enum specifies which comparison operator is used when texture comparison - is enabled on this texture. - - \value CompareLessEqual Equivalent to GL_LEQUAL. - \value CompareGreaterEqual Equivalent to GL_GEQUAL. - \value CompareLess Equivalent to GL_LESS. - \value CompareGreater Equivalent to GL_GREATER. - \value CompareEqual Equivalent to GL_EQUAL. - \value CommpareNotEqual Equivalent to GL_NOTEQUAL. - \value CompareAlways Equivalent to GL_ALWAYS. - \value CompareNever Equivalent to GL_NEVER. - -*/ - -/*! - \since 5.5 - - Sets the texture comparison function on this texture to \a function. The texture - comparison function is used by shadow samplers when sampling a depth texture. - - \sa comparisonFunction() -*/ -void QOpenGLTexture::setComparisonFunction(QOpenGLTexture::ComparisonFunction function) -{ - Q_D(QOpenGLTexture); - d->create(); - if (!d->features.testFlag(TextureComparisonOperators)) { - qWarning("QOpenGLTexture::setComparisonFunction: requires OpenGL >= 1.5 or OpenGL ES >= 3.0"); - return; - } - d->comparisonFunction = function; - d->texFuncs->glTextureParameteri(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_COMPARE_FUNC, function); -} - -/*! - \since 5.5 - - Returns the texture comparison operator set on this texture. By default, a - texture has a CompareLessEqual comparison function. - - \sa setComparisonFunction() -*/ -QOpenGLTexture::ComparisonFunction QOpenGLTexture::comparisonFunction() const -{ - Q_D(const QOpenGLTexture); - return d->comparisonFunction; -} - -/*! - \enum QOpenGLTexture::ComparisonMode - \since 5.5 - This enum specifies which comparison mode is used when sampling this texture. - - \value CompareRefToTexture Equivalent to GL_COMPARE_REF_TO_TEXTURE. - \value CompareNone Equivalent to GL_NONE. -*/ - -/*! - \since 5.5 - - Sets the texture comparison mode on this texture to \a mode. The texture - comparison mode is used by shadow samplers when sampling a depth texture. - - \sa comparisonMode() -*/ -void QOpenGLTexture::setComparisonMode(QOpenGLTexture::ComparisonMode mode) -{ - Q_D(QOpenGLTexture); - d->create(); - if (!d->features.testFlag(TextureComparisonOperators)) { - qWarning("QOpenGLTexture::setComparisonMode: requires OpenGL >= 1.5 or OpenGL ES >= 3.0"); - return; - } - d->comparisonMode = mode; - d->texFuncs->glTextureParameteri(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_COMPARE_MODE, mode); -} - -/*! - \since 5.5 - - Returns the texture comparison mode set on this texture. By default, a - texture has a CompareNone comparison mode (i.e. comparisons are disabled). - - \sa setComparisonMode() -*/ -QOpenGLTexture::ComparisonMode QOpenGLTexture::comparisonMode() const -{ - Q_D(const QOpenGLTexture); - return d->comparisonMode; -} - -/*! - Sets the filter used for minification to \a filter. - - \sa minificationFilter(), setMagnificationFilter(), setMinMagFilters() -*/ -void QOpenGLTexture::setMinificationFilter(QOpenGLTexture::Filter filter) -{ - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - d->minFilter = filter; - d->texFuncs->glTextureParameteri(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_MIN_FILTER, filter); -} - -/*! - Returns the minification filter. - - \sa setMinificationFilter() -*/ -QOpenGLTexture::Filter QOpenGLTexture::minificationFilter() const -{ - Q_D(const QOpenGLTexture); - return d->minFilter; -} - -/*! - Sets the magnification filter to \a filter. - - \sa magnificationFilter(), setMinificationFilter(), setMinMagFilters() -*/ -void QOpenGLTexture::setMagnificationFilter(QOpenGLTexture::Filter filter) -{ - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - d->magFilter = filter; - d->texFuncs->glTextureParameteri(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_MAG_FILTER, filter); -} - -/*! - Returns the magnification filter. - - \sa setMagnificationFilter() -*/ -QOpenGLTexture::Filter QOpenGLTexture::magnificationFilter() const -{ - Q_D(const QOpenGLTexture); - return d->magFilter; -} - -/*! - Sets the minification filter to \a minificationFilter and the magnification filter - to \a magnificationFilter. - - \sa minMagFilters(), setMinificationFilter(), setMagnificationFilter() -*/ -void QOpenGLTexture::setMinMagFilters(QOpenGLTexture::Filter minificationFilter, - QOpenGLTexture::Filter magnificationFilter) -{ - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - d->minFilter = minificationFilter; - d->magFilter = magnificationFilter; - d->texFuncs->glTextureParameteri(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_MIN_FILTER, minificationFilter); - d->texFuncs->glTextureParameteri(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_MAG_FILTER, magnificationFilter); -} - -/*! - Returns the current minification and magnification filters. - - \sa setMinMagFilters() -*/ -QPair<QOpenGLTexture::Filter, QOpenGLTexture::Filter> QOpenGLTexture::minMagFilters() const -{ - Q_D(const QOpenGLTexture); - return QPair<QOpenGLTexture::Filter, QOpenGLTexture::Filter>(d->minFilter, d->magFilter); -} - -/*! - If your OpenGL implementation supports the GL_EXT_texture_filter_anisotropic extension - this function sets the maximum anisotropy level to \a anisotropy. - - \sa maximumAnisotropy() -*/ -void QOpenGLTexture::setMaximumAnisotropy(float anisotropy) -{ - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - if (!d->features.testFlag(AnisotropicFiltering)) { - qWarning("QOpenGLTexture::setMaximumAnisotropy() requires GL_EXT_texture_filter_anisotropic"); - return; - } - d->maxAnisotropy = anisotropy; - d->texFuncs->glTextureParameteri(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy); -} - -/*! - Returns the maximum level of anisotropy to be accounted for when performing texture lookups. - This requires the GL_EXT_texture_filter_anisotropic extension. - - \sa setMaximumAnisotropy() -*/ -float QOpenGLTexture::maximumAnisotropy() const -{ - Q_D(const QOpenGLTexture); - return d->maxAnisotropy; -} - -/*! - Sets the wrap (or repeat mode) for all texture dimentions to \a mode. - - \sa wrapMode() -*/ -void QOpenGLTexture::setWrapMode(QOpenGLTexture::WrapMode mode) -{ - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - d->setWrapMode(mode); -} - -/*! - Holds the texture dimension \a direction. - \overload -*/ -void QOpenGLTexture::setWrapMode(QOpenGLTexture::CoordinateDirection direction, QOpenGLTexture::WrapMode mode) -{ - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - d->setWrapMode(direction, mode); -} - -/*! - Returns the wrap mode for the texture dimension \a direction. - - \sa setWrapMode() -*/ -QOpenGLTexture::WrapMode QOpenGLTexture::wrapMode(QOpenGLTexture::CoordinateDirection direction) const -{ - Q_D(const QOpenGLTexture); - return d->wrapMode(direction); -} - -/*! - Sets the border color of the texture to \a color. - - \note This function has no effect on Mac and Qt built for OpenGL ES 2. - \sa borderColor() -*/ -void QOpenGLTexture::setBorderColor(QColor color) -{ - setBorderColor(static_cast<float>(color.redF()), static_cast<float>(color.greenF()), - static_cast<float>(color.blueF()), static_cast<float>(color.alphaF())); -} - -/*! - Sets the color red to \a {r}, green to \a {g}, blue to \a {b}, and \a {a} to the - alpha value. - \overload -*/ -void QOpenGLTexture::setBorderColor(float r, float g, float b, float a) -{ -#if !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isOpenGLES()) { - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - float values[4]; - values[0] = r; - values[1] = g; - values[2] = b; - values[3] = a; - d->borderColor.clear(); - for (int i = 0; i < 4; ++i) - d->borderColor.append(QVariant(values[i])); - d->texFuncs->glTextureParameterfv(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_BORDER_COLOR, values); - return; - } -#else - Q_UNUSED(r); - Q_UNUSED(g); - Q_UNUSED(b); - Q_UNUSED(a); -#endif - qWarning("QOpenGLTexture: Border color is not supported"); -} - -/*! - Sets the color red to \a {r}, green to \a {g}, blue to \a {b}, and the alpha - value to \a {a}. - \overload -*/ -void QOpenGLTexture::setBorderColor(int r, int g, int b, int a) -{ -#if !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isOpenGLES()) { - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - int values[4]; - values[0] = r; - values[1] = g; - values[2] = b; - values[3] = a; - d->borderColor.clear(); - for (int i = 0; i < 4; ++i) - d->borderColor.append(QVariant(values[i])); - d->texFuncs->glTextureParameteriv(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_BORDER_COLOR, values); - return; - } -#else - Q_UNUSED(r); - Q_UNUSED(g); - Q_UNUSED(b); - Q_UNUSED(a); -#endif - qWarning("QOpenGLTexture: Border color is not supported"); - - // TODO Handle case of using glTextureParameterIiv() based on format -} - -/*! - Sets the color red to \a {r}, green to \a {g}, blue to \a {b}, and the alpha - value to \a {a}. - \overload -*/ -void QOpenGLTexture::setBorderColor(uint r, uint g, uint b, uint a) -{ -#if !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isOpenGLES()) { - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - int values[4]; - values[0] = int(r); - values[1] = int(g); - values[2] = int(b); - values[3] = int(a); - d->borderColor.clear(); - for (int i = 0; i < 4; ++i) - d->borderColor.append(QVariant(values[i])); - d->texFuncs->glTextureParameteriv(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_BORDER_COLOR, values); - return; - } -#else - Q_UNUSED(r); - Q_UNUSED(g); - Q_UNUSED(b); - Q_UNUSED(a); -#endif - qWarning("QOpenGLTexture: Border color is not supported"); - - // TODO Handle case of using glTextureParameterIuiv() based on format -} - -/*! - Returns the borderColor of this texture. - - \sa setBorderColor() -*/ -QColor QOpenGLTexture::borderColor() const -{ - Q_D(const QOpenGLTexture); - QColor c(0.0f, 0.0f, 0.0f, 0.0f); - if (!d->borderColor.isEmpty()) { - c.setRedF(d->borderColor.at(0).toFloat()); - c.setGreenF(d->borderColor.at(1).toFloat()); - c.setBlueF(d->borderColor.at(2).toFloat()); - c.setAlphaF(d->borderColor.at(3).toFloat()); - } - return c; -} - -/*! - Writes the texture border color into the first four elements - of the array pointed to by \a border. - - \sa setBorderColor() -*/ -void QOpenGLTexture::borderColor(float *border) const -{ - Q_D(const QOpenGLTexture); - Q_ASSERT(border); - if (d->borderColor.isEmpty()) { - for (int i = 0; i < 4; ++i) - border[i] = 0.0f; - } else { - for (int i = 0; i < 4; ++i) - border[i] = d->borderColor.at(i).toFloat(); - } -} - -/*! - Writes the texture border color into the first four elements - of the array pointed to by \a border. - - \overload -*/ -void QOpenGLTexture::borderColor(int *border) const -{ - Q_D(const QOpenGLTexture); - Q_ASSERT(border); - if (d->borderColor.isEmpty()) { - for (int i = 0; i < 4; ++i) - border[i] = 0; - } else { - for (int i = 0; i < 4; ++i) - border[i] = d->borderColor.at(i).toInt(); - } -} - -/*! - Writes the texture border color into the first four elements - of the array pointed to by \a border. - - \overload -*/ -void QOpenGLTexture::borderColor(unsigned int *border) const -{ - Q_D(const QOpenGLTexture); - Q_ASSERT(border); - if (d->borderColor.isEmpty()) { - for (int i = 0; i < 4; ++i) - border[i] = 0; - } else { - for (int i = 0; i < 4; ++i) - border[i] = d->borderColor.at(i).toUInt(); - } -} - -/*! - Sets the minimum level of detail to \a value. This limits the selection of highest - resolution mipmap (lowest mipmap level). The default value is -1000. - - \note This function has no effect on Qt built for OpenGL ES 2. - \sa minimumLevelOfDetail(), setMaximumLevelOfDetail(), setLevelOfDetailRange() -*/ -void QOpenGLTexture::setMinimumLevelOfDetail(float value) -{ -#if !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isOpenGLES()) { - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - Q_ASSERT(value < d->maxLevelOfDetail); - d->minLevelOfDetail = value; - d->texFuncs->glTextureParameterf(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_MIN_LOD, value); - return; - } -#else - Q_UNUSED(value); -#endif - qWarning("QOpenGLTexture: Detail level is not supported"); -} - -/*! - Returns the minimum level of detail parameter. - - \sa setMinimumLevelOfDetail(), maximumLevelOfDetail(), levelOfDetailRange() -*/ -float QOpenGLTexture::minimumLevelOfDetail() const -{ - Q_D(const QOpenGLTexture); - return d->minLevelOfDetail; -} - -/*! - Sets the maximum level of detail to \a value. This limits the selection of lowest - resolution mipmap (highest mipmap level). The default value is 1000. - - \note This function has no effect on Qt built for OpenGL ES 2. - \sa maximumLevelOfDetail(), setMinimumLevelOfDetail(), setLevelOfDetailRange() -*/ -void QOpenGLTexture::setMaximumLevelOfDetail(float value) -{ -#if !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isOpenGLES()) { - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - Q_ASSERT(value > d->minLevelOfDetail); - d->maxLevelOfDetail = value; - d->texFuncs->glTextureParameterf(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_MAX_LOD, value); - return; - } -#else - Q_UNUSED(value); -#endif - qWarning("QOpenGLTexture: Detail level is not supported"); -} - -/*! - Returns the maximum level of detail parameter. - - \sa setMaximumLevelOfDetail(), minimumLevelOfDetail(), levelOfDetailRange() -*/ -float QOpenGLTexture::maximumLevelOfDetail() const -{ - Q_D(const QOpenGLTexture); - return d->maxLevelOfDetail; -} - -/*! - Sets the minimum level of detail parameters to \a min and the maximum level - to \a max. - \note This function has no effect on Qt built for OpenGL ES 2. - \sa levelOfDetailRange(), setMinimumLevelOfDetail(), setMaximumLevelOfDetail() -*/ -void QOpenGLTexture::setLevelOfDetailRange(float min, float max) -{ -#if !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isOpenGLES()) { - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - Q_ASSERT(min < max); - d->minLevelOfDetail = min; - d->maxLevelOfDetail = max; - d->texFuncs->glTextureParameterf(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_MIN_LOD, min); - d->texFuncs->glTextureParameterf(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_MAX_LOD, max); - return; - } -#else - Q_UNUSED(min); - Q_UNUSED(max); -#endif - qWarning("QOpenGLTexture: Detail level is not supported"); -} - -/*! - Returns the minimum and maximum level of detail parameters. - - \sa setLevelOfDetailRange(), minimumLevelOfDetail(), maximumLevelOfDetail() -*/ -QPair<float, float> QOpenGLTexture::levelOfDetailRange() const -{ - Q_D(const QOpenGLTexture); - return qMakePair(d->minLevelOfDetail, d->maxLevelOfDetail); -} - -/*! - Sets the level of detail bias to \a bias. - Level of detail bias affects the point at which mipmapping levels change. - Increasing values for level of detail bias makes the overall images blurrier - or smoother. Decreasing values make the overall images sharper. - - \note This function has no effect on Qt built for OpenGL ES 2. - \sa levelofDetailBias() -*/ -void QOpenGLTexture::setLevelofDetailBias(float bias) -{ -#if !defined(QT_OPENGL_ES_2) - if (!QOpenGLContext::currentContext()->isOpenGLES()) { - Q_D(QOpenGLTexture); - d->create(); - Q_ASSERT(d->texFuncs); - Q_ASSERT(d->textureId); - d->levelOfDetailBias = bias; - d->texFuncs->glTextureParameterf(d->textureId, d->target, d->bindingTarget, GL_TEXTURE_LOD_BIAS, bias); - return; - } -#else - Q_UNUSED(bias); -#endif - qWarning("QOpenGLTexture: Detail level is not supported"); -} - -/*! - Returns the level of detail bias parameter. - - \sa setLevelofDetailBias() -*/ -float QOpenGLTexture::levelofDetailBias() const -{ - Q_D(const QOpenGLTexture); - return d->levelOfDetailBias; -} - -#ifndef QT_NO_DEBUG_STREAM -QDebug operator<<(QDebug debug, const QOpenGLTexture *t) -{ - QDebugStateSaver saver(debug); - debug.nospace(); - debug << "QOpenGLTexture("; - if (t) { - const QOpenGLTexturePrivate *d = t->d_ptr.data(); - debug << d->target << ", bindingTarget=" << d->bindingTarget - << ", size=[" << d->dimensions[0] - << ", " << d->dimensions[1]; - if (d->target == QOpenGLTexture::Target3D) - debug << ", " << d->dimensions[2]; - debug << "], format=" << d->format << ", formatClass=" << d->formatClass; - if (t->isCreated()) - debug << ", textureId=" << d->textureId; - if (t->isBound()) - debug << ", [bound]"; - if (t->isTextureView()) - debug << ", [view]"; - if (d->fixedSamplePositions) - debug << ", [fixedSamplePositions]"; - debug << ", mipLevels=" << d->requestedMipLevels << ", layers=" << d->layers - << ", faces=" << d->faces << ", samples=" << d->samples - << ", depthStencilMode=" << d->depthStencilMode << ", comparisonFunction=" - << d->comparisonFunction << ", comparisonMode=" << d->comparisonMode - << ", features=" << d->features << ", minificationFilter=" << d->minFilter - << ", magnificationFilter=" << d->magFilter << ", wrapMode=" << d->wrapModes[0]; - } else { - debug << '0'; - } - debug << ')'; - return debug; -} -#endif // QT_NO_DEBUG_STREAM - -QT_END_NAMESPACE diff --git a/src/gui/opengl/qopengltexture.h b/src/gui/opengl/qopengltexture.h deleted file mode 100644 index 7d984babc8..0000000000 --- a/src/gui/opengl/qopengltexture.h +++ /dev/null @@ -1,663 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB). -** 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 QOPENGLABSTRACTTEXTURE_H -#define QOPENGLABSTRACTTEXTURE_H - -#include <QtGui/qtguiglobal.h> - -#ifndef QT_NO_OPENGL - -#include <QtGui/qopengl.h> -#include <QtGui/qimage.h> -#include <QtCore/QScopedPointer> - -QT_BEGIN_NAMESPACE - -class QDebug; -class QOpenGLTexturePrivate; -class QOpenGLPixelTransferOptions; - -class Q_GUI_EXPORT QOpenGLTexture -{ - Q_GADGET -public: - enum Target { - Target1D = 0x0DE0, // GL_TEXTURE_1D - Target1DArray = 0x8C18, // GL_TEXTURE_1D_ARRAY - Target2D = 0x0DE1, // GL_TEXTURE_2D - Target2DArray = 0x8C1A, // GL_TEXTURE_2D_ARRAY - Target3D = 0x806F, // GL_TEXTURE_3D - TargetCubeMap = 0x8513, // GL_TEXTURE_CUBE_MAP - TargetCubeMapArray = 0x9009, // GL_TEXTURE_CUBE_MAP_ARRAY - Target2DMultisample = 0x9100, // GL_TEXTURE_2D_MULTISAMPLE - Target2DMultisampleArray = 0x9102, // GL_TEXTURE_2D_MULTISAMPLE_ARRAY - TargetRectangle = 0x84F5, // GL_TEXTURE_RECTANGLE - TargetBuffer = 0x8C2A // GL_TEXTURE_BUFFER - }; - Q_ENUM(Target) - - enum BindingTarget { - BindingTarget1D = 0x8068, // GL_TEXTURE_BINDING_1D - BindingTarget1DArray = 0x8C1C, // GL_TEXTURE_BINDING_1D_ARRAY - BindingTarget2D = 0x8069, // GL_TEXTURE_BINDING_2D - BindingTarget2DArray = 0x8C1D, // GL_TEXTURE_BINDING_2D_ARRAY - BindingTarget3D = 0x806A, // GL_TEXTURE_BINDING_3D - BindingTargetCubeMap = 0x8514, // GL_TEXTURE_BINDING_CUBE_MAP - BindingTargetCubeMapArray = 0x900A, // GL_TEXTURE_BINDING_CUBE_MAP_ARRAY - BindingTarget2DMultisample = 0x9104, // GL_TEXTURE_BINDING_2D_MULTISAMPLE - BindingTarget2DMultisampleArray = 0x9105, // GL_TEXTURE_BINDING_2D_MULTISAMPLE_ARRAY - BindingTargetRectangle = 0x84F6, // GL_TEXTURE_BINDING_RECTANGLE - BindingTargetBuffer = 0x8C2C // GL_TEXTURE_BINDING_BUFFER - }; - Q_ENUM(BindingTarget) - - enum MipMapGeneration { - GenerateMipMaps, - DontGenerateMipMaps - }; - Q_ENUM(MipMapGeneration) - - enum TextureUnitReset { - ResetTextureUnit, - DontResetTextureUnit - }; - Q_ENUM(TextureUnitReset) - - enum TextureFormat { - NoFormat = 0, // GL_NONE - - // Unsigned normalized formats - R8_UNorm = 0x8229, // GL_R8 - RG8_UNorm = 0x822B, // GL_RG8 - RGB8_UNorm = 0x8051, // GL_RGB8 - RGBA8_UNorm = 0x8058, // GL_RGBA8 - - R16_UNorm = 0x822A, // GL_R16 - RG16_UNorm = 0x822C, // GL_RG16 - RGB16_UNorm = 0x8054, // GL_RGB16 - RGBA16_UNorm = 0x805B, // GL_RGBA16 - - // Signed normalized formats - R8_SNorm = 0x8F94, // GL_R8_SNORM - RG8_SNorm = 0x8F95, // GL_RG8_SNORM - RGB8_SNorm = 0x8F96, // GL_RGB8_SNORM - RGBA8_SNorm = 0x8F97, // GL_RGBA8_SNORM - - R16_SNorm = 0x8F98, // GL_R16_SNORM - RG16_SNorm = 0x8F99, // GL_RG16_SNORM - RGB16_SNorm = 0x8F9A, // GL_RGB16_SNORM - RGBA16_SNorm = 0x8F9B, // GL_RGBA16_SNORM - - // Unsigned integer formats - R8U = 0x8232, // GL_R8UI - RG8U = 0x8238, // GL_RG8UI - RGB8U = 0x8D7D, // GL_RGB8UI - RGBA8U = 0x8D7C, // GL_RGBA8UI - - R16U = 0x8234, // GL_R16UI - RG16U = 0x823A, // GL_RG16UI - RGB16U = 0x8D77, // GL_RGB16UI - RGBA16U = 0x8D76, // GL_RGBA16UI - - R32U = 0x8236, // GL_R32UI - RG32U = 0x823C, // GL_RG32UI - RGB32U = 0x8D71, // GL_RGB32UI - RGBA32U = 0x8D70, // GL_RGBA32UI - - // Signed integer formats - R8I = 0x8231, // GL_R8I - RG8I = 0x8237, // GL_RG8I - RGB8I = 0x8D8F, // GL_RGB8I - RGBA8I = 0x8D8E, // GL_RGBA8I - - R16I = 0x8233, // GL_R16I - RG16I = 0x8239, // GL_RG16I - RGB16I = 0x8D89, // GL_RGB16I - RGBA16I = 0x8D88, // GL_RGBA16I - - R32I = 0x8235, // GL_R32I - RG32I = 0x823B, // GL_RG32I - RGB32I = 0x8D83, // GL_RGB32I - RGBA32I = 0x8D82, // GL_RGBA32I - - // Floating point formats - R16F = 0x822D, // GL_R16F - RG16F = 0x822F, // GL_RG16F - RGB16F = 0x881B, // GL_RGB16F - RGBA16F = 0x881A, // GL_RGBA16F - - R32F = 0x822E, // GL_R32F - RG32F = 0x8230, // GL_RG32F - RGB32F = 0x8815, // GL_RGB32F - RGBA32F = 0x8814, // GL_RGBA32F - - // Packed formats - RGB9E5 = 0x8C3D, // GL_RGB9_E5 - RG11B10F = 0x8C3A, // GL_R11F_G11F_B10F - RG3B2 = 0x2A10, // GL_R3_G3_B2 - R5G6B5 = 0x8D62, // GL_RGB565 - RGB5A1 = 0x8057, // GL_RGB5_A1 - RGBA4 = 0x8056, // GL_RGBA4 - RGB10A2 = 0x906F, // GL_RGB10_A2UI - - // Depth formats - D16 = 0x81A5, // GL_DEPTH_COMPONENT16 - D24 = 0x81A6, // GL_DEPTH_COMPONENT24 - D24S8 = 0x88F0, // GL_DEPTH24_STENCIL8 - D32 = 0x81A7, // GL_DEPTH_COMPONENT32 - D32F = 0x8CAC, // GL_DEPTH_COMPONENT32F - D32FS8X24 = 0x8CAD, // GL_DEPTH32F_STENCIL8 - S8 = 0x8D48, // GL_STENCIL_INDEX8 - - // Compressed formats - RGB_DXT1 = 0x83F0, // GL_COMPRESSED_RGB_S3TC_DXT1_EXT - RGBA_DXT1 = 0x83F1, // GL_COMPRESSED_RGBA_S3TC_DXT1_EXT - RGBA_DXT3 = 0x83F2, // GL_COMPRESSED_RGBA_S3TC_DXT3_EXT - RGBA_DXT5 = 0x83F3, // GL_COMPRESSED_RGBA_S3TC_DXT5_EXT - R_ATI1N_UNorm = 0x8DBB, // GL_COMPRESSED_RED_RGTC1 - R_ATI1N_SNorm = 0x8DBC, // GL_COMPRESSED_SIGNED_RED_RGTC1 - RG_ATI2N_UNorm = 0x8DBD, // GL_COMPRESSED_RG_RGTC2 - RG_ATI2N_SNorm = 0x8DBE, // GL_COMPRESSED_SIGNED_RG_RGTC2 - RGB_BP_UNSIGNED_FLOAT = 0x8E8F, // GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB - RGB_BP_SIGNED_FLOAT = 0x8E8E, // GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB - RGB_BP_UNorm = 0x8E8C, // GL_COMPRESSED_RGBA_BPTC_UNORM_ARB - R11_EAC_UNorm = 0x9270, // GL_COMPRESSED_R11_EAC - R11_EAC_SNorm = 0x9271, // GL_COMPRESSED_SIGNED_R11_EAC - RG11_EAC_UNorm = 0x9272, // GL_COMPRESSED_RG11_EAC - RG11_EAC_SNorm = 0x9273, // GL_COMPRESSED_SIGNED_RG11_EAC - RGB8_ETC2 = 0x9274, // GL_COMPRESSED_RGB8_ETC2 - SRGB8_ETC2 = 0x9275, // GL_COMPRESSED_SRGB8_ETC2 - RGB8_PunchThrough_Alpha1_ETC2 = 0x9276, // GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 - SRGB8_PunchThrough_Alpha1_ETC2 = 0x9277, // GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 - RGBA8_ETC2_EAC = 0x9278, // GL_COMPRESSED_RGBA8_ETC2_EAC - SRGB8_Alpha8_ETC2_EAC = 0x9279, // GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC - RGB8_ETC1 = 0x8D64, // GL_ETC1_RGB8_OES - RGBA_ASTC_4x4 = 0x93B0, // GL_COMPRESSED_RGBA_ASTC_4x4_KHR - RGBA_ASTC_5x4 = 0x93B1, // GL_COMPRESSED_RGBA_ASTC_5x4_KHR - RGBA_ASTC_5x5 = 0x93B2, // GL_COMPRESSED_RGBA_ASTC_5x5_KHR - RGBA_ASTC_6x5 = 0x93B3, // GL_COMPRESSED_RGBA_ASTC_6x5_KHR - RGBA_ASTC_6x6 = 0x93B4, // GL_COMPRESSED_RGBA_ASTC_6x6_KHR - RGBA_ASTC_8x5 = 0x93B5, // GL_COMPRESSED_RGBA_ASTC_8x5_KHR - RGBA_ASTC_8x6 = 0x93B6, // GL_COMPRESSED_RGBA_ASTC_8x6_KHR - RGBA_ASTC_8x8 = 0x93B7, // GL_COMPRESSED_RGBA_ASTC_8x8_KHR - RGBA_ASTC_10x5 = 0x93B8, // GL_COMPRESSED_RGBA_ASTC_10x5_KHR - RGBA_ASTC_10x6 = 0x93B9, // GL_COMPRESSED_RGBA_ASTC_10x6_KHR - RGBA_ASTC_10x8 = 0x93BA, // GL_COMPRESSED_RGBA_ASTC_10x8_KHR - RGBA_ASTC_10x10 = 0x93BB, // GL_COMPRESSED_RGBA_ASTC_10x10_KHR - RGBA_ASTC_12x10 = 0x93BC, // GL_COMPRESSED_RGBA_ASTC_12x10_KHR - RGBA_ASTC_12x12 = 0x93BD, // GL_COMPRESSED_RGBA_ASTC_12x12_KHR - SRGB8_Alpha8_ASTC_4x4 = 0x93D0, // GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR - SRGB8_Alpha8_ASTC_5x4 = 0x93D1, // GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR - SRGB8_Alpha8_ASTC_5x5 = 0x93D2, // GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR - SRGB8_Alpha8_ASTC_6x5 = 0x93D3, // GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR - SRGB8_Alpha8_ASTC_6x6 = 0x93D4, // GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR - SRGB8_Alpha8_ASTC_8x5 = 0x93D5, // GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR - SRGB8_Alpha8_ASTC_8x6 = 0x93D6, // GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR - SRGB8_Alpha8_ASTC_8x8 = 0x93D7, // GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR - SRGB8_Alpha8_ASTC_10x5 = 0x93D8, // GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR - SRGB8_Alpha8_ASTC_10x6 = 0x93D9, // GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR - SRGB8_Alpha8_ASTC_10x8 = 0x93DA, // GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR - SRGB8_Alpha8_ASTC_10x10 = 0x93DB, // GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR - SRGB8_Alpha8_ASTC_12x10 = 0x93DC, // GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR - SRGB8_Alpha8_ASTC_12x12 = 0x93DD, // GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR - - // sRGB formats - SRGB8 = 0x8C41, // GL_SRGB8 - SRGB8_Alpha8 = 0x8C43, // GL_SRGB8_ALPHA8 - SRGB_DXT1 = 0x8C4C, // GL_COMPRESSED_SRGB_S3TC_DXT1_EXT - SRGB_Alpha_DXT1 = 0x8C4D, // GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT - SRGB_Alpha_DXT3 = 0x8C4E, // GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT - SRGB_Alpha_DXT5 = 0x8C4F, // GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT - SRGB_BP_UNorm = 0x8E8D, // GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB - - // ES 2 formats - DepthFormat = 0x1902, // GL_DEPTH_COMPONENT - AlphaFormat = 0x1906, // GL_ALPHA - RGBFormat = 0x1907, // GL_RGB - RGBAFormat = 0x1908, // GL_RGBA - LuminanceFormat = 0x1909, // GL_LUMINANCE - LuminanceAlphaFormat = 0x190A - - }; - Q_ENUM(TextureFormat) - - // This is not used externally yet but is reserved to allow checking of - // compatibility between texture formats -#ifndef Q_QDOC - enum TextureFormatClass { - NoFormatClass, - FormatClass_128Bit, - FormatClass_96Bit, - FormatClass_64Bit, - FormatClass_48Bit, - FormatClass_32Bit, - FormatClass_24Bit, - FormatClass_16Bit, - FormatClass_8Bit, - FormatClass_RGTC1_R, - FormatClass_RGTC2_RG, - FormatClass_BPTC_Unorm, - FormatClass_BPTC_Float, - FormatClass_S3TC_DXT1_RGB, - FormatClass_S3TC_DXT1_RGBA, - FormatClass_S3TC_DXT3_RGBA, - FormatClass_S3TC_DXT5_RGBA, - FormatClass_Unique - }; -#endif - - enum CubeMapFace { - CubeMapPositiveX = 0x8515, // GL_TEXTURE_CUBE_MAP_POSITIVE_X - CubeMapNegativeX = 0x8516, // GL_TEXTURE_CUBE_MAP_NEGATIVE_X - CubeMapPositiveY = 0x8517, // GL_TEXTURE_CUBE_MAP_POSITIVE_Y - CubeMapNegativeY = 0x8518, // GL_TEXTURE_CUBE_MAP_NEGATIVE_Y - CubeMapPositiveZ = 0x8519, // GL_TEXTURE_CUBE_MAP_POSITIVE_Z - CubeMapNegativeZ = 0x851A // GL_TEXTURE_CUBE_MAP_NEGATIVE_Z - }; - Q_ENUM(CubeMapFace) - - enum PixelFormat { - NoSourceFormat = 0, // GL_NONE - Red = 0x1903, // GL_RED - RG = 0x8227, // GL_RG - RGB = 0x1907, // GL_RGB - BGR = 0x80E0, // GL_BGR - RGBA = 0x1908, // GL_RGBA - BGRA = 0x80E1, // GL_BGRA - Red_Integer = 0x8D94, // GL_RED_INTEGER - RG_Integer = 0x8228, // GL_RG_INTEGER - RGB_Integer = 0x8D98, // GL_RGB_INTEGER - BGR_Integer = 0x8D9A, // GL_BGR_INTEGER - RGBA_Integer = 0x8D99, // GL_RGBA_INTEGER - BGRA_Integer = 0x8D9B, // GL_BGRA_INTEGER - Stencil = 0x1901, // GL_STENCIL_INDEX - Depth = 0x1902, // GL_DEPTH_COMPONENT - DepthStencil = 0x84F9, // GL_DEPTH_STENCIL - Alpha = 0x1906, // GL_ALPHA - Luminance = 0x1909, // GL_LUMINANCE - LuminanceAlpha = 0x190A // GL_LUMINANCE_ALPHA - }; - Q_ENUM(PixelFormat) - - enum PixelType { - NoPixelType = 0, // GL_NONE - Int8 = 0x1400, // GL_BYTE - UInt8 = 0x1401, // GL_UNSIGNED_BYTE - Int16 = 0x1402, // GL_SHORT - UInt16 = 0x1403, // GL_UNSIGNED_SHORT - Int32 = 0x1404, // GL_INT - UInt32 = 0x1405, // GL_UNSIGNED_INT - Float16 = 0x140B, // GL_HALF_FLOAT - Float16OES = 0x8D61, // GL_HALF_FLOAT_OES - Float32 = 0x1406, // GL_FLOAT - UInt32_RGB9_E5 = 0x8C3E, // GL_UNSIGNED_INT_5_9_9_9_REV - UInt32_RG11B10F = 0x8C3B, // GL_UNSIGNED_INT_10F_11F_11F_REV - UInt8_RG3B2 = 0x8032, // GL_UNSIGNED_BYTE_3_3_2 - UInt8_RG3B2_Rev = 0x8362, // GL_UNSIGNED_BYTE_2_3_3_REV - UInt16_RGB5A1 = 0x8034, // GL_UNSIGNED_SHORT_5_5_5_1 - UInt16_RGB5A1_Rev = 0x8366, // GL_UNSIGNED_SHORT_1_5_5_5_REV - UInt16_R5G6B5 = 0x8363, // GL_UNSIGNED_SHORT_5_6_5 - UInt16_R5G6B5_Rev = 0x8364, // GL_UNSIGNED_SHORT_5_6_5_REV - UInt16_RGBA4 = 0x8033, // GL_UNSIGNED_SHORT_4_4_4_4 - UInt16_RGBA4_Rev = 0x8365, // GL_UNSIGNED_SHORT_4_4_4_4_REV - UInt32_RGBA8 = 0x8035, // GL_UNSIGNED_INT_8_8_8_8 - UInt32_RGBA8_Rev = 0x8367, // GL_UNSIGNED_INT_8_8_8_8_REV - UInt32_RGB10A2 = 0x8036, // GL_UNSIGNED_INT_10_10_10_2 - UInt32_RGB10A2_Rev = 0x8368, // GL_UNSIGNED_INT_2_10_10_10_REV - UInt32_D24S8 = 0x84FA, // GL_UNSIGNED_INT_24_8 - Float32_D32_UInt32_S8_X24 = 0x8DAD // GL_FLOAT_32_UNSIGNED_INT_24_8_REV - }; - Q_ENUM(PixelType) - - enum SwizzleComponent { - SwizzleRed = 0x8E42, // GL_TEXTURE_SWIZZLE_R - SwizzleGreen = 0x8E43, // GL_TEXTURE_SWIZZLE_G - SwizzleBlue = 0x8E44, // GL_TEXTURE_SWIZZLE_B - SwizzleAlpha = 0x8E45 // GL_TEXTURE_SWIZZLE_A - }; - Q_ENUM(SwizzleComponent) - - enum SwizzleValue { - RedValue = 0x1903, // GL_RED - GreenValue = 0x1904, // GL_GREEN - BlueValue = 0x1905, // GL_BLUE - AlphaValue = 0x1906, // GL_ALPHA - ZeroValue = 0, // GL_ZERO - OneValue = 1 // GL_ONE - }; - Q_ENUM(SwizzleValue) - - enum WrapMode { - Repeat = 0x2901, // GL_REPEAT - MirroredRepeat = 0x8370, // GL_MIRRORED_REPEAT - ClampToEdge = 0x812F, // GL_CLAMP_TO_EDGE - ClampToBorder = 0x812D // GL_CLAMP_TO_BORDER - }; - Q_ENUM(WrapMode) - - enum CoordinateDirection { - DirectionS = 0x2802, // GL_TEXTURE_WRAP_S - DirectionT = 0x2803, // GL_TEXTURE_WRAP_T - DirectionR = 0x8072 // GL_TEXTURE_WRAP_R - }; - Q_ENUM(CoordinateDirection) - - // Features - enum Feature { - ImmutableStorage = 0x00000001, - ImmutableMultisampleStorage = 0x00000002, - TextureRectangle = 0x00000004, - TextureArrays = 0x00000008, - Texture3D = 0x00000010, - TextureMultisample = 0x00000020, - TextureBuffer = 0x00000040, - TextureCubeMapArrays = 0x00000080, - Swizzle = 0x00000100, - StencilTexturing = 0x00000200, - AnisotropicFiltering = 0x00000400, - NPOTTextures = 0x00000800, - NPOTTextureRepeat = 0x00001000, - Texture1D = 0x00002000, - TextureComparisonOperators = 0x00004000, - TextureMipMapLevel = 0x00008000, -#ifndef Q_QDOC - MaxFeatureFlag = 0x00010000 -#endif - }; - Q_DECLARE_FLAGS(Features, Feature) - Q_ENUM(Feature) - - explicit QOpenGLTexture(Target target); - explicit QOpenGLTexture(const QImage& image, MipMapGeneration genMipMaps = GenerateMipMaps); - ~QOpenGLTexture(); - - Target target() const; - - // Creation and destruction - bool create(); - void destroy(); - bool isCreated() const; - GLuint textureId() const; - - // Binding and releasing - void bind(); - void bind(uint unit, TextureUnitReset reset = DontResetTextureUnit); - void release(); - void release(uint unit, TextureUnitReset reset = DontResetTextureUnit); - - bool isBound() const; - bool isBound(uint unit); - static GLuint boundTextureId(BindingTarget target); - static GLuint boundTextureId(uint unit, BindingTarget target); - - // Storage allocation - void setFormat(TextureFormat format); - TextureFormat format() const; - void setSize(int width, int height = 1, int depth = 1); - int width() const; - int height() const; - int depth() const; - void setMipLevels(int levels); - int mipLevels() const; - int maximumMipLevels() const; - void setLayers(int layers); - int layers() const; - int faces() const; - void setSamples(int samples); - int samples() const; - void setFixedSamplePositions(bool fixed); - bool isFixedSamplePositions() const; - void allocateStorage(); - void allocateStorage(PixelFormat pixelFormat, PixelType pixelType); - bool isStorageAllocated() const; - - QOpenGLTexture *createTextureView(Target target, - TextureFormat viewFormat, - int minimumMipmapLevel, int maximumMipmapLevel, - int minimumLayer, int maximumLayer) const; - bool isTextureView() const; - - // Pixel transfer - // ### Qt 6: remove the non-const void * overloads -#if QT_DEPRECATED_SINCE(5, 3) - QT_DEPRECATED void setData(int mipLevel, int layer, CubeMapFace cubeFace, - PixelFormat sourceFormat, PixelType sourceType, - void *data, const QOpenGLPixelTransferOptions * const options = nullptr); - QT_DEPRECATED void setData(int mipLevel, int layer, - PixelFormat sourceFormat, PixelType sourceType, - void *data, const QOpenGLPixelTransferOptions * const options = nullptr); - QT_DEPRECATED void setData(int mipLevel, - PixelFormat sourceFormat, PixelType sourceType, - void *data, const QOpenGLPixelTransferOptions * const options = nullptr); - QT_DEPRECATED void setData(PixelFormat sourceFormat, PixelType sourceType, - void *data, const QOpenGLPixelTransferOptions * const options = nullptr); -#endif // QT_DEPRECATED_SINCE(5, 3) - - void setData(int mipLevel, int layer, CubeMapFace cubeFace, - PixelFormat sourceFormat, PixelType sourceType, - const void *data, const QOpenGLPixelTransferOptions * const options = nullptr); - void setData(int mipLevel, int layer, int layerCount, CubeMapFace cubeFace, - PixelFormat sourceFormat, PixelType sourceType, - const void *data, const QOpenGLPixelTransferOptions * const options = nullptr); - void setData(int mipLevel, int layer, - PixelFormat sourceFormat, PixelType sourceType, - const void *data, const QOpenGLPixelTransferOptions * const options = nullptr); - void setData(int mipLevel, - PixelFormat sourceFormat, PixelType sourceType, - const void *data, const QOpenGLPixelTransferOptions * const options = nullptr); - void setData(PixelFormat sourceFormat, PixelType sourceType, - const void *data, const QOpenGLPixelTransferOptions * const options = nullptr); - - void setData(int xOffset, int yOffset, int zOffset, - int width, int height, int depth, - PixelFormat sourceFormat, PixelType sourceType, - const void *data, const QOpenGLPixelTransferOptions * const options = nullptr); - void setData(int xOffset, int yOffset, int zOffset, - int width, int height, int depth, int mipLevel, - PixelFormat sourceFormat, PixelType sourceType, - const void *data, const QOpenGLPixelTransferOptions * const options = nullptr); - void setData(int xOffset, int yOffset, int zOffset, - int width, int height, int depth, - int mipLevel, int layer, - PixelFormat sourceFormat, PixelType sourceType, - const void *data, const QOpenGLPixelTransferOptions * const options = nullptr); - void setData(int xOffset, int yOffset, int zOffset, - int width, int height, int depth, - int mipLevel, int layer, - CubeMapFace cubeFace, - PixelFormat sourceFormat, PixelType sourceType, - const void *data, const QOpenGLPixelTransferOptions * const options = nullptr); - void setData(int xOffset, int yOffset, int zOffset, - int width, int height, int depth, - int mipLevel, int layer, - CubeMapFace cubeFace, int layerCount, - PixelFormat sourceFormat, PixelType sourceType, - const void *data, const QOpenGLPixelTransferOptions * const options = nullptr); - - // Compressed data upload - // ### Qt 6: remove the non-const void * overloads -#if QT_DEPRECATED_SINCE(5, 3) - QT_DEPRECATED void setCompressedData(int mipLevel, int layer, CubeMapFace cubeFace, - int dataSize, void *data, - const QOpenGLPixelTransferOptions * const options = nullptr); - QT_DEPRECATED void setCompressedData(int mipLevel, int layer, - int dataSize, void *data, - const QOpenGLPixelTransferOptions * const options = nullptr); - QT_DEPRECATED void setCompressedData(int mipLevel, int dataSize, void *data, - const QOpenGLPixelTransferOptions * const options = nullptr); - QT_DEPRECATED void setCompressedData(int dataSize, void *data, - const QOpenGLPixelTransferOptions * const options = nullptr); -#endif // QT_DEPRECATED_SINCE(5, 3) - - void setCompressedData(int mipLevel, int layer, CubeMapFace cubeFace, - int dataSize, const void *data, - const QOpenGLPixelTransferOptions * const options = nullptr); - void setCompressedData(int mipLevel, int layer, int layerCount, CubeMapFace cubeFace, - int dataSize, const void *data, - const QOpenGLPixelTransferOptions * const options = nullptr); - void setCompressedData(int mipLevel, int layer, - int dataSize, const void *data, - const QOpenGLPixelTransferOptions * const options = nullptr); - void setCompressedData(int mipLevel, int dataSize, const void *data, - const QOpenGLPixelTransferOptions * const options = nullptr); - void setCompressedData(int dataSize, const void *data, - const QOpenGLPixelTransferOptions * const options = nullptr); - - // Helpful overloads for setData - void setData(const QImage& image, MipMapGeneration genMipMaps = GenerateMipMaps); - - static bool hasFeature(Feature feature); - - // Texture Parameters - void setMipBaseLevel(int baseLevel); - int mipBaseLevel() const; - void setMipMaxLevel(int maxLevel); - int mipMaxLevel() const; - void setMipLevelRange(int baseLevel, int maxLevel); - QPair<int, int> mipLevelRange() const; - - void setAutoMipMapGenerationEnabled(bool enabled); - bool isAutoMipMapGenerationEnabled() const; - - void generateMipMaps(); - void generateMipMaps(int baseLevel, bool resetBaseLevel = true); - - void setSwizzleMask(SwizzleComponent component, SwizzleValue value); - void setSwizzleMask(SwizzleValue r, SwizzleValue g, - SwizzleValue b, SwizzleValue a); - SwizzleValue swizzleMask(SwizzleComponent component) const; - - enum DepthStencilMode { - DepthMode = 0x1902, // GL_DEPTH_COMPONENT - StencilMode = 0x1901 // GL_STENCIL_INDEX - }; - Q_ENUM(DepthStencilMode) - - void setDepthStencilMode(DepthStencilMode mode); - DepthStencilMode depthStencilMode() const; - - enum ComparisonFunction { - CompareLessEqual = 0x0203, // GL_LEQUAL - CompareGreaterEqual = 0x0206, // GL_GEQUAL - CompareLess = 0x0201, // GL_LESS - CompareGreater = 0x0204, // GL_GREATER - CompareEqual = 0x0202, // GL_EQUAL - CommpareNotEqual = 0x0205, // GL_NOTEQUAL - CompareAlways = 0x0207, // GL_ALWAYS - CompareNever = 0x0200 // GL_NEVER - }; - Q_ENUM(ComparisonFunction) - - void setComparisonFunction(ComparisonFunction function); - ComparisonFunction comparisonFunction() const; - - enum ComparisonMode { - CompareRefToTexture = 0x884E, // GL_COMPARE_REF_TO_TEXTURE - CompareNone = 0x0000 // GL_NONE - }; - - void setComparisonMode(ComparisonMode mode); - ComparisonMode comparisonMode() const; - - // Sampling Parameters - enum Filter { - Nearest = 0x2600, // GL_NEAREST - Linear = 0x2601, // GL_LINEAR - NearestMipMapNearest = 0x2700, // GL_NEAREST_MIPMAP_NEAREST - NearestMipMapLinear = 0x2702, // GL_NEAREST_MIPMAP_LINEAR - LinearMipMapNearest = 0x2701, // GL_LINEAR_MIPMAP_NEAREST - LinearMipMapLinear = 0x2703 // GL_LINEAR_MIPMAP_LINEAR - }; - Q_ENUM(Filter) - - void setMinificationFilter(Filter filter); - Filter minificationFilter() const; - void setMagnificationFilter(Filter filter); - Filter magnificationFilter() const; - void setMinMagFilters(Filter minificationFilter, - Filter magnificationFilter); - QPair<Filter, Filter> minMagFilters() const; - void setMaximumAnisotropy(float anisotropy); - float maximumAnisotropy() const; - - void setWrapMode(WrapMode mode); - void setWrapMode(CoordinateDirection direction, WrapMode mode); - WrapMode wrapMode(CoordinateDirection direction) const; - - void setBorderColor(QColor color); - void setBorderColor(float r, float g, float b, float a); - void setBorderColor(int r, int g, int b, int a); - void setBorderColor(uint r, uint g, uint b, uint a); - - QColor borderColor() const; - void borderColor(float *border) const; - void borderColor(int *border) const; - void borderColor(unsigned int *border) const; - - void setMinimumLevelOfDetail(float value); - float minimumLevelOfDetail() const; - void setMaximumLevelOfDetail(float value); - float maximumLevelOfDetail() const; - void setLevelOfDetailRange(float min, float max); - QPair<float, float> levelOfDetailRange() const; - void setLevelofDetailBias(float bias); - float levelofDetailBias() const; - -#ifndef QT_NO_DEBUG_STREAM - friend Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QOpenGLTexture *t); -#endif - -private: - Q_DISABLE_COPY(QOpenGLTexture) - Q_DECLARE_PRIVATE(QOpenGLTexture) - QScopedPointer<QOpenGLTexturePrivate> d_ptr; -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLTexture::Features) - -#ifndef QT_NO_DEBUG_STREAM -Q_GUI_EXPORT QDebug operator<<(QDebug debug, const QOpenGLTexture *t); -#endif - -QT_END_NAMESPACE - -#endif // QT_NO_OPENGL - -#endif // QOPENGLABSTRACTTEXTURE_H diff --git a/src/gui/opengl/qopengltexture_p.h b/src/gui/opengl/qopengltexture_p.h deleted file mode 100644 index 9f3457ad0a..0000000000 --- a/src/gui/opengl/qopengltexture_p.h +++ /dev/null @@ -1,184 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB). -** 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 QABSTRACTOPENGLTEXTURE_P_H -#define QABSTRACTOPENGLTEXTURE_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#ifndef QT_NO_OPENGL - -#include <QtGui/private/qtguiglobal_p.h> -#include "private/qobject_p.h" -#include "qopengltexture.h" -#include "qopengl.h" - -#include <cmath> - -namespace { -inline double qLog2(const double x) -{ - return std::log(x) / std::log(2.0); -} -} - -QT_BEGIN_NAMESPACE - -class QOpenGLContext; -class QOpenGLTextureHelper; -class QOpenGLFunctions; - -class QOpenGLTexturePrivate -{ -public: - QOpenGLTexturePrivate(QOpenGLTexture::Target textureTarget, - QOpenGLTexture *qq); - ~QOpenGLTexturePrivate(); - - Q_DECLARE_PUBLIC(QOpenGLTexture) - - void resetFuncs(QOpenGLTextureHelper *funcs); - void initializeOpenGLFunctions(); - - bool create(); - void destroy(); - - void bind(); - void bind(uint unit, QOpenGLTexture::TextureUnitReset reset = QOpenGLTexture::DontResetTextureUnit); - void release(); - void release(uint unit, QOpenGLTexture::TextureUnitReset reset = QOpenGLTexture::DontResetTextureUnit); - bool isBound() const; - bool isBound(uint unit) const; - - void allocateStorage(QOpenGLTexture::PixelFormat pixelFormat, QOpenGLTexture::PixelType pixelType); - void allocateMutableStorage(QOpenGLTexture::PixelFormat pixelFormat, QOpenGLTexture::PixelType pixelType); - void allocateImmutableStorage(); - void setData(int mipLevel, int layer, int layerCount, QOpenGLTexture::CubeMapFace cubeFace, - QOpenGLTexture::PixelFormat sourceFormat, QOpenGLTexture::PixelType sourceType, - const void *data, const QOpenGLPixelTransferOptions * const options); - void setData(int xOffset, int yOffset, int zOffset, int width, int height, int depth, - int mipLevel, int layer, int layerCount, QOpenGLTexture::CubeMapFace cubeFace, - QOpenGLTexture::PixelFormat sourceFormat, QOpenGLTexture::PixelType sourceType, - const void *data, const QOpenGLPixelTransferOptions * const options); - void setCompressedData(int mipLevel, int layer, int layerCount, QOpenGLTexture::CubeMapFace cubeFace, - int dataSize, const void *data, - const QOpenGLPixelTransferOptions * const options); - - - void setWrapMode(QOpenGLTexture::WrapMode mode); - void setWrapMode(QOpenGLTexture::CoordinateDirection direction, QOpenGLTexture::WrapMode mode); - QOpenGLTexture::WrapMode wrapMode(QOpenGLTexture::CoordinateDirection direction) const; - - QOpenGLTexture *createTextureView(QOpenGLTexture::Target target, QOpenGLTexture::TextureFormat viewFormat, - int minimumMipmapLevel, int maximumMipmapLevel, - int minimumLayer, int maximumLayer) const; - - int evaluateMipLevels() const; - - inline int maximumMipLevelCount() const - { - return 1 + std::floor(qLog2(qMax(dimensions[0], qMax(dimensions[1], dimensions[2])))); - } - - static inline int mipLevelSize(int mipLevel, int baseLevelSize) - { - return std::floor(double(qMax(1, baseLevelSize >> mipLevel))); - } - - bool isUsingImmutableStorage() const; - - QOpenGLTexture *q_ptr; - QOpenGLContext *context; - QOpenGLTexture::Target target; - QOpenGLTexture::BindingTarget bindingTarget; - GLuint textureId; - QOpenGLTexture::TextureFormat format; - QOpenGLTexture::TextureFormatClass formatClass; - int dimensions[3]; - int requestedMipLevels; - int mipLevels; - int layers; - int faces; - - int samples; - bool fixedSamplePositions; - - int baseLevel; - int maxLevel; - - QOpenGLTexture::SwizzleValue swizzleMask[4]; - QOpenGLTexture::DepthStencilMode depthStencilMode; - QOpenGLTexture::ComparisonFunction comparisonFunction; - QOpenGLTexture::ComparisonMode comparisonMode; - - QOpenGLTexture::Filter minFilter; - QOpenGLTexture::Filter magFilter; - float maxAnisotropy; - QOpenGLTexture::WrapMode wrapModes[3]; - QVariantList borderColor; - float minLevelOfDetail; - float maxLevelOfDetail; - float levelOfDetailBias; - - bool textureView; - bool autoGenerateMipMaps; - bool storageAllocated; - - QOpenGLTextureHelper *texFuncs; - QOpenGLFunctions *functions; - - QOpenGLTexture::Features features; -}; - -QT_END_NAMESPACE - -#undef Q_CALL_MEMBER_FUNCTION - -#endif // QT_NO_OPENGL - -#endif // QABSTRACTOPENGLTEXTURE_P_H diff --git a/src/gui/opengl/qopengltextureblitter.cpp b/src/gui/opengl/qopengltextureblitter.cpp deleted file mode 100644 index b709f2f639..0000000000 --- a/src/gui/opengl/qopengltextureblitter.cpp +++ /dev/null @@ -1,682 +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 "qopengltextureblitter.h" - -#include <QtGui/QOpenGLBuffer> -#include <QtGui/QOpenGLShaderProgram> -#include <QtGui/QOpenGLVertexArrayObject> -#include <QtGui/QOpenGLContext> -#include <QtGui/QOpenGLFunctions> - -#ifndef GL_TEXTURE_EXTERNAL_OES -#define GL_TEXTURE_EXTERNAL_OES 0x8D65 -#endif - -QT_BEGIN_NAMESPACE - -/*! - \class QOpenGLTextureBlitter - \brief The QOpenGLTextureBlitter class provides a convenient way to draw textured quads via OpenGL. - \since 5.8 - \ingroup painting-3D - \inmodule QtGui - - Drawing textured quads, in order to get the contents of a texture - onto the screen, is a common operation when developing 2D user - interfaces. QOpenGLTextureBlitter provides a convenience class to - avoid repeating vertex data, shader sources, buffer and program - management and matrix calculations. - - For example, a QOpenGLWidget subclass can do the following to draw - the contents rendered into a framebuffer at the pixel position \c{(x, y)}: - - \code - void OpenGLWidget::initializeGL() - { - m_blitter.create(); - m_fbo = new QOpenGLFramebufferObject(size); - } - - void OpenGLWidget::paintGL() - { - m_fbo->bind(); - // update offscreen content - m_fbo->release(); - - m_blitter.bind(); - const QRect targetRect(QPoint(x, y), m_fbo->size()); - const QMatrix4x4 target = QOpenGLTextureBlitter::targetTransform(targetRect, QRect(QPoint(0, 0), m_fbo->size())); - m_blitter.blit(m_fbo->texture(), target, QOpenGLTextureBlitter::OriginBottomLeft); - m_blitter.release(); - } - \endcode - - The blitter implements GLSL shaders both for GLSL 1.00 (suitable - for OpenGL (ES) 2.x and compatibility profiles of newer OpenGL - versions) and version 150 (suitable for core profile contexts with - OpenGL 3.2 and newer). - */ - -static const char vertex_shader150[] = - "#version 150 core\n" - "in vec3 vertexCoord;" - "in vec2 textureCoord;" - "out vec2 uv;" - "uniform mat4 vertexTransform;" - "uniform mat3 textureTransform;" - "void main() {" - " uv = (textureTransform * vec3(textureCoord,1.0)).xy;" - " gl_Position = vertexTransform * vec4(vertexCoord,1.0);" - "}"; - -static const char fragment_shader150[] = - "#version 150 core\n" - "in vec2 uv;" - "out vec4 fragcolor;" - "uniform sampler2D textureSampler;" - "uniform bool swizzle;" - "uniform float opacity;" - "void main() {" - " vec4 tmpFragColor = texture(textureSampler, uv);" - " tmpFragColor.a *= opacity;" - " fragcolor = swizzle ? tmpFragColor.bgra : tmpFragColor;" - "}"; - -static const char vertex_shader[] = - "attribute highp vec3 vertexCoord;" - "attribute highp vec2 textureCoord;" - "varying highp vec2 uv;" - "uniform highp mat4 vertexTransform;" - "uniform highp mat3 textureTransform;" - "void main() {" - " uv = (textureTransform * vec3(textureCoord,1.0)).xy;" - " gl_Position = vertexTransform * vec4(vertexCoord,1.0);" - "}"; - -static const char fragment_shader[] = - "varying highp vec2 uv;" - "uniform sampler2D textureSampler;" - "uniform bool swizzle;" - "uniform highp float opacity;" - "void main() {" - " highp vec4 tmpFragColor = texture2D(textureSampler,uv);" - " tmpFragColor.a *= opacity;" - " gl_FragColor = swizzle ? tmpFragColor.bgra : tmpFragColor;" - "}"; - -static const char fragment_shader_external_oes[] = - "#extension GL_OES_EGL_image_external : require\n" - "varying highp vec2 uv;" - "uniform samplerExternalOES textureSampler;\n" - "uniform bool swizzle;" - "uniform highp float opacity;" - "void main() {" - " highp vec4 tmpFragColor = texture2D(textureSampler, uv);" - " tmpFragColor.a *= opacity;" - " gl_FragColor = swizzle ? tmpFragColor.bgra : tmpFragColor;" - "}"; - -static const GLfloat vertex_buffer_data[] = { - -1,-1, 0, - -1, 1, 0, - 1,-1, 0, - -1, 1, 0, - 1,-1, 0, - 1, 1, 0 -}; - -static const GLfloat texture_buffer_data[] = { - 0, 0, - 0, 1, - 1, 0, - 0, 1, - 1, 0, - 1, 1 -}; - -class TextureBinder -{ -public: - TextureBinder(GLenum target, GLuint textureId) : m_target(target) - { - QOpenGLContext::currentContext()->functions()->glBindTexture(m_target, textureId); - } - ~TextureBinder() - { - QOpenGLContext::currentContext()->functions()->glBindTexture(m_target, 0); - } - -private: - GLenum m_target; -}; - -class QOpenGLTextureBlitterPrivate -{ -public: - enum TextureMatrixUniform { - User, - Identity, - IdentityFlipped - }; - - enum ProgramIndex { - TEXTURE_2D, - TEXTURE_EXTERNAL_OES - }; - - QOpenGLTextureBlitterPrivate() : - swizzle(false), - opacity(1.0f), - vao(new QOpenGLVertexArrayObject), - currentTarget(TEXTURE_2D) - { } - - bool buildProgram(ProgramIndex idx, const char *vs, const char *fs); - - void blit(GLuint texture, const QMatrix4x4 &vertexTransform, const QMatrix3x3 &textureTransform); - void blit(GLuint texture, const QMatrix4x4 &vertexTransform, QOpenGLTextureBlitter::Origin origin); - - void prepareProgram(const QMatrix4x4 &vertexTransform); - - QOpenGLBuffer vertexBuffer; - QOpenGLBuffer textureBuffer; - struct Program { - Program() : - vertexCoordAttribPos(0), - vertexTransformUniformPos(0), - textureCoordAttribPos(0), - textureTransformUniformPos(0), - swizzleUniformPos(0), - opacityUniformPos(0), - swizzle(false), - opacity(0.0f), - textureMatrixUniformState(User) - { } - QScopedPointer<QOpenGLShaderProgram> glProgram; - GLuint vertexCoordAttribPos; - GLuint vertexTransformUniformPos; - GLuint textureCoordAttribPos; - GLuint textureTransformUniformPos; - GLuint swizzleUniformPos; - GLuint opacityUniformPos; - bool swizzle; - float opacity; - TextureMatrixUniform textureMatrixUniformState; - } programs[2]; - bool swizzle; - float opacity; - QScopedPointer<QOpenGLVertexArrayObject> vao; - GLenum currentTarget; -}; - -static inline QOpenGLTextureBlitterPrivate::ProgramIndex targetToProgramIndex(GLenum target) -{ - switch (target) { - case GL_TEXTURE_2D: - return QOpenGLTextureBlitterPrivate::TEXTURE_2D; - case GL_TEXTURE_EXTERNAL_OES: - return QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES; - default: - qWarning("Unsupported texture target 0x%x", target); - return QOpenGLTextureBlitterPrivate::TEXTURE_2D; - } -} - -void QOpenGLTextureBlitterPrivate::prepareProgram(const QMatrix4x4 &vertexTransform) -{ - Program *program = &programs[targetToProgramIndex(currentTarget)]; - - vertexBuffer.bind(); - program->glProgram->setAttributeBuffer(program->vertexCoordAttribPos, GL_FLOAT, 0, 3, 0); - program->glProgram->enableAttributeArray(program->vertexCoordAttribPos); - vertexBuffer.release(); - - program->glProgram->setUniformValue(program->vertexTransformUniformPos, vertexTransform); - - textureBuffer.bind(); - program->glProgram->setAttributeBuffer(program->textureCoordAttribPos, GL_FLOAT, 0, 2, 0); - program->glProgram->enableAttributeArray(program->textureCoordAttribPos); - textureBuffer.release(); - - if (swizzle != program->swizzle) { - program->glProgram->setUniformValue(program->swizzleUniformPos, swizzle); - program->swizzle = swizzle; - } - - if (opacity != program->opacity) { - program->glProgram->setUniformValue(program->opacityUniformPos, opacity); - program->opacity = opacity; - } -} - -void QOpenGLTextureBlitterPrivate::blit(GLuint texture, - const QMatrix4x4 &vertexTransform, - const QMatrix3x3 &textureTransform) -{ - TextureBinder binder(currentTarget, texture); - prepareProgram(vertexTransform); - - Program *program = &programs[targetToProgramIndex(currentTarget)]; - program->glProgram->setUniformValue(program->textureTransformUniformPos, textureTransform); - program->textureMatrixUniformState = User; - - QOpenGLContext::currentContext()->functions()->glDrawArrays(GL_TRIANGLES, 0, 6); -} - -void QOpenGLTextureBlitterPrivate::blit(GLuint texture, - const QMatrix4x4 &vertexTransform, - QOpenGLTextureBlitter::Origin origin) -{ - TextureBinder binder(currentTarget, texture); - prepareProgram(vertexTransform); - - Program *program = &programs[targetToProgramIndex(currentTarget)]; - if (origin == QOpenGLTextureBlitter::OriginTopLeft) { - if (program->textureMatrixUniformState != IdentityFlipped) { - QMatrix3x3 flipped; - flipped(1,1) = -1; - flipped(1,2) = 1; - program->glProgram->setUniformValue(program->textureTransformUniformPos, flipped); - program->textureMatrixUniformState = IdentityFlipped; - } - } else if (program->textureMatrixUniformState != Identity) { - program->glProgram->setUniformValue(program->textureTransformUniformPos, QMatrix3x3()); - program->textureMatrixUniformState = Identity; - } - - QOpenGLContext::currentContext()->functions()->glDrawArrays(GL_TRIANGLES, 0, 6); -} - -bool QOpenGLTextureBlitterPrivate::buildProgram(ProgramIndex idx, const char *vs, const char *fs) -{ - Program *p = &programs[idx]; - - p->glProgram.reset(new QOpenGLShaderProgram); - - p->glProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vs); - p->glProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fs); - p->glProgram->link(); - if (!p->glProgram->isLinked()) { - qWarning() << "Could not link shader program:\n" << p->glProgram->log(); - return false; - } - - p->glProgram->bind(); - - p->vertexCoordAttribPos = p->glProgram->attributeLocation("vertexCoord"); - p->vertexTransformUniformPos = p->glProgram->uniformLocation("vertexTransform"); - p->textureCoordAttribPos = p->glProgram->attributeLocation("textureCoord"); - p->textureTransformUniformPos = p->glProgram->uniformLocation("textureTransform"); - p->swizzleUniformPos = p->glProgram->uniformLocation("swizzle"); - p->opacityUniformPos = p->glProgram->uniformLocation("opacity"); - - p->glProgram->setUniformValue(p->swizzleUniformPos, false); - - // minmize state left set after a create() - p->glProgram->release(); - - return true; -} - -/*! - Constructs a new QOpenGLTextureBlitter instance. - - \note no graphics resources are initialized in the - constructor. This makes it safe to place plain - QOpenGLTextureBlitter members into classes because the actual - initialization that depends on the OpenGL context happens only in - create(). - */ -QOpenGLTextureBlitter::QOpenGLTextureBlitter() - : d_ptr(new QOpenGLTextureBlitterPrivate) -{ -} - -/*! - Destructs the instance. - - \note When the OpenGL context - or a context sharing resources - with it - that was current when calling create() is not current, - graphics resources will not be released. Therefore, it is - recommended to call destroy() manually instead of relying on the - destructor to perform OpenGL resource cleanup. - */ -QOpenGLTextureBlitter::~QOpenGLTextureBlitter() -{ - destroy(); -} - -/*! - Initializes the graphics resources used by the blitter. - - \return \c true if successful, \c false if there was a - failure. Failures can occur when there is no OpenGL context - current on the current thread, or when shader compilation fails - for some reason. - - \sa isCreated(), destroy() - */ -bool QOpenGLTextureBlitter::create() -{ - QOpenGLContext *currentContext = QOpenGLContext::currentContext(); - if (!currentContext) - return false; - - Q_D(QOpenGLTextureBlitter); - - if (d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_2D].glProgram) - return true; - - QSurfaceFormat format = currentContext->format(); - if (format.profile() == QSurfaceFormat::CoreProfile && format.version() >= qMakePair(3,2)) { - if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_2D, vertex_shader150, fragment_shader150)) - return false; - } else { - if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_2D, vertex_shader, fragment_shader)) - return false; - if (supportsExternalOESTarget()) - if (!d->buildProgram(QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES, vertex_shader, fragment_shader_external_oes)) - return false; - } - - // Create and bind the VAO, if supported. - QOpenGLVertexArrayObject::Binder vaoBinder(d->vao.data()); - - d->vertexBuffer.create(); - d->vertexBuffer.bind(); - d->vertexBuffer.allocate(vertex_buffer_data, sizeof(vertex_buffer_data)); - d->vertexBuffer.release(); - - d->textureBuffer.create(); - d->textureBuffer.bind(); - d->textureBuffer.allocate(texture_buffer_data, sizeof(texture_buffer_data)); - d->textureBuffer.release(); - - return true; -} - -/*! - \return \c true if create() was called and succeeded. \c false otherwise. - - \sa create(), destroy() - */ -bool QOpenGLTextureBlitter::isCreated() const -{ - Q_D(const QOpenGLTextureBlitter); - return d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_2D].glProgram; -} - -/*! - Frees all graphics resources held by the blitter. Assumes that - the OpenGL context, or another context sharing resources with it, - that was current on the thread when invoking create() is current. - - The function has no effect when the blitter is not in created state. - - \sa create() - */ -void QOpenGLTextureBlitter::destroy() -{ - if (!isCreated()) - return; - Q_D(QOpenGLTextureBlitter); - d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_2D].glProgram.reset(); - d->programs[QOpenGLTextureBlitterPrivate::TEXTURE_EXTERNAL_OES].glProgram.reset(); - d->vertexBuffer.destroy(); - d->textureBuffer.destroy(); - d->vao.reset(); -} - -/*! - \return \c true when bind() accepts \c GL_TEXTURE_EXTERNAL_OES as - its target argument. - - \sa bind(), blit() - */ -bool QOpenGLTextureBlitter::supportsExternalOESTarget() const -{ - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - return ctx && ctx->isOpenGLES() && ctx->hasExtension("GL_OES_EGL_image_external"); -} - -/*! - Binds the graphics resources used by the blitter. This must be - called before calling blit(). Code modifying the OpenGL state - should be avoided between the call to bind() and blit() because - otherwise conflicts may arise. - - \a target is the texture target for the source texture and must be - either \c GL_TEXTURE_2D or \c GL_OES_EGL_image_external. - - \sa release(), blit() - */ -void QOpenGLTextureBlitter::bind(GLenum target) -{ - Q_D(QOpenGLTextureBlitter); - - if (d->vao->isCreated()) - d->vao->bind(); - - d->currentTarget = target; - QOpenGLTextureBlitterPrivate::Program *p = &d->programs[targetToProgramIndex(target)]; - p->glProgram->bind(); - - d->vertexBuffer.bind(); - p->glProgram->setAttributeBuffer(p->vertexCoordAttribPos, GL_FLOAT, 0, 3, 0); - p->glProgram->enableAttributeArray(p->vertexCoordAttribPos); - d->vertexBuffer.release(); - - d->textureBuffer.bind(); - p->glProgram->setAttributeBuffer(p->textureCoordAttribPos, GL_FLOAT, 0, 2, 0); - p->glProgram->enableAttributeArray(p->textureCoordAttribPos); - d->textureBuffer.release(); -} - -/*! - Unbinds the graphics resources used by the blitter. - - \sa bind() - */ -void QOpenGLTextureBlitter::release() -{ - Q_D(QOpenGLTextureBlitter); - d->programs[targetToProgramIndex(d->currentTarget)].glProgram->release(); - if (d->vao->isCreated()) - d->vao->release(); -} - -/*! - Sets whether swizzling is enabled for the red and blue color channels to - \a swizzle. An BGRA to RGBA conversion (occurring in the shader on - the GPU, instead of a slow CPU-side transformation) can be useful - when the source texture contains data from a QImage with a format - like QImage::Format_ARGB32 which maps to BGRA on little endian - systems. - - By default the red-blue swizzle is disabled since this is what a - texture attached to an framebuffer object or a texture based on a - byte ordered QImage format (like QImage::Format_RGBA8888) needs. - */ -void QOpenGLTextureBlitter::setRedBlueSwizzle(bool swizzle) -{ - Q_D(QOpenGLTextureBlitter); - d->swizzle = swizzle; -} - -/*! - Changes the opacity to \a opacity. The default opacity is 1.0. - - \note the blitter does not alter the blend state. It is up to the - caller of blit() to ensure the correct blend settings are active. - - */ -void QOpenGLTextureBlitter::setOpacity(float opacity) -{ - Q_D(QOpenGLTextureBlitter); - d->opacity = opacity; -} - -/*! - \enum QOpenGLTextureBlitter::Origin - - \value OriginBottomLeft Indicates that the data in the texture - follows the OpenGL convention of coordinate systems, meaning Y is - running from bottom to top. - - \value OriginTopLeft Indicates that the data in the texture has Y - running from top to bottom, which is typical with regular, - unflipped image data. - - \sa blit() - */ - -/*! - Performs the blit with the source texture \a texture. - - \a targetTransform specifies the transformation applied. This is - usually generated by the targetTransform() helper function. - - \a sourceOrigin specifies if the image data needs flipping. When - \a texture corresponds to a texture attached to an FBO pass - OriginBottomLeft. On the other hand, when \a texture is based on - unflipped image data, pass OriginTopLeft. This is more efficient - than using QImage::mirrored(). - - \sa targetTransform(), Origin, bind() - */ -void QOpenGLTextureBlitter::blit(GLuint texture, - const QMatrix4x4 &targetTransform, - Origin sourceOrigin) -{ - Q_D(QOpenGLTextureBlitter); - d->blit(texture,targetTransform, sourceOrigin); -} - -/*! - Performs the blit with the source texture \a texture. - - \a targetTransform specifies the transformation applied. This is - usually generated by the targetTransform() helper function. - - \a sourceTransform specifies the transformation applied to the - source. This allows using only a sub-rect of the source - texture. This is usually generated by the sourceTransform() helper - function. - - \sa sourceTransform(), targetTransform(), Origin, bind() - */ -void QOpenGLTextureBlitter::blit(GLuint texture, - const QMatrix4x4 &targetTransform, - const QMatrix3x3 &sourceTransform) -{ - Q_D(QOpenGLTextureBlitter); - d->blit(texture, targetTransform, sourceTransform); -} - -/*! - Calculates a target transform suitable for blit(). - - \a target is the target rectangle in pixels. \a viewport describes - the source dimensions and will in most cases be set to (0, 0, - image width, image height). - - For unscaled output the size of \a target and \a viewport should - match. - - \sa blit() - */ -QMatrix4x4 QOpenGLTextureBlitter::targetTransform(const QRectF &target, - const QRect &viewport) -{ - qreal x_scale = target.width() / viewport.width(); - qreal y_scale = target.height() / viewport.height(); - - const QPointF relative_to_viewport = target.topLeft() - viewport.topLeft(); - qreal x_translate = x_scale - 1 + ((relative_to_viewport.x() / viewport.width()) * 2); - qreal y_translate = -y_scale + 1 - ((relative_to_viewport.y() / viewport.height()) * 2); - - QMatrix4x4 matrix; - matrix(0,3) = x_translate; - matrix(1,3) = y_translate; - - matrix(0,0) = x_scale; - matrix(1,1) = y_scale; - - return matrix; -} - -/*! - Calculates a 3x3 matrix suitable as the input to blit(). This is - used when only a part of the texture is to be used in the blit. - - \a subTexture is the desired source rectangle in pixels, \a - textureSize is the full width and height of the texture data. \a - origin specifies the orientation of the image data when it comes - to the Y axis. - - \sa blit(), Origin - */ -QMatrix3x3 QOpenGLTextureBlitter::sourceTransform(const QRectF &subTexture, - const QSize &textureSize, - Origin origin) -{ - qreal x_scale = subTexture.width() / textureSize.width(); - qreal y_scale = subTexture.height() / textureSize.height(); - - const QPointF topLeft = subTexture.topLeft(); - qreal x_translate = topLeft.x() / textureSize.width(); - qreal y_translate = topLeft.y() / textureSize.height(); - - if (origin == OriginTopLeft) { - y_scale = -y_scale; - y_translate = 1 - y_translate; - } - - QMatrix3x3 matrix; - matrix(0,2) = x_translate; - matrix(1,2) = y_translate; - - matrix(0,0) = x_scale; - matrix(1,1) = y_scale; - - return matrix; -} - -QT_END_NAMESPACE diff --git a/src/gui/opengl/qopengltextureblitter.h b/src/gui/opengl/qopengltextureblitter.h deleted file mode 100644 index 2f7c6b1a0a..0000000000 --- a/src/gui/opengl/qopengltextureblitter.h +++ /dev/null @@ -1,94 +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 QOPENGLTEXTUREBLITTER_H -#define QOPENGLTEXTUREBLITTER_H - -#include <QtGui/qtguiglobal.h> - -#ifndef QT_NO_OPENGL - -#include <QtGui/qopengl.h> -#include <QtGui/QMatrix3x3> -#include <QtGui/QMatrix4x4> - -QT_BEGIN_NAMESPACE - -class QOpenGLTextureBlitterPrivate; - -class Q_GUI_EXPORT QOpenGLTextureBlitter -{ -public: - QOpenGLTextureBlitter(); - ~QOpenGLTextureBlitter(); - - enum Origin { - OriginBottomLeft, - OriginTopLeft - }; - - bool create(); - bool isCreated() const; - void destroy(); - - bool supportsExternalOESTarget() const; - - void bind(GLenum target = GL_TEXTURE_2D); - void release(); - - void setRedBlueSwizzle(bool swizzle); - void setOpacity(float opacity); - - void blit(GLuint texture, const QMatrix4x4 &targetTransform, Origin sourceOrigin); - void blit(GLuint texture, const QMatrix4x4 &targetTransform, const QMatrix3x3 &sourceTransform); - - static QMatrix4x4 targetTransform(const QRectF &target, const QRect &viewport); - static QMatrix3x3 sourceTransform(const QRectF &subTexture, const QSize &textureSize, Origin origin); - -private: - Q_DISABLE_COPY(QOpenGLTextureBlitter) - Q_DECLARE_PRIVATE(QOpenGLTextureBlitter) - QScopedPointer<QOpenGLTextureBlitterPrivate> d_ptr; -}; - -QT_END_NAMESPACE - -#endif - -#endif //QOPENGLTEXTUREBLITTER_H diff --git a/src/gui/opengl/qopengltexturecache.cpp b/src/gui/opengl/qopengltexturecache.cpp deleted file mode 100644 index ef07dbe109..0000000000 --- a/src/gui/opengl/qopengltexturecache.cpp +++ /dev/null @@ -1,198 +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 "qopengltexturecache_p.h" -#include "qopengltextureuploader_p.h" -#include <qmath.h> -#include <qopenglfunctions.h> -#include <private/qimagepixmapcleanuphooks_p.h> -#include <qpa/qplatformpixmap.h> - -QT_BEGIN_NAMESPACE - -class QOpenGLTextureCacheWrapper -{ -public: - QOpenGLTextureCacheWrapper() - { - QImagePixmapCleanupHooks::instance()->addPlatformPixmapModificationHook(cleanupTexturesForPixmapData); - QImagePixmapCleanupHooks::instance()->addPlatformPixmapDestructionHook(cleanupTexturesForPixmapData); - QImagePixmapCleanupHooks::instance()->addImageHook(cleanupTexturesForCacheKey); - } - - ~QOpenGLTextureCacheWrapper() - { - QImagePixmapCleanupHooks::instance()->removePlatformPixmapModificationHook(cleanupTexturesForPixmapData); - QImagePixmapCleanupHooks::instance()->removePlatformPixmapDestructionHook(cleanupTexturesForPixmapData); - QImagePixmapCleanupHooks::instance()->removeImageHook(cleanupTexturesForCacheKey); - } - - QOpenGLTextureCache *cacheForContext(QOpenGLContext *context) { - QMutexLocker lock(&m_mutex); - return m_resource.value<QOpenGLTextureCache>(context); - } - - static void cleanupTexturesForCacheKey(qint64 key); - static void cleanupTexturesForPixmapData(QPlatformPixmap *pmd); - -private: - QOpenGLMultiGroupSharedResource m_resource; - QMutex m_mutex; -}; - -Q_GLOBAL_STATIC(QOpenGLTextureCacheWrapper, qt_texture_caches) - -QOpenGLTextureCache *QOpenGLTextureCache::cacheForContext(QOpenGLContext *context) -{ - return qt_texture_caches()->cacheForContext(context); -} - -void QOpenGLTextureCacheWrapper::cleanupTexturesForCacheKey(qint64 key) -{ - QList<QOpenGLSharedResource *> resources = qt_texture_caches()->m_resource.resources(); - for (QList<QOpenGLSharedResource *>::iterator it = resources.begin(); it != resources.end(); ++it) - static_cast<QOpenGLTextureCache *>(*it)->invalidate(key); -} - -void QOpenGLTextureCacheWrapper::cleanupTexturesForPixmapData(QPlatformPixmap *pmd) -{ - cleanupTexturesForCacheKey(pmd->cacheKey()); -} - -QOpenGLTextureCache::QOpenGLTextureCache(QOpenGLContext *ctx) - : QOpenGLSharedResource(ctx->shareGroup()) - , m_cache(256 * 1024) // 256 MB cache -{ -} - -QOpenGLTextureCache::~QOpenGLTextureCache() -{ -} - -GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, const QPixmap &pixmap, QOpenGLTextureUploader::BindOptions options) -{ - if (pixmap.isNull()) - return 0; - QMutexLocker locker(&m_mutex); - qint64 key = pixmap.cacheKey(); - - // A QPainter is active on the image - take the safe route and replace the texture. - if (!pixmap.paintingActive()) { - QOpenGLCachedTexture *entry = m_cache.object(key); - if (entry && entry->options() == options) { - context->functions()->glBindTexture(GL_TEXTURE_2D, entry->id()); - return entry->id(); - } - } - - GLuint id = bindTexture(context, key, pixmap.toImage(), options); - if (id > 0) - QImagePixmapCleanupHooks::enableCleanupHooks(pixmap); - - return id; -} - -GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, const QImage &image, QOpenGLTextureUploader::BindOptions options) -{ - if (image.isNull()) - return 0; - QMutexLocker locker(&m_mutex); - qint64 key = image.cacheKey(); - - // A QPainter is active on the image - take the safe route and replace the texture. - if (!image.paintingActive()) { - QOpenGLCachedTexture *entry = m_cache.object(key); - if (entry && entry->options() == options) { - context->functions()->glBindTexture(GL_TEXTURE_2D, entry->id()); - return entry->id(); - } - } - - QImage img = image; - if (!context->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextures)) - options |= QOpenGLTextureUploader::PowerOfTwoBindOption; - - GLuint id = bindTexture(context, key, img, options); - if (id > 0) - QImagePixmapCleanupHooks::enableCleanupHooks(image); - - return id; -} - -GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, qint64 key, const QImage &image, QOpenGLTextureUploader::BindOptions options) -{ - GLuint id; - QOpenGLFunctions *funcs = context->functions(); - funcs->glGenTextures(1, &id); - funcs->glBindTexture(GL_TEXTURE_2D, id); - - int cost = QOpenGLTextureUploader::textureImage(GL_TEXTURE_2D, image, options); - - m_cache.insert(key, new QOpenGLCachedTexture(id, options, context), cost / 1024); - - return id; -} - -void QOpenGLTextureCache::invalidate(qint64 key) -{ - QMutexLocker locker(&m_mutex); - m_cache.remove(key); -} - -void QOpenGLTextureCache::invalidateResource() -{ - m_cache.clear(); -} - -void QOpenGLTextureCache::freeResource(QOpenGLContext *) -{ - Q_ASSERT(false); // the texture cache lives until the context group disappears -} - -static void freeTexture(QOpenGLFunctions *funcs, GLuint id) -{ - funcs->glDeleteTextures(1, &id); -} - -QOpenGLCachedTexture::QOpenGLCachedTexture(GLuint id, QOpenGLTextureUploader::BindOptions options, QOpenGLContext *context) : m_options(options) -{ - m_resource = new QOpenGLSharedResourceGuard(context, id, freeTexture); -} - -QT_END_NAMESPACE diff --git a/src/gui/opengl/qopengltexturecache_p.h b/src/gui/opengl/qopengltexturecache_p.h deleted file mode 100644 index 88ef06e744..0000000000 --- a/src/gui/opengl/qopengltexturecache_p.h +++ /dev/null @@ -1,108 +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$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#ifndef QOPENGLTEXTURECACHE_P_H -#define QOPENGLTEXTURECACHE_P_H - -#include <QtGui/private/qtguiglobal_p.h> -#include <QHash> -#include <QObject> -#include <QCache> -#include <private/qopenglcontext_p.h> -#include <private/qopengltextureuploader_p.h> -#include <QtCore/qmutex.h> - -QT_BEGIN_NAMESPACE - -class QOpenGLCachedTexture; - -class Q_GUI_EXPORT QOpenGLTextureCache : public QOpenGLSharedResource -{ -public: - static QOpenGLTextureCache *cacheForContext(QOpenGLContext *context); - - QOpenGLTextureCache(QOpenGLContext *); - ~QOpenGLTextureCache(); - - GLuint bindTexture(QOpenGLContext *context, const QPixmap &pixmap, - QOpenGLTextureUploader::BindOptions options = QOpenGLTextureUploader::PremultipliedAlphaBindOption); - GLuint bindTexture(QOpenGLContext *context, const QImage &image, - QOpenGLTextureUploader::BindOptions options = QOpenGLTextureUploader::PremultipliedAlphaBindOption); - - void invalidate(qint64 key); - - void invalidateResource() override; - void freeResource(QOpenGLContext *ctx) override; - -private: - GLuint bindTexture(QOpenGLContext *context, qint64 key, const QImage &image, QOpenGLTextureUploader::BindOptions options); - - QMutex m_mutex; - QCache<quint64, QOpenGLCachedTexture> m_cache; -}; - -class QOpenGLCachedTexture -{ -public: - QOpenGLCachedTexture(GLuint id, QOpenGLTextureUploader::BindOptions options, QOpenGLContext *context); - ~QOpenGLCachedTexture() { m_resource->free(); } - - GLuint id() const { return m_resource->id(); } - QOpenGLTextureUploader::BindOptions options() const { return m_options; } - -private: - QOpenGLSharedResourceGuard *m_resource; - QOpenGLTextureUploader::BindOptions m_options; -}; - -QT_END_NAMESPACE - -#endif - diff --git a/src/gui/opengl/qopengltextureglyphcache.cpp b/src/gui/opengl/qopengltextureglyphcache.cpp deleted file mode 100644 index 41027d26e0..0000000000 --- a/src/gui/opengl/qopengltextureglyphcache.cpp +++ /dev/null @@ -1,485 +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 "qopengltextureglyphcache_p.h" -#include "qopenglpaintengine_p.h" -#include "private/qopenglengineshadersource_p.h" -#include "qopenglextensions_p.h" -#include <qrgb.h> -#include <private/qdrawhelper_p.h> - -QT_BEGIN_NAMESPACE - - -static int next_qopengltextureglyphcache_serial_number() -{ - static QBasicAtomicInt serial = Q_BASIC_ATOMIC_INITIALIZER(0); - return 1 + serial.fetchAndAddRelaxed(1); -} - -QOpenGLTextureGlyphCache::QOpenGLTextureGlyphCache(QFontEngine::GlyphFormat format, const QTransform &matrix, const QColor &color) - : QImageTextureGlyphCache(format, matrix, color) - , m_textureResource(nullptr) - , pex(nullptr) - , m_blitProgram(nullptr) - , m_filterMode(Nearest) - , m_serialNumber(next_qopengltextureglyphcache_serial_number()) - , m_buffer(QOpenGLBuffer::VertexBuffer) -{ -#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG - qDebug(" -> QOpenGLTextureGlyphCache() %p for context %p.", this, QOpenGLContext::currentContext()); -#endif - m_vertexCoordinateArray[0] = -1.0f; - m_vertexCoordinateArray[1] = -1.0f; - m_vertexCoordinateArray[2] = 1.0f; - m_vertexCoordinateArray[3] = -1.0f; - m_vertexCoordinateArray[4] = 1.0f; - m_vertexCoordinateArray[5] = 1.0f; - m_vertexCoordinateArray[6] = -1.0f; - m_vertexCoordinateArray[7] = 1.0f; - - m_textureCoordinateArray[0] = 0.0f; - m_textureCoordinateArray[1] = 0.0f; - m_textureCoordinateArray[2] = 1.0f; - m_textureCoordinateArray[3] = 0.0f; - m_textureCoordinateArray[4] = 1.0f; - m_textureCoordinateArray[5] = 1.0f; - m_textureCoordinateArray[6] = 0.0f; - m_textureCoordinateArray[7] = 1.0f; -} - -QOpenGLTextureGlyphCache::~QOpenGLTextureGlyphCache() -{ -#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG - qDebug(" -> ~QOpenGLTextureGlyphCache() %p.", this); -#endif - clear(); -} - -#if !defined(QT_OPENGL_ES_2) -static inline bool isCoreProfile() -{ - return QOpenGLContext::currentContext()->format().profile() == QSurfaceFormat::CoreProfile; -} -#endif - -void QOpenGLTextureGlyphCache::createTextureData(int width, int height) -{ - QOpenGLContext *ctx = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext()); - if (ctx == nullptr) { - qWarning("QOpenGLTextureGlyphCache::createTextureData: Called with no context"); - return; - } - - // create in QImageTextureGlyphCache baseclass is meant to be called - // only to create the initial image and does not preserve the content, - // so we don't call when this function is called from resize. - if (ctx->d_func()->workaround_brokenFBOReadBack && image().isNull()) - QImageTextureGlyphCache::createTextureData(width, height); - - // Make the lower glyph texture size 16 x 16. - if (width < 16) - width = 16; - if (height < 16) - height = 16; - - if (m_textureResource && !m_textureResource->m_texture) { - delete m_textureResource; - m_textureResource = nullptr; - } - - if (!m_textureResource) - m_textureResource = new QOpenGLGlyphTexture(ctx); - - QOpenGLFunctions *funcs = ctx->functions(); - funcs->glGenTextures(1, &m_textureResource->m_texture); - funcs->glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture); - - m_textureResource->m_width = width; - m_textureResource->m_height = height; - - if (m_format == QFontEngine::Format_A32 || m_format == QFontEngine::Format_ARGB) { - QVarLengthArray<uchar> data(width * height * 4); - for (int i = 0; i < data.size(); ++i) - data[i] = 0; - funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data[0]); - } else { - QVarLengthArray<uchar> data(width * height); - for (int i = 0; i < data.size(); ++i) - data[i] = 0; -#if !defined(QT_OPENGL_ES_2) - const GLint internalFormat = isCoreProfile() ? GL_R8 : GL_ALPHA; - const GLenum format = isCoreProfile() ? GL_RED : GL_ALPHA; -#else - const GLint internalFormat = GL_ALPHA; - const GLenum format = GL_ALPHA; -#endif - funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, format, GL_UNSIGNED_BYTE, &data[0]); - } - - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - m_filterMode = Nearest; - - if (!m_buffer.isCreated()) { - m_buffer.create(); - m_buffer.bind(); - static GLfloat buf[sizeof(m_vertexCoordinateArray) + sizeof(m_textureCoordinateArray)]; - memcpy(buf, m_vertexCoordinateArray, sizeof(m_vertexCoordinateArray)); - memcpy(buf + (sizeof(m_vertexCoordinateArray) / sizeof(GLfloat)), - m_textureCoordinateArray, - sizeof(m_textureCoordinateArray)); - m_buffer.allocate(buf, sizeof(buf)); - m_buffer.release(); - } - - if (!m_vao.isCreated()) - m_vao.create(); -} - -void QOpenGLTextureGlyphCache::setupVertexAttribs() -{ - m_buffer.bind(); - m_blitProgram->setAttributeBuffer(int(QT_VERTEX_COORDS_ATTR), GL_FLOAT, 0, 2); - m_blitProgram->setAttributeBuffer(int(QT_TEXTURE_COORDS_ATTR), GL_FLOAT, sizeof(m_vertexCoordinateArray), 2); - m_blitProgram->enableAttributeArray(int(QT_VERTEX_COORDS_ATTR)); - m_blitProgram->enableAttributeArray(int(QT_TEXTURE_COORDS_ATTR)); - m_buffer.release(); -} - -static void load_glyph_image_to_texture(QOpenGLContext *ctx, - QImage &img, - GLuint texture, - int tx, int ty) -{ - QOpenGLFunctions *funcs = ctx->functions(); - - const int imgWidth = img.width(); - const int imgHeight = img.height(); - - if (img.format() == QImage::Format_Mono) { - img = img.convertToFormat(QImage::Format_Grayscale8); - } else if (img.depth() == 32) { - if (img.format() == QImage::Format_RGB32 - // We need to make the alpha component equal to the average of the RGB values. - // This is needed when drawing sub-pixel antialiased text on translucent targets. -#if Q_BYTE_ORDER == Q_BIG_ENDIAN - || img.format() == QImage::Format_ARGB32_Premultiplied -#else - || (img.format() == QImage::Format_ARGB32_Premultiplied - && ctx->isOpenGLES()) -#endif - ) { - for (int y = 0; y < imgHeight; ++y) { - QRgb *src = (QRgb *) img.scanLine(y); - for (int x = 0; x < imgWidth; ++x) { - int r = qRed(src[x]); - int g = qGreen(src[x]); - int b = qBlue(src[x]); - int avg; - if (img.format() == QImage::Format_RGB32) - avg = (r + g + b + 1) / 3; // "+1" for rounding. - else // Format_ARGB_Premultiplied - avg = qAlpha(src[x]); - - src[x] = qRgba(r, g, b, avg); - // swizzle the bits to accommodate for the GL_RGBA upload. -#if Q_BYTE_ORDER != Q_BIG_ENDIAN - if (ctx->isOpenGLES()) -#endif - src[x] = ARGB2RGBA(src[x]); - } - } - } - } - - funcs->glBindTexture(GL_TEXTURE_2D, texture); - if (img.depth() == 32) { -#ifdef QT_OPENGL_ES_2 - GLenum fmt = GL_RGBA; -#else - GLenum fmt = ctx->isOpenGLES() ? GL_RGBA : GL_BGRA; -#endif // QT_OPENGL_ES_2 - -#if Q_BYTE_ORDER == Q_BIG_ENDIAN - fmt = GL_RGBA; -#endif - funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, tx, ty, imgWidth, imgHeight, fmt, GL_UNSIGNED_BYTE, img.constBits()); - } else { - // The scanlines in image are 32-bit aligned, even for mono or 8-bit formats. This - // is good because it matches the default of 4 bytes for GL_UNPACK_ALIGNMENT. -#if !defined(QT_OPENGL_ES_2) - const GLenum format = isCoreProfile() ? GL_RED : GL_ALPHA; -#else - const GLenum format = GL_ALPHA; -#endif - funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, tx, ty, imgWidth, imgHeight, format, GL_UNSIGNED_BYTE, img.constBits()); - } -} - -static void load_glyph_image_region_to_texture(QOpenGLContext *ctx, - const QImage &srcImg, - int x, int y, - int w, int h, - GLuint texture, - int tx, int ty) -{ - Q_ASSERT(x + w <= srcImg.width() && y + h <= srcImg.height()); - - QImage img; - if (x != 0 || y != 0 || w != srcImg.width() || h != srcImg.height()) - img = srcImg.copy(x, y, w, h); - else - img = srcImg; - - load_glyph_image_to_texture(ctx, img, texture, tx, ty); -} - -void QOpenGLTextureGlyphCache::resizeTextureData(int width, int height) -{ - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - if (ctx == nullptr) { - qWarning("QOpenGLTextureGlyphCache::resizeTextureData: Called with no context"); - return; - } - - QOpenGLFunctions *funcs = ctx->functions(); - GLint oldFbo; - funcs->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldFbo); - - int oldWidth = m_textureResource->m_width; - int oldHeight = m_textureResource->m_height; - - // Make the lower glyph texture size 16 x 16. - if (width < 16) - width = 16; - if (height < 16) - height = 16; - - GLuint oldTexture = m_textureResource->m_texture; - createTextureData(width, height); - - if (ctx->d_func()->workaround_brokenFBOReadBack) { - QImageTextureGlyphCache::resizeTextureData(width, height); - load_glyph_image_region_to_texture(ctx, image(), 0, 0, qMin(oldWidth, width), qMin(oldHeight, height), - m_textureResource->m_texture, 0, 0); - return; - } - - // ### the QTextureGlyphCache API needs to be reworked to allow - // ### resizeTextureData to fail - - funcs->glBindFramebuffer(GL_FRAMEBUFFER, m_textureResource->m_fbo); - - GLuint tmp_texture; - funcs->glGenTextures(1, &tmp_texture); - funcs->glBindTexture(GL_TEXTURE_2D, tmp_texture); - funcs->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0, - GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - m_filterMode = Nearest; - funcs->glBindTexture(GL_TEXTURE_2D, 0); - funcs->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, tmp_texture, 0); - - funcs->glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT); - funcs->glBindTexture(GL_TEXTURE_2D, oldTexture); - - if (pex != nullptr) - pex->transferMode(BrushDrawingMode); - - funcs->glDisable(GL_STENCIL_TEST); - funcs->glDisable(GL_DEPTH_TEST); - funcs->glDisable(GL_SCISSOR_TEST); - funcs->glDisable(GL_BLEND); - - funcs->glViewport(0, 0, oldWidth, oldHeight); - - QOpenGLShaderProgram *blitProgram = nullptr; - if (pex == nullptr) { - if (m_blitProgram == nullptr) { - m_blitProgram = new QOpenGLShaderProgram; - const bool isCoreProfile = ctx->format().profile() == QSurfaceFormat::CoreProfile; - - { - QString source; -#ifdef Q_OS_WASM - source.append(QLatin1String(isCoreProfile ? qopenglslUntransformedPositionVertexShader_core : qopenglslUntransformedPositionVertexShader)); - source.append(QLatin1String(isCoreProfile ? qopenglslMainWithTexCoordsVertexShader_core : qopenglslMainWithTexCoordsVertexShader)); -#else - source.append(QLatin1String(isCoreProfile ? qopenglslMainWithTexCoordsVertexShader_core : qopenglslMainWithTexCoordsVertexShader)); - source.append(QLatin1String(isCoreProfile ? qopenglslUntransformedPositionVertexShader_core : qopenglslUntransformedPositionVertexShader)); -#endif - m_blitProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, source); - } - - { - QString source; -#ifdef Q_OS_WASM - source.append(QLatin1String(isCoreProfile ? qopenglslImageSrcFragmentShader_core : qopenglslImageSrcFragmentShader)); - source.append(QLatin1String(isCoreProfile ? qopenglslMainFragmentShader_core : qopenglslMainFragmentShader)); -#else - source.append(QLatin1String(isCoreProfile ? qopenglslMainFragmentShader_core : qopenglslMainFragmentShader)); - source.append(QLatin1String(isCoreProfile ? qopenglslImageSrcFragmentShader_core : qopenglslImageSrcFragmentShader)); -#endif - m_blitProgram->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, source); - } - - m_blitProgram->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); - m_blitProgram->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); - - m_blitProgram->link(); - - if (m_vao.isCreated()) { - m_vao.bind(); - setupVertexAttribs(); - } - } - - if (m_vao.isCreated()) - m_vao.bind(); - else - setupVertexAttribs(); - - m_blitProgram->bind(); - blitProgram = m_blitProgram; - - } else { - pex->uploadData(QT_VERTEX_COORDS_ATTR, m_vertexCoordinateArray, 8); - pex->uploadData(QT_TEXTURE_COORDS_ATTR, m_textureCoordinateArray, 8); - - pex->shaderManager->useBlitProgram(); - blitProgram = pex->shaderManager->blitProgram(); - } - - blitProgram->setUniformValue("imageTexture", QT_IMAGE_TEXTURE_UNIT); - - funcs->glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - funcs->glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture); - - funcs->glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight); - - funcs->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_RENDERBUFFER, 0); - funcs->glDeleteTextures(1, &tmp_texture); - funcs->glDeleteTextures(1, &oldTexture); - - funcs->glBindFramebuffer(GL_FRAMEBUFFER, (GLuint)oldFbo); - - if (pex != nullptr) { - funcs->glViewport(0, 0, pex->width, pex->height); - pex->updateClipScissorTest(); - } else { - if (m_vao.isCreated()) { - m_vao.release(); - } else { - m_blitProgram->disableAttributeArray(int(QT_VERTEX_COORDS_ATTR)); - m_blitProgram->disableAttributeArray(int(QT_TEXTURE_COORDS_ATTR)); - } - } -} - -void QOpenGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed subPixelPosition) -{ - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - if (ctx == nullptr) { - qWarning("QOpenGLTextureGlyphCache::fillTexture: Called with no context"); - return; - } - - if (ctx->d_func()->workaround_brokenFBOReadBack) { - QImageTextureGlyphCache::fillTexture(c, glyph, subPixelPosition); - load_glyph_image_region_to_texture(ctx, image(), c.x, c.y, c.w, c.h, m_textureResource->m_texture, c.x, c.y); - return; - } - - QImage mask = textureMapForGlyph(glyph, subPixelPosition); - load_glyph_image_to_texture(ctx, mask, m_textureResource->m_texture, c.x, c.y); -} - -int QOpenGLTextureGlyphCache::glyphPadding() const -{ - return 1; -} - -int QOpenGLTextureGlyphCache::maxTextureWidth() const -{ - QOpenGLContext *ctx = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext()); - if (ctx == nullptr) - return QImageTextureGlyphCache::maxTextureWidth(); - else - return ctx->d_func()->maxTextureSize(); -} - -int QOpenGLTextureGlyphCache::maxTextureHeight() const -{ - QOpenGLContext *ctx = const_cast<QOpenGLContext *>(QOpenGLContext::currentContext()); - if (ctx == nullptr) - return QImageTextureGlyphCache::maxTextureHeight(); - - if (ctx->d_func()->workaround_brokenTexSubImage) - return qMin(1024, ctx->d_func()->maxTextureSize()); - else - return ctx->d_func()->maxTextureSize(); -} - -void QOpenGLTextureGlyphCache::clear() -{ - if (m_textureResource) - m_textureResource->free(); - m_textureResource = nullptr; - - delete m_blitProgram; - m_blitProgram = nullptr; - - m_w = 0; - m_h = 0; - m_cx = 0; - m_cy = 0; - m_currentRowHeight = 0; - coords.clear(); -} - -QT_END_NAMESPACE diff --git a/src/gui/opengl/qopengltextureglyphcache_p.h b/src/gui/opengl/qopengltextureglyphcache_p.h deleted file mode 100644 index 4bea4a463a..0000000000 --- a/src/gui/opengl/qopengltextureglyphcache_p.h +++ /dev/null @@ -1,181 +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 QOPENGLTEXTUREGLYPHCACHE_P_H -#define QOPENGLTEXTUREGLYPHCACHE_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtGui/private/qtguiglobal_p.h> -#include <private/qtextureglyphcache_p.h> -#include <private/qopenglcontext_p.h> -#include <qopenglshaderprogram.h> -#include <qopenglfunctions.h> -#include <qopenglbuffer.h> -#include <qopenglvertexarrayobject.h> - -// #define QT_GL_TEXTURE_GLYPH_CACHE_DEBUG - -QT_BEGIN_NAMESPACE - -class QOpenGL2PaintEngineExPrivate; - -class QOpenGLGlyphTexture : public QOpenGLSharedResource -{ -public: - explicit QOpenGLGlyphTexture(QOpenGLContext *ctx) - : QOpenGLSharedResource(ctx->shareGroup()) - , m_width(0) - , m_height(0) - { - if (!ctx->d_func()->workaround_brokenFBOReadBack) - QOpenGLFunctions(ctx).glGenFramebuffers(1, &m_fbo); - -#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG - qDebug(" -> QOpenGLGlyphTexture() %p for context %p.", this, ctx); -#endif - } - - void freeResource(QOpenGLContext *context) override - { - QOpenGLContext *ctx = context; -#ifdef QT_GL_TEXTURE_GLYPH_CACHE_DEBUG - qDebug("~QOpenGLGlyphTexture() %p for context %p.", this, ctx); -#endif - if (!ctx->d_func()->workaround_brokenFBOReadBack) - ctx->functions()->glDeleteFramebuffers(1, &m_fbo); - if (m_width || m_height) - ctx->functions()->glDeleteTextures(1, &m_texture); - } - - void invalidateResource() override - { - m_texture = 0; - m_fbo = 0; - m_width = 0; - m_height = 0; - } - - GLuint m_texture; - GLuint m_fbo; - int m_width; - int m_height; -}; - -class Q_GUI_EXPORT QOpenGLTextureGlyphCache : public QImageTextureGlyphCache -{ -public: - QOpenGLTextureGlyphCache(QFontEngine::GlyphFormat glyphFormat, const QTransform &matrix, const QColor &color = QColor()); - ~QOpenGLTextureGlyphCache(); - - virtual void createTextureData(int width, int height) override; - virtual void resizeTextureData(int width, int height) override; - virtual void fillTexture(const Coord &c, glyph_t glyph, QFixed subPixelPosition) override; - virtual int glyphPadding() const override; - virtual int maxTextureWidth() const override; - virtual int maxTextureHeight() const override; - - inline GLuint texture() const { - QOpenGLTextureGlyphCache *that = const_cast<QOpenGLTextureGlyphCache *>(this); - QOpenGLGlyphTexture *glyphTexture = that->m_textureResource; - return glyphTexture ? glyphTexture->m_texture : 0; - } - - inline int width() const { - QOpenGLTextureGlyphCache *that = const_cast<QOpenGLTextureGlyphCache *>(this); - QOpenGLGlyphTexture *glyphTexture = that->m_textureResource; - return glyphTexture ? glyphTexture->m_width : 0; - } - inline int height() const { - QOpenGLTextureGlyphCache *that = const_cast<QOpenGLTextureGlyphCache *>(this); - QOpenGLGlyphTexture *glyphTexture = that->m_textureResource; - return glyphTexture ? glyphTexture->m_height : 0; - } - - inline void setPaintEnginePrivate(QOpenGL2PaintEngineExPrivate *p) { pex = p; } - - inline const QOpenGLContextGroup *contextGroup() const { return m_textureResource ? m_textureResource->group() : nullptr; } - - inline int serialNumber() const { return m_serialNumber; } - - enum FilterMode { - Nearest, - Linear - }; - FilterMode filterMode() const { return m_filterMode; } - void setFilterMode(FilterMode m) { m_filterMode = m; } - - void clear(); - - QOpenGL2PaintEngineExPrivate *paintEnginePrivate() const - { - return pex; - } - -private: - void setupVertexAttribs(); - - QOpenGLGlyphTexture *m_textureResource; - - QOpenGL2PaintEngineExPrivate *pex; - QOpenGLShaderProgram *m_blitProgram; - FilterMode m_filterMode; - - GLfloat m_vertexCoordinateArray[8]; - GLfloat m_textureCoordinateArray[8]; - - int m_serialNumber; - - QOpenGLBuffer m_buffer; - QOpenGLVertexArrayObject m_vao; -}; - -QT_END_NAMESPACE - -#endif // QOPENGLTEXTUREGLYPHCACHE_P_H - diff --git a/src/gui/opengl/qopengltexturehelper.cpp b/src/gui/opengl/qopengltexturehelper.cpp deleted file mode 100644 index 6709edc4e2..0000000000 --- a/src/gui/opengl/qopengltexturehelper.cpp +++ /dev/null @@ -1,589 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB). -** 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 "qopengltexturehelper_p.h" - -#include <QOpenGLContext> -#include <private/qopenglextensions_p.h> - -QT_BEGIN_NAMESPACE - -QOpenGLTextureHelper::QOpenGLTextureHelper(QOpenGLContext *context) -{ - functions = context->functions(); - // Resolve EXT_direct_state_access entry points if present. - - // However, disable it on some systems where DSA is known to be unreliable. - bool allowDSA = true; - const char *renderer = reinterpret_cast<const char *>(context->functions()->glGetString(GL_RENDERER)); - // QTBUG-40653, QTBUG-44988 - if (renderer && strstr(renderer, "AMD Radeon HD")) - allowDSA = false; - - if (allowDSA && !context->isOpenGLES() - && context->hasExtension(QByteArrayLiteral("GL_EXT_direct_state_access"))) { - TextureParameteriEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLenum , GLint )>(context->getProcAddress("glTextureParameteriEXT")); - TextureParameterivEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLenum , const GLint *)>(context->getProcAddress("glTextureParameterivEXT")); - TextureParameterfEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLenum , GLfloat )>(context->getProcAddress("glTextureParameterfEXT")); - TextureParameterfvEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLenum , const GLfloat *)>(context->getProcAddress("glTextureParameterfvEXT")); - GenerateTextureMipmapEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum )>(context->getProcAddress("glGenerateTextureMipmapEXT")); - TextureStorage3DEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLsizei , GLenum , GLsizei , GLsizei , GLsizei )>(context->getProcAddress("glTextureStorage3DEXT")); - TextureStorage2DEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLsizei , GLenum , GLsizei , GLsizei )>(context->getProcAddress("glTextureStorage2DEXT")); - TextureStorage1DEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLsizei , GLenum , GLsizei )>(context->getProcAddress("glTextureStorage1DEXT")); - TextureStorage3DMultisampleEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLsizei , GLenum , GLsizei , GLsizei , GLsizei , GLboolean )>(context->getProcAddress("glTextureStorage3DMultisampleEXT")); - TextureStorage2DMultisampleEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLsizei , GLenum , GLsizei , GLsizei , GLboolean )>(context->getProcAddress("glTextureStorage2DMultisampleEXT")); - TextureImage3DEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLint , GLenum , GLsizei , GLsizei , GLsizei , GLint , GLenum , GLenum , const GLvoid *)>(context->getProcAddress("glTextureImage3DEXT")); - TextureImage2DEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLint , GLenum , GLsizei , GLsizei , GLint , GLenum , GLenum , const GLvoid *)>(context->getProcAddress("glTextureImage2DEXT")); - TextureImage1DEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLint , GLenum , GLsizei , GLint , GLenum , GLenum , const GLvoid *)>(context->getProcAddress("glTextureImage1DEXT")); - TextureSubImage3DEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLint , GLint , GLint , GLint , GLsizei , GLsizei , GLsizei , GLenum , GLenum , const GLvoid *)>(context->getProcAddress("glTextureSubImage3DEXT")); - TextureSubImage2DEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLint , GLint , GLint , GLsizei , GLsizei , GLenum , GLenum , const GLvoid *)>(context->getProcAddress("glTextureSubImage2DEXT")); - TextureSubImage1DEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLint , GLint , GLsizei , GLenum , GLenum , const GLvoid *)>(context->getProcAddress("glTextureSubImage1DEXT")); - CompressedTextureSubImage1DEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLint , GLint , GLsizei , GLenum , GLsizei , const GLvoid *)>(context->getProcAddress("glCompressedTextureSubImage1DEXT")); - CompressedTextureSubImage2DEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLint , GLint , GLint , GLsizei , GLsizei , GLenum , GLsizei , const GLvoid *)>(context->getProcAddress("glCompressedTextureSubImage2DEXT")); - CompressedTextureSubImage3DEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLint , GLint , GLint , GLint , GLsizei , GLsizei , GLsizei , GLenum , GLsizei , const GLvoid *)>(context->getProcAddress("glCompressedTextureSubImage3DEXT")); - CompressedTextureImage1DEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLint , GLenum , GLsizei , GLint , GLsizei , const GLvoid *)>(context->getProcAddress("glCompressedTextureImage1DEXT")); - CompressedTextureImage2DEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLint , GLenum , GLsizei , GLsizei , GLint , GLsizei , const GLvoid *)>(context->getProcAddress("glCompressedTextureImage2DEXT")); - CompressedTextureImage3DEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLint , GLenum , GLsizei , GLsizei , GLsizei , GLint , GLsizei , const GLvoid *)>(context->getProcAddress("glCompressedTextureImage3DEXT")); - - // Use the real DSA functions - TextureParameteri = &QOpenGLTextureHelper::dsa_TextureParameteri; - TextureParameteriv = &QOpenGLTextureHelper::dsa_TextureParameteriv; - TextureParameterf = &QOpenGLTextureHelper::dsa_TextureParameterf; - TextureParameterfv = &QOpenGLTextureHelper::dsa_TextureParameterfv; - GenerateTextureMipmap = &QOpenGLTextureHelper::dsa_GenerateTextureMipmap; - TextureStorage3D = &QOpenGLTextureHelper::dsa_TextureStorage3D; - TextureStorage2D = &QOpenGLTextureHelper::dsa_TextureStorage2D; - TextureStorage1D = &QOpenGLTextureHelper::dsa_TextureStorage1D; - TextureStorage3DMultisample = &QOpenGLTextureHelper::dsa_TextureStorage3DMultisample; - TextureStorage2DMultisample = &QOpenGLTextureHelper::dsa_TextureStorage2DMultisample; - TextureImage3D = &QOpenGLTextureHelper::dsa_TextureImage3D; - TextureImage2D = &QOpenGLTextureHelper::dsa_TextureImage2D; - TextureImage1D = &QOpenGLTextureHelper::dsa_TextureImage1D; - TextureSubImage3D = &QOpenGLTextureHelper::dsa_TextureSubImage3D; - TextureSubImage2D = &QOpenGLTextureHelper::dsa_TextureSubImage2D; - TextureSubImage1D = &QOpenGLTextureHelper::dsa_TextureSubImage1D; - CompressedTextureSubImage1D = &QOpenGLTextureHelper::dsa_CompressedTextureSubImage1D; - CompressedTextureSubImage2D = &QOpenGLTextureHelper::dsa_CompressedTextureSubImage2D; - CompressedTextureSubImage3D = &QOpenGLTextureHelper::dsa_CompressedTextureSubImage3D; - CompressedTextureImage1D = &QOpenGLTextureHelper::dsa_CompressedTextureImage1D; - CompressedTextureImage2D = &QOpenGLTextureHelper::dsa_CompressedTextureImage2D; - CompressedTextureImage3D = &QOpenGLTextureHelper::dsa_CompressedTextureImage3D; - } else { - // Use our own DSA emulation - TextureParameteri = &QOpenGLTextureHelper::qt_TextureParameteri; - TextureParameteriv = &QOpenGLTextureHelper::qt_TextureParameteriv; - TextureParameterf = &QOpenGLTextureHelper::qt_TextureParameterf; - TextureParameterfv = &QOpenGLTextureHelper::qt_TextureParameterfv; - GenerateTextureMipmap = &QOpenGLTextureHelper::qt_GenerateTextureMipmap; - TextureStorage3D = &QOpenGLTextureHelper::qt_TextureStorage3D; - TextureStorage2D = &QOpenGLTextureHelper::qt_TextureStorage2D; - TextureStorage1D = &QOpenGLTextureHelper::qt_TextureStorage1D; - TextureStorage3DMultisample = &QOpenGLTextureHelper::qt_TextureStorage3DMultisample; - TextureStorage2DMultisample = &QOpenGLTextureHelper::qt_TextureStorage2DMultisample; - TextureImage3D = &QOpenGLTextureHelper::qt_TextureImage3D; - TextureImage2D = &QOpenGLTextureHelper::qt_TextureImage2D; - TextureImage1D = &QOpenGLTextureHelper::qt_TextureImage1D; - TextureSubImage3D = &QOpenGLTextureHelper::qt_TextureSubImage3D; - TextureSubImage2D = &QOpenGLTextureHelper::qt_TextureSubImage2D; - TextureSubImage1D = &QOpenGLTextureHelper::qt_TextureSubImage1D; - CompressedTextureSubImage1D = &QOpenGLTextureHelper::qt_CompressedTextureSubImage1D; - CompressedTextureSubImage2D = &QOpenGLTextureHelper::qt_CompressedTextureSubImage2D; - CompressedTextureSubImage3D = &QOpenGLTextureHelper::qt_CompressedTextureSubImage3D; - CompressedTextureImage1D = &QOpenGLTextureHelper::qt_CompressedTextureImage1D; - CompressedTextureImage2D = &QOpenGLTextureHelper::qt_CompressedTextureImage2D; - CompressedTextureImage3D = &QOpenGLTextureHelper::qt_CompressedTextureImage3D; - } - - // Some DSA functions are part of NV_texture_multisample instead - if (!context->isOpenGLES() - && context->hasExtension(QByteArrayLiteral("GL_NV_texture_multisample"))) { - TextureImage3DMultisampleNV = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLsizei , GLint , GLsizei , GLsizei , GLsizei , GLboolean )>(context->getProcAddress("glTextureImage3DMultisampleNV")); - TextureImage2DMultisampleNV = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLsizei , GLint , GLsizei , GLsizei , GLboolean )>(context->getProcAddress("glTextureImage2DMultisampleNV")); - - TextureImage3DMultisample = &QOpenGLTextureHelper::dsa_TextureImage3DMultisample; - TextureImage2DMultisample = &QOpenGLTextureHelper::dsa_TextureImage2DMultisample; - } else { - TextureImage3DMultisample = &QOpenGLTextureHelper::qt_TextureImage3DMultisample; - TextureImage2DMultisample = &QOpenGLTextureHelper::qt_TextureImage2DMultisample; - } - -#if defined(QT_OPENGL_ES_2) - // Here we are targeting OpenGL ES 2.0+ only. This is likely using EGL, where, - // similarly to WGL, non-extension functions (i.e. any function that is part of the - // GLES spec) *may* not be queried via eglGetProcAddress. - - // OpenGL 1.0 - TexImage1D = 0; - - // OpenGL 1.1 - TexSubImage1D = 0; - - // OpenGL 1.3 - GetCompressedTexImage = 0; - CompressedTexSubImage1D = 0; - CompressedTexSubImage2D = ::glCompressedTexSubImage2D; - CompressedTexImage1D = 0; - CompressedTexImage2D = ::glCompressedTexImage2D; - ActiveTexture = ::glActiveTexture; - - // OpenGL 3.0 - GenerateMipmap = ::glGenerateMipmap; - - // OpenGL 3.2 - TexImage3DMultisample = 0; - TexImage2DMultisample = 0; - - // OpenGL 4.2 - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - if (ctx->format().majorVersion() >= 3) { - // OpenGL ES 3.0+ has immutable storage for 2D and 3D at least. - QOpenGLExtraFunctionsPrivate *extra = static_cast<QOpenGLExtensions *>(context->extraFunctions())->d(); - TexStorage3D = extra->f.TexStorage3D; - TexStorage2D = extra->f.TexStorage2D; - } else { - TexStorage3D = 0; - TexStorage2D = 0; - } - TexStorage1D = 0; - - // OpenGL 4.3 - TexStorage3DMultisample = 0; - TexStorage2DMultisample = 0; - TexBufferRange = 0; - TextureView = 0; - - // OpenGL ES 3.1+ has TexStorage2DMultisample - if (ctx->format().version() >= qMakePair(3, 1)) { - QOpenGLExtraFunctionsPrivate *extra = static_cast<QOpenGLExtensions *>(context->extraFunctions())->d(); - TexStorage2DMultisample = extra->f.TexStorage2DMultisample; - } - -#endif - - if (context->isOpenGLES() && context->hasExtension(QByteArrayLiteral("GL_OES_texture_3D"))) { - TexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLsizei, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*)>(context->getProcAddress("glTexImage3DOES")); - TexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLenum, const GLvoid*)>(context->getProcAddress("glTexSubImage3DOES")); - CompressedTexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLenum, GLsizei, GLsizei, GLsizei, GLint, GLsizei, const GLvoid*)>(context->getProcAddress("glCompressedTexImage3DOES")); - CompressedTexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum, GLint, GLint, GLint, GLint, GLsizei, GLsizei, GLsizei, GLenum, GLsizei, const GLvoid*)>(context->getProcAddress("glCompressedTexSubImage3DOES")); - } else { - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - if (ctx->isOpenGLES() && ctx->format().majorVersion() >= 3) { - // OpenGL ES 3.0+ has glTexImage3D. - QOpenGLExtraFunctionsPrivate *extra = static_cast<QOpenGLExtensions *>(context->extraFunctions())->d(); - TexImage3D = extra->f.TexImage3D; - TexSubImage3D = extra->f.TexSubImage3D; - CompressedTexImage3D = extra->f.CompressedTexImage3D; - CompressedTexSubImage3D = extra->f.CompressedTexSubImage3D; - } else { - // OpenGL 1.2 - TexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLsizei , GLsizei , GLsizei , GLint , GLenum , GLenum , const GLvoid *)>(context->getProcAddress("glTexImage3D")); - TexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLint , GLint , GLsizei , GLsizei , GLsizei , GLenum , GLenum , const GLvoid *)>(context->getProcAddress("glTexSubImage3D")); - - // OpenGL 1.3 - CompressedTexImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLenum , GLsizei , GLsizei , GLsizei , GLint , GLsizei , const GLvoid *)>(context->getProcAddress("glCompressedTexImage3D")); - CompressedTexSubImage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLint , GLint , GLsizei , GLsizei , GLsizei , GLenum , GLsizei , const GLvoid *)>(context->getProcAddress("glCompressedTexSubImage3D")); - } - } - -#ifndef QT_OPENGL_ES_2 - // OpenGL 1.0 and 1.1 - TexImage1D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLsizei , GLint , GLenum , GLenum , const GLvoid *)>(context->getProcAddress("glTexImage1D")); - TexSubImage1D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLsizei , GLenum , GLenum , const GLvoid *)>(context->getProcAddress("glTexSubImage1D"));\ - - // OpenGL 1.3 - GetCompressedTexImage = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLvoid *)>(context->getProcAddress("glGetCompressedTexImage")); - CompressedTexSubImage1D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLsizei , GLenum , GLsizei , const GLvoid *)>(context->getProcAddress("glCompressedTexSubImage1D")); - CompressedTexSubImage2D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLint , GLint , GLsizei , GLsizei , GLenum , GLsizei , const GLvoid *)>(context->getProcAddress("glCompressedTexSubImage2D")); - CompressedTexImage1D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLenum , GLsizei , GLint , GLsizei , const GLvoid *)>(context->getProcAddress("glCompressedTexImage1D")); - CompressedTexImage2D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLint , GLenum , GLsizei , GLsizei , GLint , GLsizei , const GLvoid *)>(context->getProcAddress("glCompressedTexImage2D")); - ActiveTexture = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum )>(context->getProcAddress("glActiveTexture")); - - // OpenGL 3.0 - GenerateMipmap = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum )>(context->getProcAddress("glGenerateMipmap")); - - // OpenGL 3.2 - TexImage3DMultisample = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLsizei , GLint , GLsizei , GLsizei , GLsizei , GLboolean )>(context->getProcAddress("glTexImage3DMultisample")); - TexImage2DMultisample = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLsizei , GLint , GLsizei , GLsizei , GLboolean )>(context->getProcAddress("glTexImage2DMultisample")); - - // OpenGL 4.2 - TexStorage3D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLsizei , GLenum , GLsizei , GLsizei , GLsizei )>(context->getProcAddress("glTexStorage3D")); - TexStorage2D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLsizei , GLenum , GLsizei , GLsizei )>(context->getProcAddress("glTexStorage2D")); - TexStorage1D = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLsizei , GLenum , GLsizei )>(context->getProcAddress("glTexStorage1D")); - - // OpenGL 4.3 - TexStorage3DMultisample = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLsizei , GLenum , GLsizei , GLsizei , GLsizei , GLboolean )>(context->getProcAddress("glTexStorage3DMultisample")); - TexStorage2DMultisample = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLsizei , GLenum , GLsizei , GLsizei , GLboolean )>(context->getProcAddress("glTexStorage2DMultisample")); - TexBufferRange = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLenum , GLenum , GLuint , GLintptr , GLsizeiptr )>(context->getProcAddress("glTexBufferRange")); - TextureView = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLuint , GLenum , GLuint , GLuint , GLuint , GLuint )>(context->getProcAddress("glTextureView")); -#endif -} - -void QOpenGLTextureHelper::dsa_TextureParameteri(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLint param) -{ - Q_UNUSED(bindingTarget); - TextureParameteriEXT(texture, target, pname, param); -} - -void QOpenGLTextureHelper::dsa_TextureParameteriv(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLint *params) -{ - Q_UNUSED(bindingTarget); - TextureParameterivEXT(texture, target, pname, params); -} - -void QOpenGLTextureHelper::dsa_TextureParameterf(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLfloat param) -{ - Q_UNUSED(bindingTarget); - TextureParameterfEXT(texture, target, pname, param); -} - -void QOpenGLTextureHelper::dsa_TextureParameterfv(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLfloat *params) -{ - Q_UNUSED(bindingTarget); - TextureParameterfvEXT(texture, target, pname, params); -} - -void QOpenGLTextureHelper::dsa_GenerateTextureMipmap(GLuint texture, GLenum target, GLenum bindingTarget) -{ - Q_UNUSED(bindingTarget); - GenerateTextureMipmapEXT(texture, target); -} - -void QOpenGLTextureHelper::dsa_TextureStorage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth) -{ - Q_UNUSED(bindingTarget); - TextureStorage3DEXT(texture, target, levels, internalFormat, width, height, depth); -} - -void QOpenGLTextureHelper::dsa_TextureStorage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height) -{ - Q_UNUSED(bindingTarget); - TextureStorage2DEXT(texture, target, levels, internalFormat, width, height); -} - -void QOpenGLTextureHelper::dsa_TextureStorage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, GLsizei width) -{ - Q_UNUSED(bindingTarget); - TextureStorage1DEXT(texture, target, levels, internalFormat, width); -} - -void QOpenGLTextureHelper::dsa_TextureStorage3DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations) -{ - Q_UNUSED(bindingTarget); - TextureStorage3DMultisampleEXT(texture, target, samples, internalFormat, width, height, depth, fixedSampleLocations); -} - -void QOpenGLTextureHelper::dsa_TextureStorage2DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations) -{ - Q_UNUSED(bindingTarget); - TextureStorage2DMultisampleEXT(texture, target, samples, internalFormat, width, height, fixedSampleLocations); -} - -void QOpenGLTextureHelper::dsa_TextureImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels) -{ - Q_UNUSED(bindingTarget); - TextureImage3DEXT(texture, target, level, internalFormat, width, height, depth, border, format, type, pixels); -} - -void QOpenGLTextureHelper::dsa_TextureImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) -{ - Q_UNUSED(bindingTarget); - TextureImage2DEXT(texture, target, level, internalFormat, width, height, border, format, type, pixels); -} - -void QOpenGLTextureHelper::dsa_TextureImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels) -{ - Q_UNUSED(bindingTarget); - TextureImage1DEXT(texture, target, level, internalFormat, width, border, format, type, pixels); -} - -void QOpenGLTextureHelper::dsa_TextureSubImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels) -{ - Q_UNUSED(bindingTarget); - TextureSubImage3DEXT(texture, target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); -} - -void QOpenGLTextureHelper::dsa_TextureSubImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) -{ - Q_UNUSED(bindingTarget); - TextureSubImage2DEXT(texture, target, level, xoffset, yoffset, width, height, format, type, pixels); -} - -void QOpenGLTextureHelper::dsa_TextureSubImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels) -{ - Q_UNUSED(bindingTarget); - TextureSubImage1DEXT(texture, target, level, xoffset, width, format, type, pixels); -} - -void QOpenGLTextureHelper::dsa_TextureImage3DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations) -{ - Q_UNUSED(bindingTarget); - TextureImage3DMultisampleNV(texture, target, samples, internalFormat, width, height, depth, fixedSampleLocations); -} - -void QOpenGLTextureHelper::dsa_TextureImage2DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations) -{ - Q_UNUSED(bindingTarget); - TextureImage2DMultisampleNV(texture, target, samples, internalFormat, width, height, fixedSampleLocations); -} - -void QOpenGLTextureHelper::dsa_CompressedTextureSubImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits) -{ - Q_UNUSED(bindingTarget); - CompressedTextureSubImage1DEXT(texture, target, level, xoffset, width, format, imageSize, bits); -} - -void QOpenGLTextureHelper::dsa_CompressedTextureSubImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits) -{ - Q_UNUSED(bindingTarget); - CompressedTextureSubImage2DEXT(texture, target, level, xoffset, yoffset, width, height, format, imageSize, bits); -} - -void QOpenGLTextureHelper::dsa_CompressedTextureSubImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits) -{ - Q_UNUSED(bindingTarget); - CompressedTextureSubImage3DEXT(texture, target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, bits); -} - -void QOpenGLTextureHelper::dsa_CompressedTextureImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits) -{ - Q_UNUSED(bindingTarget); - CompressedTextureImage1DEXT(texture, target, level, internalFormat, width, border, imageSize, bits); -} - -void QOpenGLTextureHelper::dsa_CompressedTextureImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits) -{ - Q_UNUSED(bindingTarget); - CompressedTextureImage2DEXT(texture, target, level, internalFormat, width, height, border, imageSize, bits); -} - -void QOpenGLTextureHelper::dsa_CompressedTextureImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits) -{ - Q_UNUSED(bindingTarget); - CompressedTextureImage3DEXT(texture, target, level, internalFormat, width, height, depth, border, imageSize, bits); -} - -namespace { - -class TextureBinder -{ -public: - TextureBinder(QOpenGLFunctions *functions, GLuint texture, GLenum target, GLenum bindingTarget) - : m_functions(functions) - { - // For cubemaps we can't use the standard DSA emulation as it is illegal to - // try to bind a texture to one of the cubemap face targets. So we force the - // target and binding target to the cubemap values in this case. - switch (target) { - case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: - case GL_TEXTURE_CUBE_MAP_POSITIVE_X: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: - case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: - case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: - bindingTarget = GL_TEXTURE_BINDING_CUBE_MAP; - m_target = GL_TEXTURE_CUBE_MAP; - break; - - default: - m_target = target; - break; - } - - m_functions->glGetIntegerv(bindingTarget, &m_oldTexture); - m_functions->glBindTexture(m_target, texture); - } - - ~TextureBinder() - { - m_functions->glBindTexture(m_target, m_oldTexture); - } - -private: - QOpenGLFunctions *m_functions; - GLenum m_target; - GLint m_oldTexture; -}; - -} // namespace - -void QOpenGLTextureHelper::qt_TextureParameteri(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLint param) -{ - TextureBinder binder(functions, texture, target, bindingTarget); - functions->glTexParameteri(target, pname, param); -} - -void QOpenGLTextureHelper::qt_TextureParameteriv(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLint *params) -{ - TextureBinder binder(functions, texture, target, bindingTarget); - functions->glTexParameteriv(target, pname, params); -} - -void QOpenGLTextureHelper::qt_TextureParameterf(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLfloat param) -{ - TextureBinder binder(functions, texture, target, bindingTarget); - functions->glTexParameterf(target, pname, param); -} - -void QOpenGLTextureHelper::qt_TextureParameterfv(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLfloat *params) -{ - TextureBinder binder(functions, texture, target, bindingTarget); - functions->glTexParameterfv(target, pname, params); -} - -void QOpenGLTextureHelper::qt_GenerateTextureMipmap(GLuint texture, GLenum target, GLenum bindingTarget) -{ - TextureBinder binder(functions, texture, target, bindingTarget); - functions->glGenerateMipmap(target); -} - -void QOpenGLTextureHelper::qt_TextureStorage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth) -{ - TextureBinder binder(functions, texture, target, bindingTarget); - glTexStorage3D(target, levels, internalFormat, width, height, depth); -} - -void QOpenGLTextureHelper::qt_TextureStorage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height) -{ - TextureBinder binder(functions, texture, target, bindingTarget); - glTexStorage2D(target, levels, internalFormat, width, height); -} - -void QOpenGLTextureHelper::qt_TextureStorage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, GLsizei width) -{ - TextureBinder binder(functions, texture, target, bindingTarget); - glTexStorage1D(target, levels, internalFormat, width); -} - -void QOpenGLTextureHelper::qt_TextureStorage3DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations) -{ - TextureBinder binder(functions, texture, target, bindingTarget); - glTexStorage3DMultisample(target, samples, internalFormat, width, height, depth, fixedSampleLocations); -} - -void QOpenGLTextureHelper::qt_TextureStorage2DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations) -{ - TextureBinder binder(functions, texture, target, bindingTarget); - glTexStorage2DMultisample(target, samples, internalFormat, width, height, fixedSampleLocations); -} - -void QOpenGLTextureHelper::qt_TextureImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels) -{ - TextureBinder binder(functions, texture, target, bindingTarget); - glTexImage3D(target, level, internalFormat, width, height, depth, border, format, type, pixels); -} - -void QOpenGLTextureHelper::qt_TextureImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) -{ - TextureBinder binder(functions, texture, target, bindingTarget); - functions->glTexImage2D(target, level, internalFormat, width, height, border, format, type, pixels); -} - -void QOpenGLTextureHelper::qt_TextureImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels) -{ - TextureBinder binder(functions, texture, target, bindingTarget); - glTexImage1D(target, level, internalFormat, width, border, format, type, pixels); -} - -void QOpenGLTextureHelper::qt_TextureSubImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels) -{ - TextureBinder binder(functions, texture, target, bindingTarget); - glTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); -} - -void QOpenGLTextureHelper::qt_TextureSubImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels) -{ - TextureBinder binder(functions, texture, target, bindingTarget); - functions->glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); -} - -void QOpenGLTextureHelper::qt_TextureSubImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels) -{ - TextureBinder binder(functions, texture, target, bindingTarget); - glTexSubImage1D(target, level, xoffset, width, format, type, pixels); -} - -void QOpenGLTextureHelper::qt_TextureImage3DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations) -{ - TextureBinder binder(functions, texture, target, bindingTarget); - glTexImage3DMultisample(target, samples, internalFormat, width, height, depth, fixedSampleLocations); -} - -void QOpenGLTextureHelper::qt_TextureImage2DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations) -{ - TextureBinder binder(functions, texture, target, bindingTarget); - glTexImage2DMultisample(target, samples, internalFormat, width, height, fixedSampleLocations); -} - -void QOpenGLTextureHelper::qt_CompressedTextureSubImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits) -{ - TextureBinder binder(functions, texture, target, bindingTarget); - glCompressedTexSubImage1D(target, level, xoffset, width, format, imageSize, bits); -} - -void QOpenGLTextureHelper::qt_CompressedTextureSubImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits) -{ - TextureBinder binder(functions, texture, target, bindingTarget); - glCompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, bits); -} - -void QOpenGLTextureHelper::qt_CompressedTextureSubImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits) -{ - TextureBinder binder(functions, texture, target, bindingTarget); - glCompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, bits); -} - -void QOpenGLTextureHelper::qt_CompressedTextureImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits) -{ - TextureBinder binder(functions, texture, target, bindingTarget); - glCompressedTexImage1D(target, level, internalFormat, width, border, imageSize, bits); -} - -void QOpenGLTextureHelper::qt_CompressedTextureImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits) -{ - TextureBinder binder(functions, texture, target, bindingTarget); - glCompressedTexImage2D(target, level, internalFormat, width, height, border, imageSize, bits); -} - -void QOpenGLTextureHelper::qt_CompressedTextureImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits) -{ - TextureBinder binder(functions, texture, target, bindingTarget); - glCompressedTexImage3D(target, level, internalFormat, width, height, depth, border, imageSize, bits); -} - -QT_END_NAMESPACE diff --git a/src/gui/opengl/qopengltexturehelper_p.h b/src/gui/opengl/qopengltexturehelper_p.h deleted file mode 100644 index 62d0125daf..0000000000 --- a/src/gui/opengl/qopengltexturehelper_p.h +++ /dev/null @@ -1,797 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB). -** 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 QOPENGLTEXTUREHELPER_P_H -#define QOPENGLTEXTUREHELPER_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include <QtGui/private/qtguiglobal_p.h> - -#ifndef QT_NO_OPENGL - -#include "qopengl.h" -#include "qopenglpixeltransferoptions.h" -#include "qopengltexture.h" -#include "qopenglfunctions.h" - -QT_BEGIN_NAMESPACE - -// Constants for OpenGL and OpenGL ES 3.0+ which are not available with OpenGL ES 2.0. -#ifndef GL_TEXTURE_BASE_LEVEL -#define GL_TEXTURE_BASE_LEVEL 0x813C -#endif -#ifndef GL_TEXTURE_MAX_LEVEL -#define GL_TEXTURE_MAX_LEVEL 0x813D -#endif -#ifndef GL_TEXTURE_COMPARE_MODE -#define GL_TEXTURE_COMPARE_MODE 0x884C -#endif -#ifndef GL_TEXTURE_COMPARE_FUNC -#define GL_TEXTURE_COMPARE_FUNC 0x884D -#endif - -// use GL_APICALL only on Android + __clang__ -#if !defined(Q_OS_ANDROID) || !defined(__clang__) -# undef GL_APICALL -# define GL_APICALL -#elif !defined(GL_APICALL) -# define GL_APICALL -#endif - -class QOpenGLContext; - -class QOpenGLTextureHelper -{ -public: - QOpenGLTextureHelper(QOpenGLContext *context); - - // DSA-like API. Will either use real DSA or our emulation - inline void glTextureParameteri(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLint param) - { - (this->*TextureParameteri)(texture, target, bindingTarget, pname, param); - } - - inline void glTextureParameteriv(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLint *params) - { - (this->*TextureParameteriv)(texture, target, bindingTarget, pname, params); - } - - inline void glTextureParameterf(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLfloat param) - { - (this->*TextureParameterf)(texture, target, bindingTarget, pname, param); - } - - inline void glTextureParameterfv(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLfloat *params) - { - (this->*TextureParameterfv)(texture, target, bindingTarget, pname, params); - } - - inline void glGenerateTextureMipmap(GLuint texture, GLenum target, GLenum bindingTarget) - { - (this->*GenerateTextureMipmap)(texture, target, bindingTarget); - } - - inline void glTextureStorage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, - GLsizei width, GLsizei height, GLsizei depth) - { - (this->*TextureStorage3D)(texture, target, bindingTarget, levels, internalFormat, width, height, depth); - } - - inline void glTextureStorage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, - GLsizei width, GLsizei height) - { - (this->*TextureStorage2D)(texture, target, bindingTarget, levels, internalFormat, width, height); - } - - inline void glTextureStorage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, - GLsizei width) - { - (this->*TextureStorage1D)(texture, target, bindingTarget, levels, internalFormat, width); - } - - inline void glTextureStorage3DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLenum internalFormat, - GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations) - { - (this->*TextureStorage3DMultisample)(texture, target, bindingTarget, samples, internalFormat, width, height, depth, fixedSampleLocations); - } - - inline void glTextureStorage2DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLenum internalFormat, - GLsizei width, GLsizei height, GLboolean fixedSampleLocations) - { - (this->*TextureStorage2DMultisample)(texture, target, bindingTarget, samples, internalFormat, width, height, fixedSampleLocations); - } - - inline void glTextureImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, - GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels) - { - (this->*TextureImage3D)(texture, target, bindingTarget, level, internalFormat, width, height, depth, border, format, type, pixels); - } - - inline void glTextureImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, - GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels) - { - (this->*TextureImage2D)(texture, target, bindingTarget, level, internalFormat, width, height, border, format, type, pixels); - } - - inline void glTextureImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, - GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels) - { - (this->*TextureImage1D)(texture, target, bindingTarget, level, internalFormat, width, border, format, type, pixels); - } - - inline void glTextureSubImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, - const GLvoid *pixels, const QOpenGLPixelTransferOptions * const options = nullptr) - { - if (options) { - QOpenGLPixelTransferOptions oldOptions = savePixelUploadOptions(); - setPixelUploadOptions(*options); - (this->*TextureSubImage3D)(texture, target, bindingTarget, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); - setPixelUploadOptions(oldOptions); - } else { - (this->*TextureSubImage3D)(texture, target, bindingTarget, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); - } - } - - inline void glTextureSubImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height, GLenum format, GLenum type, - const GLvoid *pixels, const QOpenGLPixelTransferOptions * const options = nullptr) - { - if (options) { - QOpenGLPixelTransferOptions oldOptions = savePixelUploadOptions(); - setPixelUploadOptions(*options); - (this->*TextureSubImage2D)(texture, target, bindingTarget, level, xoffset, yoffset, width, height, format, type, pixels); - setPixelUploadOptions(oldOptions); - } else { - (this->*TextureSubImage2D)(texture, target, bindingTarget, level, xoffset, yoffset, width, height, format, type, pixels); - } - } - - inline void glTextureSubImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, - GLsizei width, GLenum format, GLenum type, - const GLvoid *pixels, const QOpenGLPixelTransferOptions * const options = nullptr) - { - if (options) { - QOpenGLPixelTransferOptions oldOptions = savePixelUploadOptions(); - setPixelUploadOptions(*options); - (this->*TextureSubImage1D)(texture, target, bindingTarget, level, xoffset, width, format, type, pixels); - setPixelUploadOptions(oldOptions); - } else { - (this->*TextureSubImage1D)(texture, target, bindingTarget, level, xoffset, width, format, type, pixels); - } - } - - inline void glTextureImage3DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLint internalFormat, - GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations) - { - (this->*TextureImage3DMultisample)(texture, target, bindingTarget, samples, internalFormat, width, height, depth, fixedSampleLocations); - } - - inline void glTextureImage2DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLint internalFormat, - GLsizei width, GLsizei height, GLboolean fixedSampleLocations) - { - (this->*TextureImage2DMultisample)(texture, target, bindingTarget, samples, internalFormat, width, height, fixedSampleLocations); - } - - inline void glCompressedTextureSubImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, - GLint xoffset, GLsizei width, - GLenum format, GLsizei imageSize, const GLvoid *bits, - const QOpenGLPixelTransferOptions * const options = nullptr) - { - if (options) { - QOpenGLPixelTransferOptions oldOptions = savePixelUploadOptions(); - setPixelUploadOptions(*options); - (this->*CompressedTextureSubImage1D)(texture, target, bindingTarget, level, xoffset, width, format, imageSize, bits); - setPixelUploadOptions(oldOptions); - } else { - (this->*CompressedTextureSubImage1D)(texture, target, bindingTarget, level, xoffset, width, format, imageSize, bits); - } - } - - inline void glCompressedTextureSubImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, - GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height, - GLenum format, GLsizei imageSize, const GLvoid *bits, - const QOpenGLPixelTransferOptions * const options = nullptr) - { - if (options) { - QOpenGLPixelTransferOptions oldOptions = savePixelUploadOptions(); - setPixelUploadOptions(*options); - (this->*CompressedTextureSubImage2D)(texture, target, bindingTarget, level, xoffset, yoffset, width, height, format, imageSize, bits); - setPixelUploadOptions(oldOptions); - } else { - (this->*CompressedTextureSubImage2D)(texture, target, bindingTarget, level, xoffset, yoffset, width, height, format, imageSize, bits); - } - } - - inline void glCompressedTextureSubImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, - GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLsizei imageSize, const GLvoid *bits, - const QOpenGLPixelTransferOptions * const options = nullptr) - { - if (options) { - QOpenGLPixelTransferOptions oldOptions = savePixelUploadOptions(); - setPixelUploadOptions(*options); - (this->*CompressedTextureSubImage3D)(texture, target, bindingTarget, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, bits); - setPixelUploadOptions(oldOptions); - } else { - (this->*CompressedTextureSubImage3D)(texture, target, bindingTarget, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, bits); - } - } - - inline void glCompressedTextureImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, - GLenum internalFormat, GLsizei width, - GLint border, GLsizei imageSize, const GLvoid *bits, - const QOpenGLPixelTransferOptions * const options = nullptr) - { - if (options) { - QOpenGLPixelTransferOptions oldOptions = savePixelUploadOptions(); - setPixelUploadOptions(*options); - (this->*CompressedTextureImage1D)(texture, target, bindingTarget, level, internalFormat, width, border, imageSize, bits); - setPixelUploadOptions(oldOptions); - } else { - (this->*CompressedTextureImage1D)(texture, target, bindingTarget, level, internalFormat, width, border, imageSize, bits); - } - } - - inline void glCompressedTextureImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, - GLenum internalFormat, GLsizei width, GLsizei height, - GLint border, GLsizei imageSize, const GLvoid *bits, - const QOpenGLPixelTransferOptions * const options = nullptr) - - { - if (options) { - QOpenGLPixelTransferOptions oldOptions = savePixelUploadOptions(); - setPixelUploadOptions(*options); - (this->*CompressedTextureImage2D)(texture, target, bindingTarget, level, internalFormat, width, height, border, imageSize, bits); - setPixelUploadOptions(oldOptions); - } else { - (this->*CompressedTextureImage2D)(texture, target, bindingTarget, level, internalFormat, width, height, border, imageSize, bits); - } - } - - inline void glCompressedTextureImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, - GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, - GLint border, GLsizei imageSize, const GLvoid *bits, - const QOpenGLPixelTransferOptions * const options = nullptr) - { - if (options) { - QOpenGLPixelTransferOptions oldOptions = savePixelUploadOptions(); - setPixelUploadOptions(*options); - (this->*CompressedTextureImage3D)(texture, target, bindingTarget, level, internalFormat, width, height, depth, border, imageSize, bits); - setPixelUploadOptions(oldOptions); - } else { - (this->*CompressedTextureImage3D)(texture, target, bindingTarget, level, internalFormat, width, height, depth, border, imageSize, bits); - } - } - -private: - // DSA wrapper (so we can use pointer to member function as switch) - void dsa_TextureParameteri(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLint param); - - void dsa_TextureParameteriv(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLint *params); - - void dsa_TextureParameterf(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLfloat param); - - void dsa_TextureParameterfv(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLfloat *params); - - void dsa_GenerateTextureMipmap(GLuint texture, GLenum target, GLenum bindingTarget); - - void dsa_TextureStorage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, - GLsizei width, GLsizei height, GLsizei depth); - - void dsa_TextureStorage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, - GLsizei width, GLsizei height); - - void dsa_TextureStorage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, - GLsizei width); - - void dsa_TextureStorage3DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLenum internalFormat, - GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); - - void dsa_TextureStorage2DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLenum internalFormat, - GLsizei width, GLsizei height, GLboolean fixedSampleLocations); - - void dsa_TextureImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, - GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); - - void dsa_TextureImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, - GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); - - void dsa_TextureImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, - GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); - - void dsa_TextureSubImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); - - void dsa_TextureSubImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); - - void dsa_TextureSubImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, - GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); - - void dsa_TextureImage3DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLint internalFormat, - GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); - - void dsa_TextureImage2DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLint internalFormat, - GLsizei width, GLsizei height, GLboolean fixedSampleLocations); - - void dsa_CompressedTextureSubImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, - GLint xoffset, GLsizei width, - GLenum format, GLsizei imageSize, const GLvoid *bits); - - void dsa_CompressedTextureSubImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, - GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height, - GLenum format, GLsizei imageSize, const GLvoid *bits); - - void dsa_CompressedTextureSubImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, - GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLsizei imageSize, const GLvoid *bits); - - void dsa_CompressedTextureImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, - GLenum internalFormat, GLsizei width, - GLint border, GLsizei imageSize, const GLvoid *bits); - - void dsa_CompressedTextureImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, - GLenum internalFormat, GLsizei width, GLsizei height, - GLint border, GLsizei imageSize, const GLvoid *bits); - - void dsa_CompressedTextureImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, - GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, - GLint border, GLsizei imageSize, const GLvoid *bits); - - // DSA emulation API - void qt_TextureParameteri(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLint param); - - void qt_TextureParameteriv(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLint *params); - - void qt_TextureParameterf(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLfloat param); - - void qt_TextureParameterfv(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLfloat *params); - - void qt_GenerateTextureMipmap(GLuint texture, GLenum target, GLenum bindingTarget); - - void qt_TextureStorage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, - GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth); - - void qt_TextureStorage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, - GLenum internalFormat, GLsizei width, GLsizei height); - - void qt_TextureStorage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, - GLenum internalFormat, GLsizei width); - - void qt_TextureStorage3DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, - GLenum internalFormat, GLsizei width, GLsizei height, - GLsizei depth, GLboolean fixedSampleLocations); - - void qt_TextureStorage2DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, - GLenum internalFormat, GLsizei width, GLsizei height, - GLboolean fixedSampleLocations); - - void qt_TextureImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, - GLsizei width, GLsizei height, GLsizei depth, - GLint border, GLenum format, GLenum type, - const GLvoid *pixels); - - void qt_TextureImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, - GLsizei width, GLsizei height, - GLint border, GLenum format, GLenum type, - const GLvoid *pixels); - - void qt_TextureImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, - GLsizei width, GLint border, GLenum format, GLenum type, - const GLvoid *pixels); - - void qt_TextureSubImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, - GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLenum type, const GLvoid *pixels); - - void qt_TextureSubImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, - GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height, - GLenum format, GLenum type, const GLvoid *pixels); - - void qt_TextureSubImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, - GLint xoffset, GLsizei width, - GLenum format, GLenum type, const GLvoid *pixels); - - void qt_TextureImage3DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, - GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, - GLboolean fixedSampleLocations); - - void qt_TextureImage2DMultisample(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, - GLint internalFormat, GLsizei width, GLsizei height, - GLboolean fixedSampleLocations); - - void qt_CompressedTextureSubImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, - GLint xoffset, GLsizei width, GLenum format, - GLsizei imageSize, const GLvoid *bits); - - void qt_CompressedTextureSubImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, - GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height, - GLenum format, GLsizei imageSize, const GLvoid *bits); - - void qt_CompressedTextureSubImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, - GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, - GLenum format, GLsizei imageSize, const GLvoid *bits); - - void qt_CompressedTextureImage1D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, - GLsizei width, GLint border, - GLsizei imageSize, const GLvoid *bits); - - void qt_CompressedTextureImage2D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, - GLsizei width, GLsizei height, GLint border, - GLsizei imageSize, const GLvoid *bits); - - void qt_CompressedTextureImage3D(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, - GLsizei width, GLsizei height, GLsizei depth, GLint border, - GLsizei imageSize, const GLvoid *bits); - -public: - // Raw OpenGL functions, resolved and used by our DSA-like static functions if no EXT_direct_state_access is available - - // OpenGL 1.0 - inline void glTexImage1D(GLenum target, GLint level, GLint internalFormat, - GLsizei width, GLint border, - GLenum format, GLenum type, const GLvoid *pixels) - { - TexImage1D(target, level, internalFormat, width, border, format, type, pixels); - } - - // OpenGL 1.1 - inline void glTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLsizei width, - GLenum format, GLenum type, const GLvoid *pixels) - { - TexSubImage1D(target, level, xoffset, width, format, type, pixels); - } - - // OpenGL 1.2 - inline void glTexImage3D(GLenum target, GLint level, GLint internalFormat, - GLsizei width, GLsizei height, GLsizei depth, GLint border, - GLenum format, GLenum type, const GLvoid *pixels) - { - TexImage3D(target, level, internalFormat, width, height, depth, border, format, type, pixels); - } - - inline void glTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels) - { - TexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels); - } - - // OpenGL 1.3 - inline void glGetCompressedTexImage(GLenum target, GLint level, GLvoid *img) - { - GetCompressedTexImage(target, level, img); - } - - inline void glCompressedTexSubImage1D(GLenum target, GLint level, GLint xoffset, GLsizei width, - GLenum format, GLsizei imageSize, const GLvoid *data) - { - CompressedTexSubImage1D(target, level, xoffset, width, format, imageSize, data); - } - - inline void glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, - GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data) - { - CompressedTexSubImage2D(target, level, xoffset, yoffset, width, height, format, imageSize, data); - } - - inline void glCompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, - GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data) - { - CompressedTexSubImage3D(target, level, xoffset, yoffset, zoffset, width, height, depth, format, imageSize, data); - } - - inline void glCompressedTexImage1D(GLenum target, GLint level, GLenum internalFormat, GLsizei width, - GLint border, GLsizei imageSize, const GLvoid *data) - { - CompressedTexImage1D(target, level, internalFormat, width, border, imageSize, data); - } - - inline void glCompressedTexImage2D(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, - GLint border, GLsizei imageSize, const GLvoid *data) - { - CompressedTexImage2D(target, level, internalFormat, width, height, border, imageSize, data); - } - - inline void glCompressedTexImage3D(GLenum target, GLint level, GLenum internalFormat, - GLsizei width, GLsizei height, GLsizei depth, - GLint border, GLsizei imageSize, const GLvoid *data) - { - CompressedTexImage3D(target, level, internalFormat, width, height, depth, border, imageSize, data); - } - - inline void glActiveTexture(GLenum texture) - { - ActiveTexture(texture); - } - - // OpenGL 3.0 - inline void glGenerateMipmap(GLenum target) - { - GenerateMipmap(target); - } - - // OpenGL 3.2 - inline void glTexImage3DMultisample(GLenum target, GLsizei samples, GLint internalFormat, - GLsizei width, GLsizei height, GLsizei depth, - GLboolean fixedSampleLocations) - { - TexImage3DMultisample(target, samples, internalFormat, width, height, depth, fixedSampleLocations); - } - - inline void glTexImage2DMultisample(GLenum target, GLsizei samples, GLint internalFormat, - GLsizei width, GLsizei height, - GLboolean fixedSampleLocations) - { - TexImage2DMultisample(target, samples, internalFormat, width, height, fixedSampleLocations); - } - - // OpenGL 4.2 - inline void glTexStorage3D(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth) - { - TexStorage3D(target, levels, internalFormat, width, height, depth); - } - - inline void glTexStorage2D(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height) - { - TexStorage2D(target, levels, internalFormat, width, height); - } - - inline void glTexStorage1D(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width) - { - TexStorage1D(target, levels, internalFormat, width); - } - - // OpenGL 4.3 - inline void glTexStorage3DMultisample(GLenum target, GLsizei samples, GLenum internalFormat, - GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations) - { - TexStorage3DMultisample(target, samples, internalFormat, width, height, depth, fixedSampleLocations); - } - - inline void glTexStorage2DMultisample(GLenum target, GLsizei samples, GLenum internalFormat, - GLsizei width, GLsizei height, GLboolean fixedSampleLocations) - { - TexStorage2DMultisample(target, samples, internalFormat, width, height, fixedSampleLocations); - } - - inline void glTexBufferRange(GLenum target, GLenum internalFormat, GLuint buffer, - GLintptr offset, GLsizeiptr size) - { - TexBufferRange(target, internalFormat, buffer, offset, size); - } - - inline void glTextureView(GLuint texture, GLenum target, GLuint origTexture, GLenum internalFormat, - GLuint minLevel, GLuint numLevels, GLuint minLayer, GLuint numLayers) - { - TextureView(texture, target, origTexture, internalFormat, minLevel, numLevels, minLayer, numLayers); - } - - // Helper functions - inline QOpenGLPixelTransferOptions savePixelUploadOptions() - { - QOpenGLPixelTransferOptions options; - int val = 0; - functions->glGetIntegerv(GL_UNPACK_ALIGNMENT, &val); - options.setAlignment(val); -#if !defined(QT_OPENGL_ES_2) - functions->glGetIntegerv(GL_UNPACK_SKIP_IMAGES, &val); - options.setSkipImages(val); - functions->glGetIntegerv(GL_UNPACK_SKIP_ROWS, &val); - options.setSkipRows(val); - functions->glGetIntegerv(GL_UNPACK_SKIP_PIXELS, &val); - options.setSkipPixels(val); - functions->glGetIntegerv(GL_UNPACK_IMAGE_HEIGHT, &val); - options.setImageHeight(val); - functions->glGetIntegerv(GL_UNPACK_ROW_LENGTH, &val); - options.setRowLength(val); - GLboolean b = GL_FALSE; - functions->glGetBooleanv(GL_UNPACK_LSB_FIRST, &b); - options.setLeastSignificantByteFirst(b); - functions->glGetBooleanv(GL_UNPACK_SWAP_BYTES, &b); - options.setSwapBytesEnabled(b); -#endif - return options; - } - - inline void setPixelUploadOptions(const QOpenGLPixelTransferOptions &options) - { - functions->glPixelStorei(GL_UNPACK_ALIGNMENT, options.alignment()); -#if !defined(QT_OPENGL_ES_2) - functions->glPixelStorei(GL_UNPACK_SKIP_IMAGES, options.skipImages()); - functions->glPixelStorei(GL_UNPACK_SKIP_ROWS, options.skipRows()); - functions->glPixelStorei(GL_UNPACK_SKIP_PIXELS, options.skipPixels()); - functions->glPixelStorei(GL_UNPACK_IMAGE_HEIGHT, options.imageHeight()); - functions->glPixelStorei(GL_UNPACK_ROW_LENGTH, options.rowLength()); - functions->glPixelStorei(GL_UNPACK_LSB_FIRST, options.isLeastSignificantBitFirst()); - functions->glPixelStorei(GL_UNPACK_SWAP_BYTES, options.isSwapBytesEnabled()); -#endif - } - - QOpenGLFunctions *functions; -private: - // Typedefs and pointers to member functions used to switch between EXT_direct_state_access and our own emulated DSA. - // The argument match the corresponding GL function, but there's an extra "GLenum bindingTarget" which gets used with - // the DSA emulation -- it contains the right GL_BINDING_TEXTURE_X to use. - typedef void (QOpenGLTextureHelper::*TextureParameteriMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLint param); - typedef void (QOpenGLTextureHelper::*TextureParameterivMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLint *params); - typedef void (QOpenGLTextureHelper::*TextureParameterfMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, GLfloat param); - typedef void (QOpenGLTextureHelper::*TextureParameterfvMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLenum pname, const GLfloat *params); - typedef void (QOpenGLTextureHelper::*GenerateTextureMipmapMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget); - typedef void (QOpenGLTextureHelper::*TextureStorage3DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth); - typedef void (QOpenGLTextureHelper::*TextureStorage2DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height); - typedef void (QOpenGLTextureHelper::*TextureStorage1DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei levels, GLenum internalFormat, GLsizei width); - typedef void (QOpenGLTextureHelper::*TextureStorage3DMultisampleMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); - typedef void (QOpenGLTextureHelper::*TextureStorage2DMultisampleMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); - typedef void (QOpenGLTextureHelper::*TextureImage3DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); - typedef void (QOpenGLTextureHelper::*TextureImage2DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); - typedef void (QOpenGLTextureHelper::*TextureImage1DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); - typedef void (QOpenGLTextureHelper::*TextureSubImage3DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); - typedef void (QOpenGLTextureHelper::*TextureSubImage2DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); - typedef void (QOpenGLTextureHelper::*TextureSubImage1DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); - typedef void (QOpenGLTextureHelper::*TextureImage3DMultisampleMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); - typedef void (QOpenGLTextureHelper::*TextureImage2DMultisampleMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); - typedef void (QOpenGLTextureHelper::*CompressedTextureSubImage1DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); - typedef void (QOpenGLTextureHelper::*CompressedTextureSubImage2DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); - typedef void (QOpenGLTextureHelper::*CompressedTextureSubImage3DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits); - typedef void (QOpenGLTextureHelper::*CompressedTextureImage1DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); - typedef void (QOpenGLTextureHelper::*CompressedTextureImage2DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); - typedef void (QOpenGLTextureHelper::*CompressedTextureImage3DMemberFunc)(GLuint texture, GLenum target, GLenum bindingTarget, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); - - - TextureParameteriMemberFunc TextureParameteri; - TextureParameterivMemberFunc TextureParameteriv; - TextureParameterfMemberFunc TextureParameterf; - TextureParameterfvMemberFunc TextureParameterfv; - GenerateTextureMipmapMemberFunc GenerateTextureMipmap; - TextureStorage3DMemberFunc TextureStorage3D; - TextureStorage2DMemberFunc TextureStorage2D; - TextureStorage1DMemberFunc TextureStorage1D; - TextureStorage3DMultisampleMemberFunc TextureStorage3DMultisample; - TextureStorage2DMultisampleMemberFunc TextureStorage2DMultisample; - TextureImage3DMemberFunc TextureImage3D; - TextureImage2DMemberFunc TextureImage2D; - TextureImage1DMemberFunc TextureImage1D; - TextureSubImage3DMemberFunc TextureSubImage3D; - TextureSubImage2DMemberFunc TextureSubImage2D; - TextureSubImage1DMemberFunc TextureSubImage1D; - TextureImage3DMultisampleMemberFunc TextureImage3DMultisample; - TextureImage2DMultisampleMemberFunc TextureImage2DMultisample; - CompressedTextureSubImage1DMemberFunc CompressedTextureSubImage1D; - CompressedTextureSubImage2DMemberFunc CompressedTextureSubImage2D; - CompressedTextureSubImage3DMemberFunc CompressedTextureSubImage3D; - CompressedTextureImage1DMemberFunc CompressedTextureImage1D; - CompressedTextureImage2DMemberFunc CompressedTextureImage2D; - CompressedTextureImage3DMemberFunc CompressedTextureImage3D; - - // Raw function pointers for core and DSA functions - - // EXT_direct_state_access used when DSA is available - void (QOPENGLF_APIENTRYP TextureParameteriEXT)(GLuint texture, GLenum target, GLenum pname, GLint param); - void (QOPENGLF_APIENTRYP TextureParameterivEXT)(GLuint texture, GLenum target, GLenum pname, const GLint *params); - void (QOPENGLF_APIENTRYP TextureParameterfEXT)(GLuint texture, GLenum target, GLenum pname, GLfloat param); - void (QOPENGLF_APIENTRYP TextureParameterfvEXT)(GLuint texture, GLenum target, GLenum pname, const GLfloat *params); - void (QOPENGLF_APIENTRYP GenerateTextureMipmapEXT)(GLuint texture, GLenum target); - void (QOPENGLF_APIENTRYP TextureStorage3DEXT)(GLuint texture, GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth); - void (QOPENGLF_APIENTRYP TextureStorage2DEXT)(GLuint texture, GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height); - void (QOPENGLF_APIENTRYP TextureStorage1DEXT)(GLuint texture, GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width); - void (QOPENGLF_APIENTRYP TextureStorage3DMultisampleEXT)(GLuint texture, GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); - void (QOPENGLF_APIENTRYP TextureStorage2DMultisampleEXT)(GLuint texture, GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); - void (QOPENGLF_APIENTRYP TextureImage3DEXT)(GLuint texture, GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); - void (QOPENGLF_APIENTRYP TextureImage2DEXT)(GLuint texture, GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); - void (QOPENGLF_APIENTRYP TextureImage1DEXT)(GLuint texture, GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); - void (QOPENGLF_APIENTRYP TextureSubImage3DEXT)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); - void (QOPENGLF_APIENTRYP TextureSubImage2DEXT)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); - void (QOPENGLF_APIENTRYP TextureSubImage1DEXT)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); - void (QOPENGLF_APIENTRYP CompressedTextureSubImage1DEXT)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *bits); - void (QOPENGLF_APIENTRYP CompressedTextureSubImage2DEXT)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *bits); - void (QOPENGLF_APIENTRYP CompressedTextureSubImage3DEXT)(GLuint texture, GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *bits); - void (QOPENGLF_APIENTRYP CompressedTextureImage1DEXT)(GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *bits); - void (QOPENGLF_APIENTRYP CompressedTextureImage2DEXT)(GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *bits); - void (QOPENGLF_APIENTRYP CompressedTextureImage3DEXT)(GLuint texture, GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *bits); - - - // Plus some missing ones that are in the NV_texture_multisample extension instead - void (QOPENGLF_APIENTRYP TextureImage3DMultisampleNV)(GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); - void (QOPENGLF_APIENTRYP TextureImage2DMultisampleNV)(GLuint texture, GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); - - // OpenGL 1.0 - void (QOPENGLF_APIENTRYP TexImage1D)(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); - - // OpenGL 1.1 - void (QOPENGLF_APIENTRYP TexSubImage1D)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); - - // OpenGL 1.2 - void (QOPENGLF_APIENTRYP TexImage3D)(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels); - void (QOPENGLF_APIENTRYP TexSubImage3D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid *pixels); - - // OpenGL 1.3 - void (QOPENGLF_APIENTRYP GetCompressedTexImage)(GLenum target, GLint level, GLvoid *img); - void (QOPENGLF_APIENTRYP CompressedTexSubImage1D)(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLsizei imageSize, const GLvoid *data); - GL_APICALL void (QOPENGLF_APIENTRYP CompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data); - void (QOPENGLF_APIENTRYP CompressedTexSubImage3D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid *data); - void (QOPENGLF_APIENTRYP CompressedTexImage1D)(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLint border, GLsizei imageSize, const GLvoid *data); - GL_APICALL void (QOPENGLF_APIENTRYP CompressedTexImage2D)(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data); - void (QOPENGLF_APIENTRYP CompressedTexImage3D)(GLenum target, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid *data); - GL_APICALL void (QOPENGLF_APIENTRYP ActiveTexture)(GLenum texture); - - // OpenGL 3.0 - GL_APICALL void (QOPENGLF_APIENTRYP GenerateMipmap)(GLenum target); - - // OpenGL 3.2 - void (QOPENGLF_APIENTRYP TexImage3DMultisample)(GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); - void (QOPENGLF_APIENTRYP TexImage2DMultisample)(GLenum target, GLsizei samples, GLint internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); - - // OpenGL 4.2 - void (QOPENGLF_APIENTRYP TexStorage3D)(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth); - void (QOPENGLF_APIENTRYP TexStorage2D)(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width, GLsizei height); - void (QOPENGLF_APIENTRYP TexStorage1D)(GLenum target, GLsizei levels, GLenum internalFormat, GLsizei width); - - // OpenGL 4.3 - void (QOPENGLF_APIENTRYP TexStorage3DMultisample)(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedSampleLocations); - void (QOPENGLF_APIENTRYP TexStorage2DMultisample)(GLenum target, GLsizei samples, GLenum internalFormat, GLsizei width, GLsizei height, GLboolean fixedSampleLocations); - void (QOPENGLF_APIENTRYP TexBufferRange)(GLenum target, GLenum internalFormat, GLuint buffer, GLintptr offset, GLsizeiptr size); - void (QOPENGLF_APIENTRYP TextureView)(GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers); -}; - -QT_END_NAMESPACE - -#undef Q_CALL_MEMBER_FUNCTION - -#endif // QT_NO_OPENGL - -#endif // QOPENGLTEXTUREHELPER_P_H diff --git a/src/gui/opengl/qopengltextureuploader.cpp b/src/gui/opengl/qopengltextureuploader.cpp deleted file mode 100644 index 9e393bc47a..0000000000 --- a/src/gui/opengl/qopengltextureuploader.cpp +++ /dev/null @@ -1,381 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2018 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 "qopengltextureuploader_p.h" - -#include <qimage.h> -#include <qmath.h> -#include <qopenglfunctions.h> -#include <private/qopenglcontext_p.h> -#include <private/qopenglextensions_p.h> - -#ifndef GL_RED -#define GL_RED 0x1903 -#endif - -#ifndef GL_GREEN -#define GL_GREEN 0x1904 -#endif - -#ifndef GL_BLUE -#define GL_BLUE 0x1905 -#endif - -#ifndef GL_RGB10_A2 -#define GL_RGB10_A2 0x8059 -#endif - -#ifndef GL_RGBA16 -#define GL_RGBA16 0x805B -#endif - -#ifndef GL_BGR -#define GL_BGR 0x80E0 -#endif - -#ifndef GL_BGRA -#define GL_BGRA 0x80E1 -#endif - -#ifndef GL_UNSIGNED_INT_8_8_8_8_REV -#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 -#endif - -#ifndef GL_UNSIGNED_INT_2_10_10_10_REV -#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 -#endif - -#ifndef GL_TEXTURE_SWIZZLE_R -#define GL_TEXTURE_SWIZZLE_R 0x8E42 -#endif - -#ifndef GL_TEXTURE_SWIZZLE_G -#define GL_TEXTURE_SWIZZLE_G 0x8E43 -#endif - -#ifndef GL_TEXTURE_SWIZZLE_B -#define GL_TEXTURE_SWIZZLE_B 0x8E44 -#endif - -#ifndef GL_TEXTURE_SWIZZLE_A -#define GL_TEXTURE_SWIZZLE_A 0x8E45 -#endif - -#ifndef GL_SRGB -#define GL_SRGB 0x8C40 -#endif -#ifndef GL_SRGB_ALPHA -#define GL_SRGB_ALPHA 0x8C42 -#endif - -QT_BEGIN_NAMESPACE - -qsizetype QOpenGLTextureUploader::textureImage(GLenum target, const QImage &image, QOpenGLTextureUploader::BindOptions options, QSize maxSize) -{ - QOpenGLContext *context = QOpenGLContext::currentContext(); - QOpenGLExtensions *funcs = static_cast<QOpenGLExtensions*>(context->functions()); - - QImage tx; - GLenum externalFormat; - GLenum internalFormat; - GLuint pixelType; - QImage::Format targetFormat = QImage::Format_Invalid; - const bool isOpenGL12orBetter = !context->isOpenGLES() && (context->format().majorVersion() >= 2 || context->format().minorVersion() >= 2); - const bool isOpenGLES3orBetter = context->isOpenGLES() && context->format().majorVersion() >= 3; - const bool sRgbBinding = (options & SRgbBindOption); - Q_ASSERT(isOpenGL12orBetter || context->isOpenGLES()); - Q_ASSERT((options & (SRgbBindOption | UseRedForAlphaAndLuminanceBindOption)) != (SRgbBindOption | UseRedForAlphaAndLuminanceBindOption)); - - switch (image.format()) { - case QImage::Format_RGB32: - case QImage::Format_ARGB32: - case QImage::Format_ARGB32_Premultiplied: - if (isOpenGL12orBetter) { - externalFormat = GL_BGRA; - internalFormat = GL_RGBA; - pixelType = GL_UNSIGNED_INT_8_8_8_8_REV; -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - // Without GL_UNSIGNED_INT_8_8_8_8_REV, BGRA only matches ARGB on little endian: - } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::BGRATextureFormat) && !sRgbBinding) { - // The GL_EXT_texture_format_BGRA8888 extension requires the internal format to match the external. - externalFormat = internalFormat = GL_BGRA; - pixelType = GL_UNSIGNED_BYTE; - } else if (context->isOpenGLES() && context->hasExtension(QByteArrayLiteral("GL_APPLE_texture_format_BGRA8888"))) { - // Is only allowed as an external format like OpenGL. - externalFormat = GL_BGRA; - internalFormat = GL_RGBA; - pixelType = GL_UNSIGNED_BYTE; -#endif - } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) { -#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN - funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_BLUE); - funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_RED); -#else - funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_GREEN); - funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_G, GL_BLUE); - funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_ALPHA); - funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_A, GL_RED); -#endif - externalFormat = internalFormat = GL_RGBA; - pixelType = GL_UNSIGNED_BYTE; - } else { - // No support for direct ARGB32 upload. - break; - } - targetFormat = image.format(); - break; - case QImage::Format_BGR30: - case QImage::Format_A2BGR30_Premultiplied: - if (sRgbBinding) { - // Always needs conversion - break; - } else if (isOpenGL12orBetter || isOpenGLES3orBetter) { - pixelType = GL_UNSIGNED_INT_2_10_10_10_REV; - externalFormat = GL_RGBA; - internalFormat = GL_RGB10_A2; - targetFormat = image.format(); - } - break; - case QImage::Format_RGB30: - case QImage::Format_A2RGB30_Premultiplied: - if (sRgbBinding) { - // Always needs conversion - break; - } else if (isOpenGL12orBetter) { - pixelType = GL_UNSIGNED_INT_2_10_10_10_REV; - externalFormat = GL_BGRA; - internalFormat = GL_RGB10_A2; - targetFormat = image.format(); - } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) { - funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_RED); - funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_BLUE); - pixelType = GL_UNSIGNED_INT_2_10_10_10_REV; - externalFormat = GL_RGBA; - internalFormat = GL_RGB10_A2; - targetFormat = image.format(); - } - break; - case QImage::Format_RGB444: - case QImage::Format_RGB555: - case QImage::Format_RGB16: - if (isOpenGL12orBetter || context->isOpenGLES()) { - externalFormat = internalFormat = GL_RGB; - pixelType = GL_UNSIGNED_SHORT_5_6_5; - targetFormat = QImage::Format_RGB16; - } - break; - case QImage::Format_RGB666: - case QImage::Format_RGB888: - externalFormat = internalFormat = GL_RGB; - pixelType = GL_UNSIGNED_BYTE; - targetFormat = QImage::Format_RGB888; - break; - case QImage::Format_BGR888: - if (isOpenGL12orBetter) { - externalFormat = GL_BGR; - internalFormat = GL_RGB; - pixelType = GL_UNSIGNED_BYTE; - targetFormat = QImage::Format_BGR888; - } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) { - funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_RED); - funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_BLUE); - externalFormat = internalFormat = GL_RGB; - pixelType = GL_UNSIGNED_BYTE; - targetFormat = QImage::Format_BGR888; - } - break; - case QImage::Format_RGBX8888: - case QImage::Format_RGBA8888: - case QImage::Format_RGBA8888_Premultiplied: - externalFormat = internalFormat = GL_RGBA; - pixelType = GL_UNSIGNED_BYTE; - targetFormat = image.format(); - break; - case QImage::Format_RGBX64: - case QImage::Format_RGBA64: - case QImage::Format_RGBA64_Premultiplied: - externalFormat = internalFormat = GL_RGBA; - if (isOpenGL12orBetter || (context->isOpenGLES() && context->format().majorVersion() >= 3)) - internalFormat = GL_RGBA16; - pixelType = GL_UNSIGNED_SHORT; - targetFormat = image.format(); - break; - case QImage::Format_Indexed8: - if (sRgbBinding) { - // Always needs conversion - break; - } else if (options & UseRedForAlphaAndLuminanceBindOption) { - externalFormat = internalFormat = GL_RED; - pixelType = GL_UNSIGNED_BYTE; - targetFormat = image.format(); - } - break; - case QImage::Format_Alpha8: - if (sRgbBinding) { - // Always needs conversion - break; - } else if (options & UseRedForAlphaAndLuminanceBindOption) { - externalFormat = internalFormat = GL_RED; - pixelType = GL_UNSIGNED_BYTE; - targetFormat = image.format(); - } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) { - externalFormat = internalFormat = GL_ALPHA; - pixelType = GL_UNSIGNED_BYTE; - targetFormat = image.format(); - } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) { - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ALPHA); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_ZERO); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_ZERO); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ZERO); - externalFormat = internalFormat = GL_RED; - pixelType = GL_UNSIGNED_BYTE; - targetFormat = image.format(); - } - break; - case QImage::Format_Grayscale8: - if (sRgbBinding) { - // Always needs conversion - break; - } else if (options & UseRedForAlphaAndLuminanceBindOption) { - externalFormat = internalFormat = GL_RED; - pixelType = GL_UNSIGNED_BYTE; - targetFormat = image.format(); - } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) { - externalFormat = internalFormat = GL_LUMINANCE; - pixelType = GL_UNSIGNED_BYTE; - targetFormat = image.format(); - } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) { - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE); - externalFormat = internalFormat = GL_RED; - pixelType = GL_UNSIGNED_BYTE; - targetFormat = image.format(); - } - break; - case QImage::Format_Grayscale16: - if (sRgbBinding) { - // Always needs conversion - break; - } else if (options & UseRedForAlphaAndLuminanceBindOption) { - externalFormat = internalFormat = GL_RED; - pixelType = GL_UNSIGNED_SHORT; - targetFormat = image.format(); - } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) { - externalFormat = internalFormat = GL_LUMINANCE; - pixelType = GL_UNSIGNED_SHORT; - targetFormat = image.format(); - } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) { - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE); - externalFormat = internalFormat = GL_RED; - pixelType = GL_UNSIGNED_SHORT; - targetFormat = image.format(); - } - break; - default: - break; - } - - // If no direct upload was detected above, convert to RGBA8888 and upload that - if (targetFormat == QImage::Format_Invalid) { - externalFormat = internalFormat = GL_RGBA; - pixelType = GL_UNSIGNED_BYTE; - if (!image.hasAlphaChannel()) - targetFormat = QImage::Format_RGBX8888; - else - targetFormat = QImage::Format_RGBA8888; - } - - if (options & PremultipliedAlphaBindOption) { - if (targetFormat == QImage::Format_ARGB32) - targetFormat = QImage::Format_ARGB32_Premultiplied; - else if (targetFormat == QImage::Format_RGBA8888) - targetFormat = QImage::Format_RGBA8888_Premultiplied; - else if (targetFormat == QImage::Format_RGBA64) - targetFormat = QImage::Format_RGBA64_Premultiplied; - } else { - if (targetFormat == QImage::Format_ARGB32_Premultiplied) - targetFormat = QImage::Format_ARGB32; - else if (targetFormat == QImage::Format_RGBA8888_Premultiplied) - targetFormat = QImage::Format_RGBA8888; - else if (targetFormat == QImage::Format_RGBA64_Premultiplied) - targetFormat = QImage::Format_RGBA64; - } - - if (sRgbBinding) { - Q_ASSERT(internalFormat == GL_RGBA || internalFormat == GL_RGB); - if (image.hasAlphaChannel()) - internalFormat = GL_SRGB_ALPHA; - else - internalFormat = GL_SRGB; - } - - if (image.format() != targetFormat) - tx = image.convertToFormat(targetFormat); - else - tx = image; - - QSize newSize = tx.size(); - if (!maxSize.isEmpty()) - newSize = newSize.boundedTo(maxSize); - if (options & PowerOfTwoBindOption) { - newSize.setWidth(qNextPowerOfTwo(newSize.width() - 1)); - newSize.setHeight(qNextPowerOfTwo(newSize.height() - 1)); - } - - if (newSize != tx.size()) - tx = tx.scaled(newSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); - - // Handle cases where the QImage is actually a sub image of its image data: - qsizetype naturalBpl = ((qsizetype(tx.width()) * tx.depth() + 31) >> 5) << 2; - if (tx.bytesPerLine() != naturalBpl) - tx = tx.copy(tx.rect()); - - funcs->glTexImage2D(target, 0, internalFormat, tx.width(), tx.height(), 0, externalFormat, pixelType, tx.constBits()); - - qsizetype cost = qint64(tx.width()) * tx.height() * tx.depth() / 8; - - return cost; -} - -QT_END_NAMESPACE diff --git a/src/gui/opengl/qopengltextureuploader_p.h b/src/gui/opengl/qopengltextureuploader_p.h deleted file mode 100644 index 0dcf709d7e..0000000000 --- a/src/gui/opengl/qopengltextureuploader_p.h +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2018 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$ -** -****************************************************************************/ - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#ifndef QOPENGLTEXTUREUPLOADER_P_H -#define QOPENGLTEXTUREUPLOADER_P_H - -#include <QtCore/qsize.h> -#include <QtGui/private/qtguiglobal_p.h> -#include <QtGui/private/qopenglcontext_p.h> - -QT_BEGIN_NAMESPACE - -class QImage; - -class Q_GUI_EXPORT QOpenGLTextureUploader -{ -public: - enum BindOption { - NoBindOption = 0x0000, - PremultipliedAlphaBindOption = 0x0001, - UseRedForAlphaAndLuminanceBindOption = 0x0002, - SRgbBindOption = 0x0004, - PowerOfTwoBindOption = 0x0008 - }; - Q_DECLARE_FLAGS(BindOptions, BindOption) - Q_FLAGS(BindOptions) - - static qsizetype textureImage(GLenum target, const QImage &image, BindOptions options, QSize maxSize = QSize()); - -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLTextureUploader::BindOptions) - -QT_END_NAMESPACE - -#endif - diff --git a/src/gui/opengl/qopengltimerquery.cpp b/src/gui/opengl/qopengltimerquery.cpp deleted file mode 100644 index a4e10b42f7..0000000000 --- a/src/gui/opengl/qopengltimerquery.cpp +++ /dev/null @@ -1,880 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB). -** 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 "qopengltimerquery.h" - -#include "qopenglqueryhelper_p.h" -#include <QtCore/private/qobject_p.h> -#include <QtGui/QOpenGLContext> -#include <QtGui/QOpenGLFunctions> - -QT_BEGIN_NAMESPACE - -// Helper class used as fallback if OpenGL <3.3 is being used with EXT_timer_query -class QExtTimerQueryHelper -{ -public: - QExtTimerQueryHelper(QOpenGLContext *context) - { - Q_ASSERT(context); - GetQueryObjectui64vEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLuint64EXT *)>(context->getProcAddress("glGetQueryObjectui64vEXT")); - GetQueryObjecti64vEXT = reinterpret_cast<void (QOPENGLF_APIENTRYP)(GLuint , GLenum , GLint64EXT *)>(context->getProcAddress("glGetQueryObjecti64vEXT")); - } - - inline void glGetQueryObjectui64vEXT(GLuint id, GLenum pname, GLuint64EXT *params) - { - GetQueryObjectui64vEXT(id, pname, params); - } - - inline void glGetQueryObjecti64vEXT(GLuint id, GLenum pname, GLint64EXT *params) - { - GetQueryObjecti64vEXT(id, pname, params); - } - -private: - void (QOPENGLF_APIENTRYP GetQueryObjectui64vEXT)(GLuint id, GLenum pname, GLuint64EXT *params); - void (QOPENGLF_APIENTRYP GetQueryObjecti64vEXT)(GLuint id, GLenum pname, GLint64EXT *params); -}; - -class QOpenGLTimerQueryPrivate : public QObjectPrivate -{ -public: - QOpenGLTimerQueryPrivate() - : QObjectPrivate(), - context(nullptr), - ext(nullptr), - timeInterval(0), - timer(0) - { - } - - ~QOpenGLTimerQueryPrivate() - { - delete core; - delete ext; - } - - bool create(); - void destroy(); - void begin(); - void end(); - GLuint64 waitForTimeStamp() const; - void recordTimestamp(); - bool isResultAvailable() const; - GLuint64 result() const; - - // There are several cases we must handle: - // OpenGL >=3.3 includes timer queries as a core feature - // ARB_timer_query has same functionality as above. Requires OpenGL 3.2 - // EXT_timer_query offers limited support. Can be used with OpenGL >=1.5 - // - // Note that some implementations (OS X) provide OpenGL 3.2 but do not expose the - // ARB_timer_query extension. In such situations we must also be able to handle - // using the EXT_timer_query extension with any version of OpenGL. - // - // OpenGL 1.5 or above contains the generic query API and OpenGL 3.3 and - // ARB_timer_query provide the 64-bit query API. These are wrapped by - // QOpenGLQueryHelper. All we need to handle in addition is the EXT_timer_query - // case and to take care not to call the Core/ARB functions when we only - // have EXT_timer_query available. - QOpenGLContext *context; - QOpenGLQueryHelper *core; - QExtTimerQueryHelper *ext; - mutable GLuint64 timeInterval; - GLuint timer; -}; - -bool QOpenGLTimerQueryPrivate::create() -{ - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - - if (timer && context == ctx) - return true; - - context = ctx; - if (!context) { - qWarning("A current OpenGL context is required to create timer query objects"); - return false; - } - - if (context->isOpenGLES()) { - qWarning("QOpenGLTimerQuery: Not supported on OpenGL ES"); - return false; - } - - // Resolve the functions provided by OpenGL 1.5 and OpenGL 3.3 or ARB_timer_query - core = new QOpenGLQueryHelper(context); - - // Check to see if we also need to resolve the functions for EXT_timer_query - QSurfaceFormat f = context->format(); - if (f.version() <= qMakePair<int, int>(3, 2) - && !context->hasExtension(QByteArrayLiteral("GL_ARB_timer_query")) - && context->hasExtension(QByteArrayLiteral("GL_EXT_timer_query"))) { - ext = new QExtTimerQueryHelper(context); - } else if (f.version() <= qMakePair<int, int>(3, 2) - && !context->hasExtension(QByteArrayLiteral("GL_ARB_timer_query")) - && !context->hasExtension(QByteArrayLiteral("GL_EXT_timer_query"))) { - qWarning("QOpenGLTimerQuery requires one of:\n" - " OpenGL 3.3 or newer,\n" - " OpenGL 3.2 and the ARB_timer_query extension\n" - " or the EXT_timer query extension"); - return false; - } - - core->glGenQueries(1, &timer); - return (timer != 0); -} - -void QOpenGLTimerQueryPrivate::destroy() -{ - if (!timer) - return; - - core->glDeleteQueries(1, &timer); - timer = 0; - context = nullptr; -} - -// GL_TIME_ELAPSED_EXT is not defined on OS X 10.6 -#if !defined(GL_TIME_ELAPSED_EXT) -#define GL_TIME_ELAPSED_EXT 0x88BF -#endif - -// GL_TIME_ELAPSED is not defined on OS X 10.7 or 10.8 yet -#if !defined(GL_TIME_ELAPSED) -#define GL_TIME_ELAPSED GL_TIME_ELAPSED_EXT -#endif - -void QOpenGLTimerQueryPrivate::begin() -{ - core->glBeginQuery(GL_TIME_ELAPSED, timer); -} - -void QOpenGLTimerQueryPrivate::end() -{ - core->glEndQuery(GL_TIME_ELAPSED); -} - -void QOpenGLTimerQueryPrivate::recordTimestamp() -{ - // Don't call glQueryCounter if we only have EXT_timer_query -#if defined(GL_TIMESTAMP) - if (!ext) - core->glQueryCounter(timer, GL_TIMESTAMP); - else - qWarning("QOpenGLTimerQuery::recordTimestamp() requires OpenGL 3.3 or GL_ARB_timer_query"); -#else - qWarning("QOpenGLTimerQuery::recordTimestamp() requires OpenGL 3.3 or GL_ARB_timer_query"); -#endif -} - -GLuint64 QOpenGLTimerQueryPrivate::waitForTimeStamp() const -{ - GLint64 tmp = 0; -#if defined(GL_TIMESTAMP) - if (!ext) - core->glGetInteger64v(GL_TIMESTAMP, &tmp); - else - qWarning("QOpenGLTimerQuery::waitForTimestamp() requires OpenGL 3.3 or GL_ARB_timer_query"); -#else - qWarning("QOpenGLTimerQuery::waitForTimestamp() requires OpenGL 3.3 or GL_ARB_timer_query"); -#endif - GLuint64 timestamp(tmp); - return timestamp; -} - -bool QOpenGLTimerQueryPrivate::isResultAvailable() const -{ - GLuint available = GL_FALSE; - core->glGetQueryObjectuiv(timer, GL_QUERY_RESULT_AVAILABLE, &available); - return available; -} - -GLuint64 QOpenGLTimerQueryPrivate::result() const -{ - if (!ext) - core->glGetQueryObjectui64v(timer, GL_QUERY_RESULT, &timeInterval); - else - ext->glGetQueryObjectui64vEXT(timer, GL_QUERY_RESULT, &timeInterval); - return timeInterval; -} - -/*! - \class QOpenGLTimerQuery - \brief The QOpenGLTimerQuery class wraps an OpenGL timer query object. - \inmodule QtGui - \since 5.1 - \ingroup painting-3D - - OpenGL timer query objects are OpenGL managed resources to measure the - execution times of sequences of OpenGL commands on the GPU. - - OpenGL offers various levels of support for timer queries, depending on - the version of OpenGL you have and the presence of the ARB_timer_query or - EXT_timer_query extensions. The support can be summarized as: - - \list - \li OpenGL >=3.3 offers full support for all timer query functionality. - \li OpenGL 3.2 with the ARB_timer_query extension offers full support - for all timer query functionality. - \li OpenGL <=3.2 with the EXT_timer_query extension offers limited support - in that the timestamp of the GPU cannot be queried. Places where this - impacts functions provided by Qt classes will be highlighted in the - function documentation. - \li OpenGL ES 2 (and OpenGL ES 3) do not provide any support for OpenGL - timer queries. - \endlist - - OpenGL represents time with a granularity of 1 nanosecond (1e-9 seconds). As a - consequence of this, 32-bit integers would only give a total possible duration - of approximately 4 seconds, which would not be difficult to exceed in poorly - performing or lengthy operations. OpenGL therefore uses 64 bit integer types - to represent times. A GLuint64 variable has enough width to contain a duration - of hundreds of years, which is plenty for real-time rendering needs. - - As with the other Qt OpenGL classes, QOpenGLTimerQuery has a create() - function to create the underlying OpenGL object. This is to allow the developer to - ensure that there is a valid current OpenGL context at the time. - - Once created, timer queries can be issued in one of several ways. The simplest - method is to delimit a block of commands with calls to begin() and end(). This - instructs OpenGL to measure the time taken from completing all commands issued - prior to begin() until the completion of all commands issued prior to end(). - - At the end of a frame we can retrieve the results by calling waitForResult(). - As this function's name implies, it blocks CPU execution until OpenGL notifies - that the timer query result is available. To avoid blocking, you can check - if the query result is available by calling isResultAvailable(). Note that - modern GPUs are deeply pipelined and query results may not become available for - between 1-5 frames after they were issued. - - Note that OpenGL does not permit nesting or interleaving of multiple timer queries - using begin() and end(). Using multiple timer queries and recordTimestamp() avoids - this limitation. When using recordTimestamp() the result can be obtained at - some later time using isResultAvailable() and waitForResult(). Qt provides the - convenience class QOpenGLTimeMonitor that helps with using multiple query objects. - - \sa QOpenGLTimeMonitor -*/ - -/*! - Creates a QOpenGLTimerQuery instance with the given \a parent. You must call create() - with a valid OpenGL context before using. -*/ -QOpenGLTimerQuery::QOpenGLTimerQuery(QObject *parent) - : QObject(*new QOpenGLTimerQueryPrivate, parent) -{ -} - -/*! - Destroys the QOpenGLTimerQuery and the underlying OpenGL resource. -*/ -QOpenGLTimerQuery::~QOpenGLTimerQuery() -{ - QOpenGLContext* ctx = QOpenGLContext::currentContext(); - - Q_D(QOpenGLTimerQuery); - QOpenGLContext *oldContext = nullptr; - if (d->context != ctx) { - oldContext = ctx; - if (d->context->makeCurrent(oldContext->surface())) { - ctx = d->context; - } else { - qWarning("QOpenGLTimerQuery::~QOpenGLTimerQuery() failed to make query objects's context current"); - ctx = nullptr; - } - } - - if (ctx) - destroy(); - - if (oldContext) { - if (!oldContext->makeCurrent(oldContext->surface())) - qWarning("QOpenGLTimerQuery::~QOpenGLTimerQuery() failed to restore current context"); - } -} - -/*! - Creates the underlying OpenGL timer query object. There must be a valid OpenGL context - that supports query objects current for this function to succeed. - - Returns \c true if the OpenGL timer query object was successfully created. -*/ -bool QOpenGLTimerQuery::create() -{ - Q_D(QOpenGLTimerQuery); - return d->create(); -} - -/*! - Destroys the underlying OpenGL timer query object. The context that was current when - create() was called must be current when calling this function. -*/ -void QOpenGLTimerQuery::destroy() -{ - Q_D(QOpenGLTimerQuery); - d->destroy(); -} - -/*! - Returns \c true if the underlying OpenGL query object has been created. If this - returns \c true and the associated OpenGL context is current, then you are able to issue - queries with this object. -*/ -bool QOpenGLTimerQuery::isCreated() const -{ - Q_D(const QOpenGLTimerQuery); - return (d->timer != 0); -} - -/*! - Returns the id of the underlying OpenGL query object. -*/ -GLuint QOpenGLTimerQuery::objectId() const -{ - Q_D(const QOpenGLTimerQuery); - return d->timer; -} - -/*! - Marks the start point in the OpenGL command queue for a sequence of commands to - be timed by this query object. - - This is useful for simple use-cases. Usually it is better to use recordTimestamp(). - - \sa end(), isResultAvailable(), waitForResult(), recordTimestamp() -*/ -void QOpenGLTimerQuery::begin() -{ - Q_D(QOpenGLTimerQuery); - d->begin(); -} - -/*! - Marks the end point in the OpenGL command queue for a sequence of commands to - be timed by this query object. - - This is useful for simple use-cases. Usually it is better to use recordTimestamp(). - - \sa begin(), isResultAvailable(), waitForResult(), recordTimestamp() -*/ -void QOpenGLTimerQuery::end() -{ - Q_D(QOpenGLTimerQuery); - d->end(); -} - -/*! - Places a marker in the OpenGL command queue for the GPU to record the timestamp - when this marker is reached by the GPU. This function is non-blocking and the - result will become available at some later time. - - The availability of the result can be checked with isResultAvailable(). The result - can be fetched with waitForResult() which will block if the result is not yet - available. - - \sa waitForResult(), isResultAvailable(), begin(), end() -*/ -void QOpenGLTimerQuery::recordTimestamp() -{ - Q_D(QOpenGLTimerQuery); - return d->recordTimestamp(); -} - -/*! - Returns the current timestamp of the GPU when all previously issued OpenGL - commands have been received but not necessarily executed by the GPU. - - This function blocks until the result is returned. - - \sa recordTimestamp() -*/ -GLuint64 QOpenGLTimerQuery::waitForTimestamp() const -{ - Q_D(const QOpenGLTimerQuery); - return d->waitForTimeStamp(); -} - -/*! - Returns \c true if the OpenGL timer query result is available. - - This function is non-blocking and ideally should be used to check for the - availability of the query result before calling waitForResult(). - - \sa waitForResult() -*/ -bool QOpenGLTimerQuery::isResultAvailable() const -{ - Q_D(const QOpenGLTimerQuery); - return d->isResultAvailable(); -} - -/*! - Returns the result of the OpenGL timer query. - - This function will block until the result is made available by OpenGL. It is - recommended to call isResultAvailable() to ensure that the result is available - to avoid unnecessary blocking and stalling. - - \sa isResultAvailable() -*/ -GLuint64 QOpenGLTimerQuery::waitForResult() const -{ - Q_D(const QOpenGLTimerQuery); - return d->result(); -} - - -class QOpenGLTimeMonitorPrivate : public QObjectPrivate -{ -public: - QOpenGLTimeMonitorPrivate() - : QObjectPrivate(), - timers(), - timeSamples(), - context(nullptr), - core(nullptr), - ext(nullptr), - requestedSampleCount(2), - currentSample(-1), - timerQueryActive(false) - { - } - - ~QOpenGLTimeMonitorPrivate() - { - delete core; - delete ext; - } - - bool create(); - void destroy(); - void recordSample(); - bool isResultAvailable() const; - QVector<GLuint64> samples() const; - QVector<GLuint64> intervals() const; - void reset(); - - QVector<GLuint> timers; - mutable QVector<GLuint64> timeSamples; - - QOpenGLContext *context; - QOpenGLQueryHelper *core; - QExtTimerQueryHelper *ext; - - int requestedSampleCount; - int currentSample; - mutable bool timerQueryActive; -}; - -bool QOpenGLTimeMonitorPrivate::create() -{ - if (!timers.isEmpty() && timers.at(0) != 0 && timers.size() == requestedSampleCount) - return true; - - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - if (context && context != ctx) { - qWarning("QTimeMonitor: Attempting to use different OpenGL context to recreate timers.\n" - "Please call destroy() first or use the same context to previously create"); - return false; - } - - context = ctx; - if (!context) { - qWarning("A current OpenGL context is required to create timer query objects"); - return false; - } - - // Resize the vectors that hold the timers and the recorded samples - timers.resize(requestedSampleCount); - timeSamples.resize(requestedSampleCount); - - // Resolve the functions provided by OpenGL 1.5 and OpenGL 3.3 or ARB_timer_query - core = new QOpenGLQueryHelper(context); - - // Check to see if we also need to resolve the functions for EXT_timer_query - QSurfaceFormat f = context->format(); - if (f.version() <= qMakePair<int, int>(3, 2) - && !context->hasExtension(QByteArrayLiteral("GL_ARB_timer_query")) - && context->hasExtension(QByteArrayLiteral("GL_EXT_timer_query"))) { - ext = new QExtTimerQueryHelper(context); - } else if (f.version() <= qMakePair<int, int>(3, 2) - && !context->hasExtension(QByteArrayLiteral("GL_ARB_timer_query")) - && !context->hasExtension(QByteArrayLiteral("GL_EXT_timer_query"))) { - qWarning("QOpenGLTimeMonitor requires one of:\n" - " OpenGL 3.3 or newer,\n" - " OpenGL 3.2 and the ARB_timer_query extension\n" - " or the EXT_timer query extension"); - return false; - } - - core->glGenQueries(requestedSampleCount, timers.data()); - return (timers.at(0) != 0); -} - -void QOpenGLTimeMonitorPrivate::destroy() -{ - if (timers.isEmpty() || timers.at(0) == 0) - return; - - core->glDeleteQueries(timers.size(), timers.data()); - timers.clear(); - delete core; - core = nullptr; - delete ext; - ext = nullptr; - context = nullptr; -} - -void QOpenGLTimeMonitorPrivate::recordSample() -{ - // Use glQueryCounter() and GL_TIMESTAMP where available. - // Otherwise, simulate it with glBeginQuery()/glEndQuery() - if (!ext) { -#if defined(GL_TIMESTAMP) - core->glQueryCounter(timers.at(++currentSample), GL_TIMESTAMP); -#endif - } else { - if (currentSample == -1) { - core->glBeginQuery(GL_TIME_ELAPSED_EXT, timers.at(++currentSample)); - timerQueryActive = true; - } else if (currentSample < timers.size() - 1) { - core->glEndQuery(GL_TIME_ELAPSED_EXT); - core->glBeginQuery(GL_TIME_ELAPSED_EXT, timers.at(++currentSample)); - } else { - if (timerQueryActive) { - core->glEndQuery(GL_TIME_ELAPSED_EXT); - timerQueryActive = false; - } - } - } -} - -bool QOpenGLTimeMonitorPrivate::isResultAvailable() const -{ - // The OpenGL spec says that if a query result is ready then the results of all queries - // of the same type issued before it must also be ready. Therefore we only need to check - // the availability of the result for the last issued query - GLuint available = GL_FALSE; - core->glGetQueryObjectuiv(timers.at(currentSample), GL_QUERY_RESULT_AVAILABLE, &available); - return available; -} - -QVector<GLuint64> QOpenGLTimeMonitorPrivate::samples() const -{ - // For the Core and ARB options just ask for the timestamp for each timer query. - // For the EXT implementation we cannot obtain timestamps so we defer any result - // collection to the intervals() function - if (!ext) { - for (int i = 0; i <= currentSample; ++i) - core->glGetQueryObjectui64v(timers.at(i), GL_QUERY_RESULT, &timeSamples[i]); - } else { - qWarning("QOpenGLTimeMonitor::samples() requires OpenGL >=3.3\n" - "or OpenGL 3.2 and GL_ARB_timer_query"); - } - return timeSamples; -} - -QVector<GLuint64> QOpenGLTimeMonitorPrivate::intervals() const -{ - QVector<GLuint64> intervals(timers.size() - 1); - if (!ext) { - // Obtain the timestamp samples and calculate the interval durations - const QVector<GLuint64> timeStamps = samples(); - for (int i = 0; i < intervals.size(); ++i) - intervals[i] = timeStamps[i+1] - timeStamps[i]; - } else { - // Stop the last timer if needed - if (timerQueryActive) { - core->glEndQuery(GL_TIME_ELAPSED_EXT); - timerQueryActive = false; - } - - // Obtain the results from all timers apart from the redundant last one. In this - // case the results actually are the intervals not timestamps - for (int i = 0; i < currentSample; ++i) - ext->glGetQueryObjectui64vEXT(timers.at(i), GL_QUERY_RESULT, &intervals[i]); - } - - return intervals; -} - -void QOpenGLTimeMonitorPrivate::reset() -{ - currentSample = -1; - timeSamples.fill(0); -} - - -/*! - \class QOpenGLTimeMonitor - \brief The QOpenGLTimeMonitor class wraps a sequence of OpenGL timer query objects. - \inmodule QtGui - \since 5.1 - \ingroup painting-3D - - The QOpenGLTimeMonitor class is a convenience wrapper around a collection of OpenGL - timer query objects used to measure intervals of time on the GPU to the level of - granularity required by your rendering application. - - The OpenGL timer queries objects are queried in sequence to record the GPU - timestamps at positions of interest in your rendering code. Once the results for - all issues timer queries become available, the results can be fetched and - QOpenGLTimerMonitor will calculate the recorded time intervals for you. - - The typical use case of this class is to either profile your application's rendering - algorithms or to adjust those algorithms in real-time for dynamic performance/quality - balancing. - - Prior to using QOpenGLTimeMonitor in your rendering function you should set the - required number of sample points that you wish to record by calling setSamples(). Note - that measuring N sample points will produce N-1 time intervals. Once you have set the - number of sample points, call the create() function with a valid current OpenGL context - to create the necessary query timer objects. These steps are usually performed just - once in an initialization function. - - Use the recordSample() function to delimit blocks of code containing OpenGL commands - that you wish to time. You can check availability of the resulting time - samples and time intervals with isResultAvailable(). The calculated time intervals and - the raw timestamp samples can be retrieved with the blocking waitForIntervals() and - waitForSamples() functions respectively. - - After retrieving the results and before starting a new round of taking samples - (for example, in the next frame) be sure to call the reset() function which will clear - the cached results and reset the timer index back to the first timer object. - - \sa QOpenGLTimerQuery -*/ - -/*! - Creates a QOpenGLTimeMonitor instance with the given \a parent. You must call create() - with a valid OpenGL context before using. - - \sa setSampleCount(), create() -*/ -QOpenGLTimeMonitor::QOpenGLTimeMonitor(QObject *parent) - : QObject(*new QOpenGLTimeMonitorPrivate, parent) -{ -} - -/*! - Destroys the QOpenGLTimeMonitor and any underlying OpenGL resources. -*/ -QOpenGLTimeMonitor::~QOpenGLTimeMonitor() -{ - QOpenGLContext* ctx = QOpenGLContext::currentContext(); - - Q_D(QOpenGLTimeMonitor); - QOpenGLContext *oldContext = nullptr; - if (d->context != ctx) { - oldContext = ctx; - if (d->context->makeCurrent(oldContext->surface())) { - ctx = d->context; - } else { - qWarning("QOpenGLTimeMonitor::~QOpenGLTimeMonitor() failed to make time monitor's context current"); - ctx = nullptr; - } - } - - if (ctx) - destroy(); - - if (oldContext) { - if (!oldContext->makeCurrent(oldContext->surface())) - qWarning("QOpenGLTimeMonitor::~QOpenGLTimeMonitor() failed to restore current context"); - } -} - -/*! - Sets the number of sample points to \a sampleCount. After setting the number - of samples with this function, you must call create() to instantiate the underlying - OpenGL timer query objects. - - The new \a sampleCount must be at least 2. - - \sa sampleCount(), create(), recordSample() -*/ -void QOpenGLTimeMonitor::setSampleCount(int sampleCount) -{ - // We need at least 2 samples to get an interval - if (sampleCount < 2) - return; - Q_D(QOpenGLTimeMonitor); - d->requestedSampleCount = sampleCount; -} - -/*! - Returns the number of sample points that have been requested with - setSampleCount(). If create was successfully called following setSampleCount(), - then the value returned will be the actual number of sample points - that can be used. - - The default value for sample count is 2, leading to the measurement of a - single interval. - - \sa setSampleCount() -*/ -int QOpenGLTimeMonitor::sampleCount() const -{ - Q_D(const QOpenGLTimeMonitor); - return d->requestedSampleCount; -} - -/*! - Instantiate sampleCount() OpenGL timer query objects that will be used - to track the amount of time taken to execute OpenGL commands between - successive calls to recordSample(). - - Returns \c true if the OpenGL timer query objects could be created. - - \sa destroy(), setSampleCount(), recordSample() -*/ -bool QOpenGLTimeMonitor::create() -{ - Q_D(QOpenGLTimeMonitor); - return d->create(); -} - -/*! - Destroys any OpenGL timer query objects used within this instance. - - \sa create() -*/ -void QOpenGLTimeMonitor::destroy() -{ - Q_D(QOpenGLTimeMonitor); - d->destroy(); -} - -/*! - Returns \c true if the underlying OpenGL query objects have been created. If this - returns \c true and the associated OpenGL context is current, then you are able to record - time samples with this object. -*/ -bool QOpenGLTimeMonitor::isCreated() const -{ - Q_D(const QOpenGLTimeMonitor); - return (!d->timers.isEmpty() && d->timers.at(0) != 0); -} - -/*! - Returns a QVector containing the object Ids of the OpenGL timer query objects. -*/ -QVector<GLuint> QOpenGLTimeMonitor::objectIds() const -{ - Q_D(const QOpenGLTimeMonitor); - return d->timers; -} - -/*! - Issues an OpenGL timer query at this point in the OpenGL command queue. Calling this - function in a sequence in your application's rendering function, will build up - details of the GPU time taken to execute the OpenGL commands between successive - calls to this function. - - \sa setSampleCount(), isResultAvailable(), waitForSamples(), waitForIntervals() -*/ -int QOpenGLTimeMonitor::recordSample() -{ - Q_D(QOpenGLTimeMonitor); - d->recordSample(); - return d->currentSample; -} - -/*! - Returns \c true if the OpenGL timer query results are available. - - \sa waitForSamples(), waitForIntervals() -*/ -bool QOpenGLTimeMonitor::isResultAvailable() const -{ - Q_D(const QOpenGLTimeMonitor); - return d->isResultAvailable(); -} - -/*! - Returns a QVector containing the GPU timestamps taken with recordSample(). - - This function will block until OpenGL indicates the results are available. It - is recommended to check the availability of the result prior to calling this - function with isResultAvailable(). - - \note This function only works on systems that have OpenGL >=3.3 or the - ARB_timer_query extension. See QOpenGLTimerQuery for more details. - - \sa waitForIntervals(), isResultAvailable() -*/ -QVector<GLuint64> QOpenGLTimeMonitor::waitForSamples() const -{ - Q_D(const QOpenGLTimeMonitor); - return d->samples(); -} - -/*! - Returns a QVector containing the time intervals delimited by the calls to - recordSample(). The resulting vector will contain one fewer element as - this represents the intervening intervals rather than the actual timestamp - samples. - - This function will block until OpenGL indicates the results are available. It - is recommended to check the availability of the result prior to calling this - function with isResultAvailable(). - - \sa waitForSamples(), isResultAvailable() -*/ -QVector<GLuint64> QOpenGLTimeMonitor::waitForIntervals() const -{ - Q_D(const QOpenGLTimeMonitor); - return d->intervals(); -} - -/*! - Resets the time monitor ready for use in another frame of rendering. Call - this once you have obtained the previous results and before calling - recordSample() for the first time on the next frame. - - \sa recordSample() -*/ -void QOpenGLTimeMonitor::reset() -{ - Q_D(QOpenGLTimeMonitor); - d->reset(); -} - -QT_END_NAMESPACE diff --git a/src/gui/opengl/qopengltimerquery.h b/src/gui/opengl/qopengltimerquery.h deleted file mode 100644 index 27da74a3fb..0000000000 --- a/src/gui/opengl/qopengltimerquery.h +++ /dev/null @@ -1,116 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB). -** 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 QOPENGLTIMERQUERY_H -#define QOPENGLTIMERQUERY_H - -#include <QtGui/qtguiglobal.h> - -#if !defined(QT_NO_OPENGL) && !defined(QT_OPENGL_ES_2) - -#include <QtCore/QObject> -#include <QtGui/qopengl.h> - -QT_BEGIN_NAMESPACE - -class QOpenGLTimerQueryPrivate; - -class Q_GUI_EXPORT QOpenGLTimerQuery : public QObject -{ - Q_OBJECT - -public: - explicit QOpenGLTimerQuery(QObject *parent = nullptr); - ~QOpenGLTimerQuery(); - - bool create(); - void destroy(); - bool isCreated() const; - GLuint objectId() const; - - void begin(); - void end(); - GLuint64 waitForTimestamp() const; - void recordTimestamp(); - bool isResultAvailable() const; - GLuint64 waitForResult() const; - -private: - Q_DECLARE_PRIVATE(QOpenGLTimerQuery) - Q_DISABLE_COPY(QOpenGLTimerQuery) -}; - - -class QOpenGLTimeMonitorPrivate; - -class Q_GUI_EXPORT QOpenGLTimeMonitor : public QObject -{ - Q_OBJECT - -public: - explicit QOpenGLTimeMonitor(QObject *parent = nullptr); - ~QOpenGLTimeMonitor(); - - void setSampleCount(int sampleCount); - int sampleCount() const; - - bool create(); - void destroy(); - bool isCreated() const; - QVector<GLuint> objectIds() const; - - int recordSample(); - - bool isResultAvailable() const; - - QVector<GLuint64> waitForSamples() const; - QVector<GLuint64> waitForIntervals() const; - - void reset(); - -private: - Q_DECLARE_PRIVATE(QOpenGLTimeMonitor) - Q_DISABLE_COPY(QOpenGLTimeMonitor) -}; - -QT_END_NAMESPACE - -#endif // QT_NO_OPENGL - -#endif // QOPENGLTIMERQUERY_H diff --git a/src/gui/opengl/qopenglversionprofile.cpp b/src/gui/opengl/qopenglversionprofile.cpp new file mode 100644 index 0000000000..4e728f9405 --- /dev/null +++ b/src/gui/opengl/qopenglversionprofile.cpp @@ -0,0 +1,214 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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 "qopenglversionprofile.h" + +#include <QtCore/QDebug> + +QT_BEGIN_NAMESPACE + +class QOpenGLVersionProfilePrivate +{ +public: + QOpenGLVersionProfilePrivate() + : majorVersion(0), + minorVersion(0), + profile(QSurfaceFormat::NoProfile) + {} + + int majorVersion; + int minorVersion; + QSurfaceFormat::OpenGLContextProfile profile; +}; + +/*! + \class QOpenGLVersionProfile + \inmodule QtGui + \since 5.1 + \brief The QOpenGLVersionProfile class represents the version and if applicable + the profile of an OpenGL context. + + An object of this class can be passed to QOpenGLContext::versionFunctions() to + request a functions object for a specific version and profile of OpenGL. + + It also contains some helper functions to check if a version supports profiles + or is a legacy version. +*/ + +/*! + Creates a default invalid QOpenGLVersionProfile object. +*/ +QOpenGLVersionProfile::QOpenGLVersionProfile() + : d(new QOpenGLVersionProfilePrivate) +{ +} + +/*! + Creates a QOpenGLVersionProfile object initialised with the version and profile + from \a format. +*/ +QOpenGLVersionProfile::QOpenGLVersionProfile(const QSurfaceFormat &format) + : d(new QOpenGLVersionProfilePrivate) +{ + d->majorVersion = format.majorVersion(); + d->minorVersion = format.minorVersion(); + d->profile = format.profile(); +} + +/*! + Constructs a copy of \a other. +*/ +QOpenGLVersionProfile::QOpenGLVersionProfile(const QOpenGLVersionProfile &other) + : d(new QOpenGLVersionProfilePrivate) +{ + *d = *(other.d); +} + +/*! + Destroys the QOpenGLVersionProfile object. +*/ +QOpenGLVersionProfile::~QOpenGLVersionProfile() +{ + delete d; +} + +/*! + Assigns the version and profile of \a rhs to this QOpenGLVersionProfile object. +*/ +QOpenGLVersionProfile &QOpenGLVersionProfile::operator=(const QOpenGLVersionProfile &rhs) +{ + if (this == &rhs) + return *this; + *d = *(rhs.d); + return *this; +} + +/*! + Returns a QPair<int,int> where the components represent the major and minor OpenGL + version numbers respectively. + + \sa setVersion() +*/ +QPair<int, int> QOpenGLVersionProfile::version() const +{ + return qMakePair( d->majorVersion, d->minorVersion); +} + +/*! + Sets the major and minor version numbers to \a majorVersion and \a minorVersion respectively. + + \sa version() +*/ +void QOpenGLVersionProfile::setVersion(int majorVersion, int minorVersion) +{ + d->majorVersion = majorVersion; + d->minorVersion = minorVersion; +} + +/*! + Returns the OpenGL profile. Only makes sense if profiles are supported by this version. + + \sa setProfile() +*/ +QSurfaceFormat::OpenGLContextProfile QOpenGLVersionProfile::profile() const +{ + return d->profile; +} + +/*! + Sets the OpenGL profile \a profile. Only makes sense if profiles are supported by + this version. + + \sa profile() +*/ +void QOpenGLVersionProfile::setProfile(QSurfaceFormat::OpenGLContextProfile profile) +{ + d->profile = profile; +} + +/*! + Returns \c true if profiles are supported by the OpenGL version returned by version(). Only + OpenGL versions >= 3.2 support profiles. + + \sa profile(), version() +*/ +bool QOpenGLVersionProfile::hasProfiles() const +{ + return ( d->majorVersion > 3 + || (d->majorVersion == 3 && d->minorVersion > 1)); +} + +/*! + Returns \c true is the OpenGL version returned by version() contains deprecated functions + and does not support profiles i.e. if the OpenGL version is <= 3.1. +*/ +bool QOpenGLVersionProfile::isLegacyVersion() const +{ + return (d->majorVersion < 3 || (d->majorVersion == 3 && d->minorVersion == 0)); +} + +/*! + Returns \c true if the version number is valid. Note that for a default constructed + QOpenGLVersionProfile object this function will return \c false. + + \sa setVersion(), version() +*/ +bool QOpenGLVersionProfile::isValid() const +{ + return d->majorVersion > 0 && d->minorVersion >= 0; +} + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug debug, const QOpenGLVersionProfile &vp) +{ + QDebugStateSaver saver(debug); + debug.nospace(); + debug << "QOpenGLVersionProfile("; + if (vp.isValid()) { + debug << vp.version().first << '.' << vp.version().second + << ", profile=" << vp.profile(); + } else { + debug << "invalid"; + } + debug << ')'; + return debug; +} + +#endif // QT_NO_DEBUG_STREAM +QT_END_NAMESPACE diff --git a/src/gui/opengl/qopenglpaintdevice.h b/src/gui/opengl/qopenglversionprofile.h index 54118f2926..f3b67e4eb5 100644 --- a/src/gui/opengl/qopenglpaintdevice.h +++ b/src/gui/opengl/qopenglversionprofile.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2020 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtGui module of the Qt Toolkit. @@ -37,59 +37,74 @@ ** ****************************************************************************/ -#ifndef QOPENGLPAINTDEVICE_H -#define QOPENGLPAINTDEVICE_H +#ifndef QOPENGLVERSIONPROFILE_H +#define QOPENGLVERSIONPROFILE_H #include <QtGui/qtguiglobal.h> -#ifndef QT_NO_OPENGL +#include <QtGui/QSurfaceFormat> + +#include <QtCore/QPair> +#if QT_DEPRECATED_SINCE(5, 6) +#include <QtCore/qhash.h> +#endif +#include <QtCore/qhashfunctions.h> -#include <QtGui/qpaintdevice.h> -#include <QtGui/qopengl.h> -#include <QtGui/qopenglcontext.h> +#ifndef QT_NO_OPENGL QT_BEGIN_NAMESPACE -class QOpenGLPaintDevicePrivate; +class QOpenGLVersionProfilePrivate; +class QDebug; -class Q_GUI_EXPORT QOpenGLPaintDevice : public QPaintDevice +class Q_GUI_EXPORT QOpenGLVersionProfile { - Q_DECLARE_PRIVATE(QOpenGLPaintDevice) public: - QOpenGLPaintDevice(); - explicit QOpenGLPaintDevice(const QSize &size); - QOpenGLPaintDevice(int width, int height); - ~QOpenGLPaintDevice(); + QOpenGLVersionProfile(); + explicit QOpenGLVersionProfile(const QSurfaceFormat &format); + QOpenGLVersionProfile(const QOpenGLVersionProfile &other); + ~QOpenGLVersionProfile(); - int devType() const override { return QInternal::OpenGL; } - QPaintEngine *paintEngine() const override; + QOpenGLVersionProfile &operator=(const QOpenGLVersionProfile &rhs); - QOpenGLContext *context() const; - QSize size() const; - void setSize(const QSize &size); - void setDevicePixelRatio(qreal devicePixelRatio); + QPair<int, int> version() const; + void setVersion(int majorVersion, int minorVersion); - qreal dotsPerMeterX() const; - qreal dotsPerMeterY() const; + QSurfaceFormat::OpenGLContextProfile profile() const; + void setProfile(QSurfaceFormat::OpenGLContextProfile profile); - void setDotsPerMeterX(qreal); - void setDotsPerMeterY(qreal); + bool hasProfiles() const; + bool isLegacyVersion() const; + bool isValid() const; - void setPaintFlipped(bool flipped); - bool paintFlipped() const; +private: + QOpenGLVersionProfilePrivate* d; +}; - virtual void ensureActiveTarget(); +inline uint qHash(const QOpenGLVersionProfile &v, uint seed = 0) +{ + return qHash(static_cast<int>(v.profile() * 1000) + + v.version().first * 100 + v.version().second * 10, seed); +} -protected: - QOpenGLPaintDevice(QOpenGLPaintDevicePrivate &dd); - int metric(QPaintDevice::PaintDeviceMetric metric) const override; +inline bool operator==(const QOpenGLVersionProfile &lhs, const QOpenGLVersionProfile &rhs) +{ + if (lhs.profile() != rhs.profile()) + return false; + return lhs.version() == rhs.version(); +} - Q_DISABLE_COPY(QOpenGLPaintDevice) - QScopedPointer<QOpenGLPaintDevicePrivate> d_ptr; -}; +inline bool operator!=(const QOpenGLVersionProfile &lhs, const QOpenGLVersionProfile &rhs) +{ + return !operator==(lhs, rhs); +} + +#ifndef QT_NO_DEBUG_STREAM +Q_GUI_EXPORT QDebug operator<<(QDebug debug, const QOpenGLVersionProfile &vp); +#endif // !QT_NO_DEBUG_STREAM QT_END_NAMESPACE #endif // QT_NO_OPENGL -#endif // QOPENGLPAINTDEVICE_H +#endif // QOPENGLVERSIONPROFILE_H diff --git a/src/gui/opengl/qopenglvertexarrayobject.cpp b/src/gui/opengl/qopenglvertexarrayobject.cpp deleted file mode 100644 index f15fe06ee8..0000000000 --- a/src/gui/opengl/qopenglvertexarrayobject.cpp +++ /dev/null @@ -1,531 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Sean Harmer <sean.harmer@kdab.com> -** 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 "qopenglvertexarrayobject.h" - -#include <QtCore/private/qobject_p.h> -#include <QtCore/qthread.h> -#include <QtGui/qopenglcontext.h> -#include <QtGui/qoffscreensurface.h> -#include <QtGui/qguiapplication.h> - -#include <QtGui/qopenglfunctions_3_0.h> -#include <QtGui/qopenglfunctions_3_2_core.h> - -#include <private/qopenglextensions_p.h> -#include <private/qopenglvertexarrayobject_p.h> - -QT_BEGIN_NAMESPACE - -class QOpenGLFunctions_3_0; -class QOpenGLFunctions_3_2_Core; - -void qtInitializeVertexArrayObjectHelper(QOpenGLVertexArrayObjectHelper *helper, QOpenGLContext *context) -{ - Q_ASSERT(helper); - Q_ASSERT(context); - - bool tryARB = true; - - if (context->isOpenGLES()) { - if (context->format().majorVersion() >= 3) { - QOpenGLExtraFunctionsPrivate *extra = static_cast<QOpenGLExtensions *>(context->extraFunctions())->d(); - helper->GenVertexArrays = extra->f.GenVertexArrays; - helper->DeleteVertexArrays = extra->f.DeleteVertexArrays; - helper->BindVertexArray = extra->f.BindVertexArray; - helper->IsVertexArray = extra->f.IsVertexArray; - tryARB = false; - } else if (context->hasExtension(QByteArrayLiteral("GL_OES_vertex_array_object"))) { - helper->GenVertexArrays = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_GenVertexArrays_t>(context->getProcAddress("glGenVertexArraysOES")); - helper->DeleteVertexArrays = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_DeleteVertexArrays_t>(context->getProcAddress("glDeleteVertexArraysOES")); - helper->BindVertexArray = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_BindVertexArray_t>(context->getProcAddress("glBindVertexArrayOES")); - helper->IsVertexArray = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_IsVertexArray_t>(context->getProcAddress("glIsVertexArrayOES")); - tryARB = false; - } - } else if (context->hasExtension(QByteArrayLiteral("GL_APPLE_vertex_array_object")) && - !context->hasExtension(QByteArrayLiteral("GL_ARB_vertex_array_object"))) { - helper->GenVertexArrays = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_GenVertexArrays_t>(context->getProcAddress("glGenVertexArraysAPPLE")); - helper->DeleteVertexArrays = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_DeleteVertexArrays_t>(context->getProcAddress("glDeleteVertexArraysAPPLE")); - helper->BindVertexArray = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_BindVertexArray_t>(context->getProcAddress("glBindVertexArrayAPPLE")); - helper->IsVertexArray = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_IsVertexArray_t>(context->getProcAddress("glIsVertexArrayAPPLE")); - tryARB = false; - } - - if (tryARB && context->hasExtension(QByteArrayLiteral("GL_ARB_vertex_array_object"))) { - helper->GenVertexArrays = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_GenVertexArrays_t>(context->getProcAddress("glGenVertexArrays")); - helper->DeleteVertexArrays = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_DeleteVertexArrays_t>(context->getProcAddress("glDeleteVertexArrays")); - helper->BindVertexArray = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_BindVertexArray_t>(context->getProcAddress("glBindVertexArray")); - helper->IsVertexArray = reinterpret_cast<QOpenGLVertexArrayObjectHelper::qt_IsVertexArray_t>(context->getProcAddress("glIsVertexArray")); - } -} - -class QOpenGLVertexArrayObjectPrivate : public QObjectPrivate -{ -public: - QOpenGLVertexArrayObjectPrivate() - : vao(0) - , vaoFuncsType(NotSupported) - , context(nullptr) - { - } - - ~QOpenGLVertexArrayObjectPrivate() - { - if (vaoFuncsType == ARB || vaoFuncsType == APPLE || vaoFuncsType == OES) - delete vaoFuncs.helper; - } - - bool create(); - void destroy(); - void bind(); - void release(); - void _q_contextAboutToBeDestroyed(); - - Q_DECLARE_PUBLIC(QOpenGLVertexArrayObject) - - GLuint vao; - - union { - QOpenGLFunctions_3_0 *core_3_0; - QOpenGLFunctions_3_2_Core *core_3_2; - QOpenGLVertexArrayObjectHelper *helper; - } vaoFuncs; - enum { - NotSupported, - Core_3_0, - Core_3_2, - ARB, - APPLE, - OES - } vaoFuncsType; - - QOpenGLContext *context; -}; - -bool QOpenGLVertexArrayObjectPrivate::create() -{ - if (vao) { - qWarning("QOpenGLVertexArrayObject::create() VAO is already created"); - return false; - } - - Q_Q(QOpenGLVertexArrayObject); - - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - if (!ctx) { - qWarning("QOpenGLVertexArrayObject::create() requires a valid current OpenGL context"); - return false; - } - - //Fail early, if context is the same as ctx, it means we have tried to initialize for this context and failed - if (ctx == context) - return false; - - context = ctx; - QObject::connect(context, SIGNAL(aboutToBeDestroyed()), q, SLOT(_q_contextAboutToBeDestroyed())); - - if (ctx->isOpenGLES()) { - if (ctx->format().majorVersion() >= 3 || ctx->hasExtension(QByteArrayLiteral("GL_OES_vertex_array_object"))) { - vaoFuncs.helper = new QOpenGLVertexArrayObjectHelper(ctx); - vaoFuncsType = OES; - vaoFuncs.helper->glGenVertexArrays(1, &vao); - } - } else { - vaoFuncs.core_3_0 = nullptr; - vaoFuncsType = NotSupported; - QSurfaceFormat format = ctx->format(); -#ifndef QT_OPENGL_ES_2 - if (format.version() >= qMakePair<int, int>(3,2)) { - vaoFuncs.core_3_2 = ctx->versionFunctions<QOpenGLFunctions_3_2_Core>(); - vaoFuncsType = Core_3_2; - vaoFuncs.core_3_2->glGenVertexArrays(1, &vao); - } else if (format.majorVersion() >= 3) { - vaoFuncs.core_3_0 = ctx->versionFunctions<QOpenGLFunctions_3_0>(); - vaoFuncsType = Core_3_0; - vaoFuncs.core_3_0->glGenVertexArrays(1, &vao); - } else -#endif - if (ctx->hasExtension(QByteArrayLiteral("GL_ARB_vertex_array_object"))) { - vaoFuncs.helper = new QOpenGLVertexArrayObjectHelper(ctx); - vaoFuncsType = ARB; - vaoFuncs.helper->glGenVertexArrays(1, &vao); - } else if (ctx->hasExtension(QByteArrayLiteral("GL_APPLE_vertex_array_object"))) { - vaoFuncs.helper = new QOpenGLVertexArrayObjectHelper(ctx); - vaoFuncsType = APPLE; - vaoFuncs.helper->glGenVertexArrays(1, &vao); - } - } - - return (vao != 0); -} - -void QOpenGLVertexArrayObjectPrivate::destroy() -{ - Q_Q(QOpenGLVertexArrayObject); - - QOpenGLContext *ctx = QOpenGLContext::currentContext(); - QOpenGLContext *oldContext = nullptr; - QSurface *oldContextSurface = nullptr; - QScopedPointer<QOffscreenSurface> offscreenSurface; - if (context && context != ctx) { - oldContext = ctx; - oldContextSurface = ctx ? ctx->surface() : nullptr; - // Before going through the effort of creating an offscreen surface - // check that we are on the GUI thread because otherwise many platforms - // will not able to create that offscreen surface. - if (QThread::currentThread() != qGuiApp->thread()) { - ctx = nullptr; - } else { - // Cannot just make the current surface current again with another context. - // The format may be incompatible and some platforms (iOS) may impose - // restrictions on using a window with different contexts. Create an - // offscreen surface (a pbuffer or a hidden window) instead to be safe. - offscreenSurface.reset(new QOffscreenSurface); - offscreenSurface->setFormat(context->format()); - offscreenSurface->create(); - if (context->makeCurrent(offscreenSurface.data())) { - ctx = context; - } else { - qWarning("QOpenGLVertexArrayObject::destroy() failed to make VAO's context current"); - ctx = nullptr; - } - } - } - - if (context) { - QObject::disconnect(context, SIGNAL(aboutToBeDestroyed()), q, SLOT(_q_contextAboutToBeDestroyed())); - context = nullptr; - } - - if (vao && ctx) { - switch (vaoFuncsType) { -#ifndef QT_OPENGL_ES_2 - case Core_3_2: - vaoFuncs.core_3_2->glDeleteVertexArrays(1, &vao); - break; - case Core_3_0: - vaoFuncs.core_3_0->glDeleteVertexArrays(1, &vao); - break; -#endif - case ARB: - case APPLE: - case OES: - vaoFuncs.helper->glDeleteVertexArrays(1, &vao); - break; - default: - break; - } - - vao = 0; - } - - if (oldContext && oldContextSurface) { - if (!oldContext->makeCurrent(oldContextSurface)) - qWarning("QOpenGLVertexArrayObject::destroy() failed to restore current context"); - } -} - -/*! - \internal -*/ -void QOpenGLVertexArrayObjectPrivate::_q_contextAboutToBeDestroyed() -{ - destroy(); -} - -void QOpenGLVertexArrayObjectPrivate::bind() -{ - switch (vaoFuncsType) { -#ifndef QT_OPENGL_ES_2 - case Core_3_2: - vaoFuncs.core_3_2->glBindVertexArray(vao); - break; - case Core_3_0: - vaoFuncs.core_3_0->glBindVertexArray(vao); - break; -#endif - case ARB: - case APPLE: - case OES: - vaoFuncs.helper->glBindVertexArray(vao); - break; - default: - break; - } -} - -void QOpenGLVertexArrayObjectPrivate::release() -{ - switch (vaoFuncsType) { -#ifndef QT_OPENGL_ES_2 - case Core_3_2: - vaoFuncs.core_3_2->glBindVertexArray(0); - break; - case Core_3_0: - vaoFuncs.core_3_0->glBindVertexArray(0); - break; -#endif - case ARB: - case APPLE: - case OES: - vaoFuncs.helper->glBindVertexArray(0); - break; - default: - break; - } -} - - -/*! - \class QOpenGLVertexArrayObject - \brief The QOpenGLVertexArrayObject class wraps an OpenGL Vertex Array Object. - \inmodule QtGui - \since 5.1 - \ingroup painting-3D - - A Vertex Array Object (VAO) is an OpenGL container object that encapsulates - the state needed to specify per-vertex attribute data to the OpenGL pipeline. - To put it another way, a VAO remembers the states of buffer objects (see - QOpenGLBuffer) and their associated state (e.g. vertex attribute divisors). - This allows a very easy and efficient method of switching between OpenGL buffer - states for rendering different "objects" in a scene. The QOpenGLVertexArrayObject - class is a thin wrapper around an OpenGL VAO. - - For the desktop, VAOs are supported as a core feature in OpenGL 3.0 or newer and by the - GL_ARB_vertex_array_object for older versions. On OpenGL ES 2, VAOs are provided by - the optional GL_OES_vertex_array_object extension. You can check the version of - OpenGL with QOpenGLContext::surfaceFormat() and check for the presence of extensions - with QOpenGLContext::hasExtension(). - - As with the other Qt OpenGL classes, QOpenGLVertexArrayObject has a create() - function to create the underlying OpenGL object. This is to allow the developer to - ensure that there is a valid current OpenGL context at the time. - - Once you have successfully created a VAO the typical usage pattern is: - - \list - \li In scene initialization function, for each visual object: - \list - \li Bind the VAO - \li Set vertex data state for this visual object (vertices, normals, texture coordinates etc.) - \li Unbind (release()) the VAO - \endlist - \li In render function, for each visual object: - \list - \li Bind the VAO (and shader program if needed) - \li Call a glDraw*() function - \li Unbind (release()) the VAO - \endlist - \endlist - - The act of binding the VAO in the render function has the effect of restoring - all of the vertex data state setup in the initialization phase. In this way we can - set a great deal of state when setting up a VAO and efficiently switch between - state sets of objects to be rendered. Using VAOs also allows the OpenGL driver - to amortise the validation checks of the vertex data. - - \note Vertex Array Objects, like all other OpenGL container objects, are specific - to the context for which they were created and cannot be shared amongst a - context group. - - \sa QOpenGLVertexArrayObject::Binder, QOpenGLBuffer -*/ - -/*! - Creates a QOpenGLVertexArrayObject with the given \a parent. You must call create() - with a valid OpenGL context before using. -*/ -QOpenGLVertexArrayObject::QOpenGLVertexArrayObject(QObject* parent) - : QObject(*new QOpenGLVertexArrayObjectPrivate, parent) -{ -} - -/*! - \internal -*/ -QOpenGLVertexArrayObject::QOpenGLVertexArrayObject(QOpenGLVertexArrayObjectPrivate &dd) - : QObject(dd) -{ -} - -/*! - Destroys the QOpenGLVertexArrayObject and the underlying OpenGL resource. -*/ -QOpenGLVertexArrayObject::~QOpenGLVertexArrayObject() -{ - destroy(); -} - -/*! - Creates the underlying OpenGL vertex array object. There must be a valid OpenGL context - that supports vertex array objects current for this function to succeed. - - Returns \c true if the OpenGL vertex array object was successfully created. - - When the return value is \c false, vertex array object support is not available. This - is not an error: on systems with OpenGL 2.x or OpenGL ES 2.0 vertex array objects may - not be supported. The application is free to continue execution in this case, but it - then has to be prepared to operate in a VAO-less manner too. This means that instead - of merely calling bind(), the value of isCreated() must be checked and the vertex - arrays has to be initialized in the traditional way when there is no vertex array - object present. - - \sa isCreated() -*/ -bool QOpenGLVertexArrayObject::create() -{ - Q_D(QOpenGLVertexArrayObject); - return d->create(); -} - -/*! - Destroys the underlying OpenGL vertex array object. There must be a valid OpenGL context - that supports vertex array objects current for this function to succeed. -*/ -void QOpenGLVertexArrayObject::destroy() -{ - Q_D(QOpenGLVertexArrayObject); - d->destroy(); -} - -/*! - Returns \c true is the underlying OpenGL vertex array object has been created. If this - returns \c true and the associated OpenGL context is current, then you are able to bind() - this object. -*/ -bool QOpenGLVertexArrayObject::isCreated() const -{ - Q_D(const QOpenGLVertexArrayObject); - return (d->vao != 0); -} - -/*! - Returns the id of the underlying OpenGL vertex array object. -*/ -GLuint QOpenGLVertexArrayObject::objectId() const -{ - Q_D(const QOpenGLVertexArrayObject); - return d->vao; -} - -/*! - Binds this vertex array object to the OpenGL binding point. From this point on - and until release() is called or another vertex array object is bound, any - modifications made to vertex data state are stored inside this vertex array object. - - If another vertex array object is then bound you can later restore the set of - state associated with this object by calling bind() on this object once again. - This allows efficient changes between vertex data states in rendering functions. -*/ -void QOpenGLVertexArrayObject::bind() -{ - Q_D(QOpenGLVertexArrayObject); - d->bind(); -} - -/*! - Unbinds this vertex array object by binding the default vertex array object (id = 0). -*/ -void QOpenGLVertexArrayObject::release() -{ - Q_D(QOpenGLVertexArrayObject); - d->release(); -} - - -/*! - \class QOpenGLVertexArrayObject::Binder - \brief The QOpenGLVertexArrayObject::Binder class is a convenience class to help - with the binding and releasing of OpenGL Vertex Array Objects. - \inmodule QtGui - \reentrant - \since 5.1 - \ingroup painting-3D - - QOpenGLVertexArrayObject::Binder is a simple convenience class that can be used - to assist with the binding and releasing of QOpenGLVertexArrayObject instances. - This class is to QOpenGLVertexArrayObject as QMutexLocker is to QMutex. - - This class implements the RAII principle which helps to ensure behavior in - complex code or in the presence of exceptions. - - The constructor of this class accepts a QOpenGLVertexArrayObject (VAO) as an - argument and attempts to bind the VAO, calling QOpenGLVertexArrayObject::create() - if necessary. The destructor of this class calls QOpenGLVertexArrayObject::release() - which unbinds the VAO. - - If needed the VAO can be temporarily unbound with the release() function and bound - once more with rebind(). - - \sa QOpenGLVertexArrayObject -*/ - -/*! - \fn QOpenGLVertexArrayObject::Binder::Binder(QOpenGLVertexArrayObject *v) - - Creates a QOpenGLVertexArrayObject::Binder object and binds \a v by calling - QOpenGLVertexArrayObject::bind(). If necessary it first calls - QOpenGLVertexArrayObject::create(). -*/ - -/*! - \fn QOpenGLVertexArrayObject::Binder::~Binder() - - Destroys the QOpenGLVertexArrayObject::Binder and releases the associated vertex array object. -*/ - -/*! - \fn QOpenGLVertexArrayObject::Binder::release() - - Can be used to temporarily release the associated vertex array object. - - \sa rebind() -*/ - -/*! - \fn QOpenGLVertexArrayObject::Binder::rebind() - - Can be used to rebind the associated vertex array object. - - \sa release() -*/ - -QT_END_NAMESPACE - -#include "moc_qopenglvertexarrayobject.cpp" diff --git a/src/gui/opengl/qopenglvertexarrayobject.h b/src/gui/opengl/qopenglvertexarrayobject.h deleted file mode 100644 index b81ae6a2a9..0000000000 --- a/src/gui/opengl/qopenglvertexarrayobject.h +++ /dev/null @@ -1,111 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Sean Harmer <sean.harmer@kdab.com> -** 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 QOPENGLVERTEXARRAYOBJECT_H -#define QOPENGLVERTEXARRAYOBJECT_H - -#include <QtGui/qtguiglobal.h> - -#ifndef QT_NO_OPENGL - -#include <QtCore/QObject> -#include <QtGui/qopengl.h> - -QT_BEGIN_NAMESPACE - -class QOpenGLVertexArrayObjectPrivate; - -class Q_GUI_EXPORT QOpenGLVertexArrayObject : public QObject -{ - Q_OBJECT - -public: - explicit QOpenGLVertexArrayObject(QObject* parent = nullptr); - ~QOpenGLVertexArrayObject(); - - bool create(); - void destroy(); - bool isCreated() const; - GLuint objectId() const; - void bind(); - void release(); - - class Q_GUI_EXPORT Binder - { - public: - inline Binder(QOpenGLVertexArrayObject *v) - : vao(v) - { - Q_ASSERT(v); - if (vao->isCreated() || vao->create()) - vao->bind(); - } - - inline ~Binder() - { - release(); - } - - inline void release() - { - vao->release(); - } - - inline void rebind() - { - vao->bind(); - } - - private: - Q_DISABLE_COPY(Binder) - QOpenGLVertexArrayObject *vao; - }; - -private: - Q_DISABLE_COPY(QOpenGLVertexArrayObject) - Q_DECLARE_PRIVATE(QOpenGLVertexArrayObject) - Q_PRIVATE_SLOT(d_func(), void _q_contextAboutToBeDestroyed()) - QOpenGLVertexArrayObject(QOpenGLVertexArrayObjectPrivate &dd); -}; - -QT_END_NAMESPACE - -#endif - -#endif // QOPENGLVERTEXARRAYOBJECT_H diff --git a/src/gui/opengl/qopenglvertexarrayobject_p.h b/src/gui/opengl/qopenglvertexarrayobject_p.h deleted file mode 100644 index fd3a6f0f89..0000000000 --- a/src/gui/opengl/qopenglvertexarrayobject_p.h +++ /dev/null @@ -1,125 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Sean Harmer <sean.harmer@kdab.com> -** 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 QOPENGLVERTEXARRAYOBJECT_P_H -#define QOPENGLVERTEXARRAYOBJECT_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists for the convenience -// of the Qt OpenGL classes. This header file may change from -// version to version without notice, or even be removed. -// -// We mean it. -// - -#include <QtCore/qglobal.h> - -#ifndef QT_NO_OPENGL - -#include <QtGui/qopengl.h> - -QT_BEGIN_NAMESPACE - -class QOpenGLVertexArrayObjectHelper; -class QOpenGLContext; - -void Q_GUI_EXPORT qtInitializeVertexArrayObjectHelper(QOpenGLVertexArrayObjectHelper *helper, QOpenGLContext *context); - -class QOpenGLVertexArrayObjectHelper -{ - Q_DISABLE_COPY(QOpenGLVertexArrayObjectHelper) - -public: - explicit inline QOpenGLVertexArrayObjectHelper(QOpenGLContext *context) - : GenVertexArrays(nullptr) - , DeleteVertexArrays(nullptr) - , BindVertexArray(nullptr) - , IsVertexArray(nullptr) - { - qtInitializeVertexArrayObjectHelper(this, context); - } - - inline bool isValid() const - { - return GenVertexArrays && DeleteVertexArrays && BindVertexArray && IsVertexArray; - } - - inline void glGenVertexArrays(GLsizei n, GLuint *arrays) const - { - GenVertexArrays(n, arrays); - } - - inline void glDeleteVertexArrays(GLsizei n, const GLuint *arrays) const - { - DeleteVertexArrays(n, arrays); - } - - inline void glBindVertexArray(GLuint array) const - { - BindVertexArray(array); - } - - inline GLboolean glIsVertexArray(GLuint array) const - { - return IsVertexArray(array); - } - -private: - friend void Q_GUI_EXPORT qtInitializeVertexArrayObjectHelper(QOpenGLVertexArrayObjectHelper *helper, QOpenGLContext *context); - - // Function signatures are equivalent between desktop core, ARB, APPLE, ES 3 and ES 2 extensions - typedef void (QOPENGLF_APIENTRYP qt_GenVertexArrays_t)(GLsizei n, GLuint *arrays); - typedef void (QOPENGLF_APIENTRYP qt_DeleteVertexArrays_t)(GLsizei n, const GLuint *arrays); - typedef void (QOPENGLF_APIENTRYP qt_BindVertexArray_t)(GLuint array); - typedef GLboolean (QOPENGLF_APIENTRYP qt_IsVertexArray_t)(GLuint array); - - qt_GenVertexArrays_t GenVertexArrays; - qt_DeleteVertexArrays_t DeleteVertexArrays; - qt_BindVertexArray_t BindVertexArray; - qt_IsVertexArray_t IsVertexArray; -}; - -QT_END_NAMESPACE - -#endif // QT_NO_OPENGL - -#endif // QOPENGLVERTEXARRAYOBJECT_P_H |