diff options
author | Johan Klokkhammer Helsing <johan.helsing@qt.io> | 2019-12-12 08:51:20 +0100 |
---|---|---|
committer | Johan Klokkhammer Helsing <johan.helsing@qt.io> | 2020-01-24 08:57:38 +0100 |
commit | 2344e5cc3104b7d599f4d2a96bbfd8530223a08e (patch) | |
tree | 02fae8469ce67262c21c187825c370627e62991d /src/opengl | |
parent | 85e3e88e1e68d9834346593c6b4819694f8a1a59 (diff) |
Move QOpenGLTexture and related classes from QtGui to QtOpenGL
Task-number: QTBUG-74409
Change-Id: Ied825dd7cb92365505a4aa43fd67488024160341
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Diffstat (limited to 'src/opengl')
-rw-r--r-- | src/opengl/opengl.pro | 7 | ||||
-rw-r--r-- | src/opengl/qopenglpixeltransferoptions.cpp | 263 | ||||
-rw-r--r-- | src/opengl/qopenglpixeltransferoptions.h | 100 | ||||
-rw-r--r-- | src/opengl/qopengltexture.cpp | 4987 | ||||
-rw-r--r-- | src/opengl/qopengltexture.h | 663 | ||||
-rw-r--r-- | src/opengl/qopengltexture_p.h | 184 | ||||
-rw-r--r-- | src/opengl/qopengltexturehelper.cpp | 589 | ||||
-rw-r--r-- | src/opengl/qopengltexturehelper_p.h | 797 |
8 files changed, 7590 insertions, 0 deletions
diff --git a/src/opengl/opengl.pro b/src/opengl/opengl.pro index 6c2a969820..ba9590ec07 100644 --- a/src/opengl/opengl.pro +++ b/src/opengl/opengl.pro @@ -19,7 +19,11 @@ HEADERS += \ qopenglpaintdevice.h \ qopenglpaintdevice_p.h \ qopenglpaintengine_p.h \ + qopenglpixeltransferoptions.h \ qopenglshadercache_p.h \ + qopengltexture.h \ + qopengltexture_p.h \ + qopengltexturehelper_p.h \ qopengltexturecache_p.h \ qopengltextureglyphcache_p.h \ qopengltextureuploader_p.h \ @@ -33,6 +37,9 @@ SOURCES += \ qopenglgradientcache.cpp \ qopenglpaintdevice.cpp \ qopenglpaintengine.cpp \ + qopenglpixeltransferoptions.cpp \ + qopengltexture.cpp \ + qopengltexturehelper.cpp \ qopengltexturecache.cpp \ qopengltextureglyphcache.cpp \ qopengltextureuploader.cpp \ diff --git a/src/opengl/qopenglpixeltransferoptions.cpp b/src/opengl/qopenglpixeltransferoptions.cpp new file mode 100644 index 0000000000..aa1af3b092 --- /dev/null +++ b/src/opengl/qopenglpixeltransferoptions.cpp @@ -0,0 +1,263 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "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/opengl/qopenglpixeltransferoptions.h b/src/opengl/qopenglpixeltransferoptions.h new file mode 100644 index 0000000000..252c2a2f1e --- /dev/null +++ b/src/opengl/qopenglpixeltransferoptions.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENGLPIXELUPLOADOPTIONS_H +#define QOPENGLPIXELUPLOADOPTIONS_H + +#include <QtOpenGL/qtopenglglobal.h> + +#if !defined(QT_NO_OPENGL) + +#include <QtCore/QSharedDataPointer> + +QT_BEGIN_NAMESPACE + +class QOpenGLPixelTransferOptionsData; + +class Q_OPENGL_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/opengl/qopengltexture.cpp b/src/opengl/qopengltexture.cpp new file mode 100644 index 0000000000..35d90898e5 --- /dev/null +++ b/src/opengl/qopengltexture.cpp @@ -0,0 +1,4987 @@ +/**************************************************************************** +** +** 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 "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); + auto *funcs = texFuncs; // lets us capture by pointer value below + context->setTextureFunctions(funcs, [funcs] { delete funcs; }); + } +} + +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. + + \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 1-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(const 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/opengl/qopengltexture.h b/src/opengl/qopengltexture.h new file mode 100644 index 0000000000..8eba2724df --- /dev/null +++ b/src/opengl/qopengltexture.h @@ -0,0 +1,663 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QOPENGLABSTRACTTEXTURE_H +#define QOPENGLABSTRACTTEXTURE_H + +#include <QtOpenGL/qtopenglglobal.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_OPENGL_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(const 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_OPENGL_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_OPENGL_EXPORT QDebug operator<<(QDebug debug, const QOpenGLTexture *t); +#endif + +QT_END_NAMESPACE + +#endif // QT_NO_OPENGL + +#endif // QOPENGLABSTRACTTEXTURE_H diff --git a/src/opengl/qopengltexture_p.h b/src/opengl/qopengltexture_p.h new file mode 100644 index 0000000000..1dc0801644 --- /dev/null +++ b/src/opengl/qopengltexture_p.h @@ -0,0 +1,184 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef 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 <QtOpenGL/qtopenglglobal.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/opengl/qopengltexturehelper.cpp b/src/opengl/qopengltexturehelper.cpp new file mode 100644 index 0000000000..8f1473ecc9 --- /dev/null +++ b/src/opengl/qopengltexturehelper.cpp @@ -0,0 +1,589 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "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/opengl/qopengltexturehelper_p.h b/src/opengl/qopengltexturehelper_p.h new file mode 100644 index 0000000000..a62a47d029 --- /dev/null +++ b/src/opengl/qopengltexturehelper_p.h @@ -0,0 +1,797 @@ +/**************************************************************************** +** +** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef 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 <QtOpenGL/qtopenglglobal.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 |