summaryrefslogtreecommitdiffstats
path: root/src/gui/opengl
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-07-18 14:49:15 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-07-27 12:12:34 +0000
commitede3791df8330ed8daae6667d025ad40219a9f5f (patch)
tree0f0c8d8897799b6a7f56c381fe36701795f28f6c /src/gui/opengl
parent318b15db15b515675b0b1e7b3319c793b9f1a757 (diff)
Move texture uploading out of QOpenGLTextureCache
This way the logic can be reused elsewhere. At the same time a standard OpenGL ES/3 way of handling BGRA is added, so we don't depend on extensions, and handling of NPOT and max size which QSGTexture will need. Change-Id: I475bc7127f44be3964fdb482c9e86a20db1fbca5 Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
Diffstat (limited to 'src/gui/opengl')
-rw-r--r--src/gui/opengl/opengl.pri2
-rw-r--r--src/gui/opengl/qopenglextensions_p.h3
-rw-r--r--src/gui/opengl/qopenglfunctions.cpp20
-rw-r--r--src/gui/opengl/qopenglpaintengine.cpp8
-rw-r--r--src/gui/opengl/qopengltexturecache.cpp199
-rw-r--r--src/gui/opengl/qopengltexturecache_p.h24
-rw-r--r--src/gui/opengl/qopengltextureuploader.cpp303
-rw-r--r--src/gui/opengl/qopengltextureuploader_p.h84
8 files changed, 432 insertions, 211 deletions
diff --git a/src/gui/opengl/opengl.pri b/src/gui/opengl/opengl.pri
index 4c778b184e..24758afdeb 100644
--- a/src/gui/opengl/opengl.pri
+++ b/src/gui/opengl/opengl.pri
@@ -32,6 +32,7 @@ qtConfig(opengl) {
opengl/qopengltexture.h \
opengl/qopengltexture_p.h \
opengl/qopengltexturehelper_p.h \
+ opengl/qopengltextureuploader_p.h \
opengl/qopenglpixeltransferoptions.h \
opengl/qopenglextrafunctions.h \
opengl/qopenglprogrambinarycache_p.h
@@ -56,6 +57,7 @@ qtConfig(opengl) {
opengl/qopengltextureblitter.cpp \
opengl/qopengltexture.cpp \
opengl/qopengltexturehelper.cpp \
+ opengl/qopengltextureuploader.cpp \
opengl/qopenglpixeltransferoptions.cpp \
opengl/qopenglprogrambinarycache.cpp
diff --git a/src/gui/opengl/qopenglextensions_p.h b/src/gui/opengl/qopenglextensions_p.h
index a5f1a2cc88..af8ee8201d 100644
--- a/src/gui/opengl/qopenglextensions_p.h
+++ b/src/gui/opengl/qopenglextensions_p.h
@@ -90,7 +90,8 @@ public:
MapBufferRange = 0x00100000,
Sized8Formats = 0x00200000,
DiscardFramebuffer = 0x00400000,
- Sized16Formats = 0x00800000
+ Sized16Formats = 0x00800000,
+ TextureSwizzle = 0x01000000,
};
Q_DECLARE_FLAGS(OpenGLExtensions, OpenGLExtension)
diff --git a/src/gui/opengl/qopenglfunctions.cpp b/src/gui/opengl/qopenglfunctions.cpp
index 913b289c52..4f48604a88 100644
--- a/src/gui/opengl/qopenglfunctions.cpp
+++ b/src/gui/opengl/qopenglfunctions.cpp
@@ -45,6 +45,7 @@
#include <QtGui/private/qopengl_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
+#include <qpa/qplatformnativeinterface.h>
#ifdef Q_OS_INTEGRITY
#include <EGL/egl.h>
@@ -424,6 +425,8 @@ static int qt_gl_resolve_extensions()
extensions |= QOpenGLExtensions::NVFloatBuffer;
if (extensionMatcher.match("GL_ARB_pixel_buffer_object"))
extensions |= QOpenGLExtensions::PixelBufferObject;
+ if (extensionMatcher.match("GL_ARB_texture_swizzle") || extensionMatcher.match("GL_EXT_texture_swizzle"))
+ extensions |= QOpenGLExtensions::TextureSwizzle;
if (ctx->isOpenGLES()) {
if (format.majorVersion() >= 2)
@@ -436,7 +439,8 @@ static int qt_gl_resolve_extensions()
| QOpenGLExtensions::MapBufferRange
| QOpenGLExtensions::FramebufferBlit
| QOpenGLExtensions::FramebufferMultisample
- | QOpenGLExtensions::Sized8Formats;
+ | QOpenGLExtensions::Sized8Formats
+ | QOpenGLExtensions::TextureSwizzle;
} else {
// Recognize features by extension name.
if (extensionMatcher.match("GL_OES_packed_depth_stencil"))
@@ -462,6 +466,17 @@ static int qt_gl_resolve_extensions()
// We don't match GL_APPLE_texture_format_BGRA8888 here because it has different semantics.
if (extensionMatcher.match("GL_IMG_texture_format_BGRA8888") || extensionMatcher.match("GL_EXT_texture_format_BGRA8888"))
extensions |= QOpenGLExtensions::BGRATextureFormat;
+#if defined(Q_OS_ANDROID) && !defined(Q_OS_ANDROID_EMBEDDED)
+ QString *deviceName =
+ static_cast<QString *>(QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("AndroidDeviceName"));
+ static bool wrongfullyReportsBgra8888Support = deviceName != 0
+ && (deviceName->compare(QLatin1String("samsung SM-T211"), Qt::CaseInsensitive) == 0
+ || deviceName->compare(QLatin1String("samsung SM-T210"), Qt::CaseInsensitive) == 0
+ || deviceName->compare(QLatin1String("samsung SM-T215"), Qt::CaseInsensitive) == 0);
+ if (wrongfullyReportsBgra8888Support)
+ extensions &= ~QOpenGLExtensions::BGRATextureFormat;
+#endif
+
if (extensionMatcher.match("GL_EXT_discard_framebuffer"))
extensions |= QOpenGLExtensions::DiscardFramebuffer;
if (extensionMatcher.match("GL_EXT_texture_norm16"))
@@ -495,6 +510,9 @@ static int qt_gl_resolve_extensions()
if (format.version() >= qMakePair(3, 2) || extensionMatcher.match("GL_ARB_geometry_shader4"))
extensions |= QOpenGLExtensions::GeometryShaders;
+ if (format.version() >= qMakePair(3, 3))
+ extensions |= QOpenGLExtensions::TextureSwizzle;
+
if (extensionMatcher.match("GL_ARB_map_buffer_range"))
extensions |= QOpenGLExtensions::MapBufferRange;
diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp
index e390183893..5902713faa 100644
--- a/src/gui/opengl/qopenglpaintengine.cpp
+++ b/src/gui/opengl/qopenglpaintengine.cpp
@@ -263,7 +263,7 @@ GLuint QOpenGL2PaintEngineExPrivate::bindTexture(const QGradient &gradient)
struct ImageWithBindOptions
{
const QImage &image;
- QOpenGLTextureCache::BindOptions options;
+ QOpenGLTextureUploader::BindOptions options;
};
template<>
@@ -1554,7 +1554,7 @@ void QOpenGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, c
ensureActive();
d->transferMode(ImageDrawingMode);
- QOpenGLTextureCache::BindOptions bindOption = QOpenGLTextureCache::PremultipliedAlphaBindOption;
+ QOpenGLTextureUploader::BindOptions bindOption = QOpenGLTextureUploader::PremultipliedAlphaBindOption;
// Use specialized bind for formats we have specialized shaders for.
switch (image.format()) {
case QImage::Format_RGBA8888:
@@ -1565,14 +1565,14 @@ void QOpenGL2PaintEngineEx::drawImage(const QRectF& dest, const QImage& image, c
case QImage::Format_Alpha8:
if (ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::TextureRGFormats)) {
d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::AlphaImageSrc);
- bindOption = QOpenGLTextureCache::UseRedFor8BitBindOption;
+ bindOption = QOpenGLTextureUploader::UseRedFor8BitBindOption;
} else
d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::ImageSrc);
break;
case QImage::Format_Grayscale8:
if (ctx->functions()->hasOpenGLFeature(QOpenGLFunctions::TextureRGFormats)) {
d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::GrayscaleImageSrc);
- bindOption = QOpenGLTextureCache::UseRedFor8BitBindOption;
+ bindOption = QOpenGLTextureUploader::UseRedFor8BitBindOption;
} else
d->shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::ImageSrc);
break;
diff --git a/src/gui/opengl/qopengltexturecache.cpp b/src/gui/opengl/qopengltexturecache.cpp
index 27aa8db33a..8de0b25fee 100644
--- a/src/gui/opengl/qopengltexturecache.cpp
+++ b/src/gui/opengl/qopengltexturecache.cpp
@@ -38,39 +38,14 @@
****************************************************************************/
#include "qopengltexturecache_p.h"
+#include "qopengltextureuploader_p.h"
#include <qmath.h>
#include <qopenglfunctions.h>
-#include <private/qopenglcontext_p.h>
-#include <private/qopenglextensions_p.h>
#include <private/qimagepixmapcleanuphooks_p.h>
#include <qpa/qplatformpixmap.h>
QT_BEGIN_NAMESPACE
-#ifndef GL_RED
-#define GL_RED 0x1903
-#endif
-
-#ifndef GL_RGB10_A2
-#define GL_RGB10_A2 0x8059
-#endif
-
-#ifndef GL_BGR
-#define GL_BGR 0x80E0
-#endif
-
-#ifndef GL_BGRA
-#define GL_BGRA 0x80E1
-#endif
-
-#ifndef GL_UNSIGNED_INT_8_8_8_8_REV
-#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
-#endif
-
-#ifndef GL_UNSIGNED_INT_2_10_10_10_REV
-#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
-#endif
-
class QOpenGLTextureCacheWrapper
{
public:
@@ -130,7 +105,7 @@ QOpenGLTextureCache::~QOpenGLTextureCache()
{
}
-GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, const QPixmap &pixmap, BindOptions options)
+GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, const QPixmap &pixmap, QOpenGLTextureUploader::BindOptions options)
{
if (pixmap.isNull())
return 0;
@@ -153,7 +128,7 @@ GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, const QPixmap &
return id;
}
-GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, const QImage &image, BindOptions options)
+GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, const QImage &image, QOpenGLTextureUploader::BindOptions options)
{
if (image.isNull())
return 0;
@@ -170,16 +145,8 @@ GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, const QImage &i
}
QImage img = image;
- if (!context->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextures)) {
- // Scale the pixmap if needed. GL textures needs to have the
- // dimensions 2^n+2(border) x 2^m+2(border), unless we're using GL
- // 2.0 or use the GL_TEXTURE_RECTANGLE texture target
- int tx_w = qNextPowerOfTwo(image.width() - 1);
- int tx_h = qNextPowerOfTwo(image.height() - 1);
- if (tx_w != image.width() || tx_h != image.height()) {
- img = img.scaled(tx_w, tx_h);
- }
- }
+ if (!context->functions()->hasOpenGLFeature(QOpenGLFunctions::NPOTTextures))
+ options |= QOpenGLTextureUploader::PowerOfTwoBindOption;
GLuint id = bindTexture(context, key, img, options);
if (id > 0)
@@ -188,164 +155,16 @@ GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, const QImage &i
return id;
}
-GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, qint64 key, const QImage &image, BindOptions options)
+GLuint QOpenGLTextureCache::bindTexture(QOpenGLContext *context, qint64 key, const QImage &image, QOpenGLTextureUploader::BindOptions options)
{
GLuint id;
QOpenGLFunctions *funcs = context->functions();
funcs->glGenTextures(1, &id);
funcs->glBindTexture(GL_TEXTURE_2D, id);
- QImage tx;
- GLenum externalFormat;
- GLenum internalFormat;
- GLuint pixelType;
- QImage::Format targetFormat = QImage::Format_Invalid;
- const bool isOpenGL12orBetter = !context->isOpenGLES() && (context->format().majorVersion() >= 2 || context->format().minorVersion() >= 2);
-
- switch (image.format()) {
- case QImage::Format_RGB32:
- case QImage::Format_ARGB32:
- case QImage::Format_ARGB32_Premultiplied:
- if (isOpenGL12orBetter) {
- externalFormat = GL_BGRA;
- internalFormat = GL_RGBA;
- pixelType = GL_UNSIGNED_INT_8_8_8_8_REV;
- } else {
-#if Q_BYTE_ORDER == Q_BIG_ENDIAN
- // Without GL_UNSIGNED_INT_8_8_8_8_REV, BGRA only matches ARGB on little endian.
- break;
-#endif
- if (static_cast<QOpenGLExtensions*>(context->functions())->hasOpenGLExtension(QOpenGLExtensions::BGRATextureFormat)) {
- // GL_EXT_bgra or GL_EXT_texture_format_BGRA8888 extensions.
- if (context->isOpenGLES()) {
- // The GL_EXT_texture_format_BGRA8888 extension requires the internal format to match the external.
- externalFormat = internalFormat = GL_BGRA;
- } else {
- // OpenGL BGRA/BGR format is not allowed as an internal format
- externalFormat = GL_BGRA;
- internalFormat = GL_RGBA;
- }
- pixelType = GL_UNSIGNED_BYTE;
- } else if (context->isOpenGLES() && context->hasExtension(QByteArrayLiteral("GL_APPLE_texture_format_BGRA8888"))) {
- // Is only allowed as an external format like OpenGL.
- externalFormat = GL_BGRA;
- internalFormat = GL_RGBA;
- pixelType = GL_UNSIGNED_BYTE;
- } else {
- // No support for direct ARGB32 upload.
- break;
- }
- }
- targetFormat = image.format();
- break;
- case QImage::Format_BGR30:
- case QImage::Format_A2BGR30_Premultiplied:
- if (isOpenGL12orBetter || (context->isOpenGLES() && context->format().majorVersion() >= 3)) {
- pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
- externalFormat = GL_RGBA;
- internalFormat = GL_RGB10_A2;
- targetFormat = image.format();
- }
- break;
- case QImage::Format_RGB30:
- case QImage::Format_A2RGB30_Premultiplied:
- if (isOpenGL12orBetter) {
- pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
- externalFormat = GL_BGRA;
- internalFormat = GL_RGB10_A2;
- targetFormat = image.format();
- } else if (context->isOpenGLES() && context->format().majorVersion() >= 3) {
- pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
- externalFormat = GL_RGBA;
- internalFormat = GL_RGB10_A2;
- targetFormat = QImage::Format_A2BGR30_Premultiplied;
- }
- break;
- case QImage::Format_RGB444:
- case QImage::Format_RGB555:
- case QImage::Format_RGB16:
- if (isOpenGL12orBetter || context->isOpenGLES()) {
- externalFormat = internalFormat = GL_RGB;
- pixelType = GL_UNSIGNED_SHORT_5_6_5;
- targetFormat = QImage::Format_RGB16;
- }
- break;
- case QImage::Format_RGB666:
- case QImage::Format_RGB888:
- externalFormat = internalFormat = GL_RGB;
- pixelType = GL_UNSIGNED_BYTE;
- targetFormat = QImage::Format_RGB888;
- break;
- case QImage::Format_RGBX8888:
- case QImage::Format_RGBA8888:
- case QImage::Format_RGBA8888_Premultiplied:
- externalFormat = internalFormat = GL_RGBA;
- pixelType = GL_UNSIGNED_BYTE;
- targetFormat = image.format();
- break;
- case QImage::Format_Indexed8:
- if (options & UseRedFor8BitBindOption) {
- externalFormat = internalFormat = GL_RED;
- pixelType = GL_UNSIGNED_BYTE;
- targetFormat = image.format();
- }
- break;
- case QImage::Format_Alpha8:
- if (options & UseRedFor8BitBindOption) {
- externalFormat = internalFormat = GL_RED;
- pixelType = GL_UNSIGNED_BYTE;
- targetFormat = image.format();
- } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) {
- externalFormat = internalFormat = GL_ALPHA;
- pixelType = GL_UNSIGNED_BYTE;
- targetFormat = image.format();
- }
- break;
- case QImage::Format_Grayscale8:
- if (options & UseRedFor8BitBindOption) {
- externalFormat = internalFormat = GL_RED;
- pixelType = GL_UNSIGNED_BYTE;
- targetFormat = image.format();
- } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) {
- externalFormat = internalFormat = GL_LUMINANCE;
- pixelType = GL_UNSIGNED_BYTE;
- targetFormat = image.format();
- }
- break;
- default:
- break;
- }
-
- if (targetFormat == QImage::Format_Invalid) {
- externalFormat = internalFormat = GL_RGBA;
- pixelType = GL_UNSIGNED_BYTE;
- if (!image.hasAlphaChannel())
- targetFormat = QImage::Format_RGBX8888;
- else
- targetFormat = QImage::Format_RGBA8888;
- }
-
- if (options & PremultipliedAlphaBindOption) {
- if (targetFormat == QImage::Format_ARGB32)
- targetFormat = QImage::Format_ARGB32_Premultiplied;
- else if (targetFormat == QImage::Format_RGBA8888)
- targetFormat = QImage::Format_RGBA8888_Premultiplied;
- } else {
- if (targetFormat == QImage::Format_ARGB32_Premultiplied)
- targetFormat = QImage::Format_ARGB32;
- else if (targetFormat == QImage::Format_RGBA8888_Premultiplied)
- targetFormat = QImage::Format_RGBA8888;
- }
-
- if (image.format() != targetFormat)
- tx = image.convertToFormat(targetFormat);
- else
- tx = image;
-
- funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, tx.width(), tx.height(), 0, externalFormat, pixelType, const_cast<const QImage &>(tx).bits());
+ int cost = QOpenGLTextureUploader::textureImage(GL_TEXTURE_2D, image, options);
- int cost = tx.width() * tx.height() * tx.depth() / (1024 * 8);
- m_cache.insert(key, new QOpenGLCachedTexture(id, options, context), cost);
+ m_cache.insert(key, new QOpenGLCachedTexture(id, options, context), cost / 1024);
return id;
}
@@ -371,7 +190,7 @@ static void freeTexture(QOpenGLFunctions *funcs, GLuint id)
funcs->glDeleteTextures(1, &id);
}
-QOpenGLCachedTexture::QOpenGLCachedTexture(GLuint id, QOpenGLTextureCache::BindOptions options, QOpenGLContext *context) : m_options(options)
+QOpenGLCachedTexture::QOpenGLCachedTexture(GLuint id, QOpenGLTextureUploader::BindOptions options, QOpenGLContext *context) : m_options(options)
{
m_resource = new QOpenGLSharedResourceGuard(context, id, freeTexture);
}
diff --git a/src/gui/opengl/qopengltexturecache_p.h b/src/gui/opengl/qopengltexturecache_p.h
index b9d7df91e3..88ef06e744 100644
--- a/src/gui/opengl/qopengltexturecache_p.h
+++ b/src/gui/opengl/qopengltexturecache_p.h
@@ -56,6 +56,7 @@
#include <QObject>
#include <QCache>
#include <private/qopenglcontext_p.h>
+#include <private/qopengltextureuploader_p.h>
#include <QtCore/qmutex.h>
QT_BEGIN_NAMESPACE
@@ -70,15 +71,10 @@ public:
QOpenGLTextureCache(QOpenGLContext *);
~QOpenGLTextureCache();
- enum BindOption {
- NoBindOption = 0x0000,
- PremultipliedAlphaBindOption = 0x0001,
- UseRedFor8BitBindOption = 0x0002,
- };
- Q_DECLARE_FLAGS(BindOptions, BindOption)
-
- GLuint bindTexture(QOpenGLContext *context, const QPixmap &pixmap, QOpenGLTextureCache::BindOptions options = PremultipliedAlphaBindOption);
- GLuint bindTexture(QOpenGLContext *context, const QImage &image, QOpenGLTextureCache::BindOptions options = PremultipliedAlphaBindOption);
+ GLuint bindTexture(QOpenGLContext *context, const QPixmap &pixmap,
+ QOpenGLTextureUploader::BindOptions options = QOpenGLTextureUploader::PremultipliedAlphaBindOption);
+ GLuint bindTexture(QOpenGLContext *context, const QImage &image,
+ QOpenGLTextureUploader::BindOptions options = QOpenGLTextureUploader::PremultipliedAlphaBindOption);
void invalidate(qint64 key);
@@ -86,26 +82,24 @@ public:
void freeResource(QOpenGLContext *ctx) override;
private:
- GLuint bindTexture(QOpenGLContext *context, qint64 key, const QImage &image, QOpenGLTextureCache::BindOptions options);
+ GLuint bindTexture(QOpenGLContext *context, qint64 key, const QImage &image, QOpenGLTextureUploader::BindOptions options);
QMutex m_mutex;
QCache<quint64, QOpenGLCachedTexture> m_cache;
};
-Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLTextureCache::BindOptions)
-
class QOpenGLCachedTexture
{
public:
- QOpenGLCachedTexture(GLuint id, QOpenGLTextureCache::BindOptions options, QOpenGLContext *context);
+ QOpenGLCachedTexture(GLuint id, QOpenGLTextureUploader::BindOptions options, QOpenGLContext *context);
~QOpenGLCachedTexture() { m_resource->free(); }
GLuint id() const { return m_resource->id(); }
- QOpenGLTextureCache::BindOptions options() const { return m_options; }
+ QOpenGLTextureUploader::BindOptions options() const { return m_options; }
private:
QOpenGLSharedResourceGuard *m_resource;
- QOpenGLTextureCache::BindOptions m_options;
+ QOpenGLTextureUploader::BindOptions m_options;
};
QT_END_NAMESPACE
diff --git a/src/gui/opengl/qopengltextureuploader.cpp b/src/gui/opengl/qopengltextureuploader.cpp
new file mode 100644
index 0000000000..0204d4852f
--- /dev/null
+++ b/src/gui/opengl/qopengltextureuploader.cpp
@@ -0,0 +1,303 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qopengltextureuploader_p.h"
+
+#include <qimage.h>
+#include <qmath.h>
+#include <qopenglfunctions.h>
+#include <private/qopenglcontext_p.h>
+#include <private/qopenglextensions_p.h>
+
+#ifndef GL_RED
+#define GL_RED 0x1903
+#endif
+
+#ifndef GL_GREEN
+#define GL_GREEN 0x1904
+#endif
+
+#ifndef GL_BLUE
+#define GL_BLUE 0x1905
+#endif
+
+#ifndef GL_RGB10_A2
+#define GL_RGB10_A2 0x8059
+#endif
+
+#ifndef GL_BGRA
+#define GL_BGRA 0x80E1
+#endif
+
+#ifndef GL_UNSIGNED_INT_8_8_8_8_REV
+#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
+#endif
+
+#ifndef GL_UNSIGNED_INT_2_10_10_10_REV
+#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
+#endif
+
+#ifndef GL_TEXTURE_SWIZZLE_RGBA
+#define GL_TEXTURE_SWIZZLE_RGBA 0x8E46
+#endif
+
+#ifndef GL_SRGB
+#define GL_SRGB 0x8C40
+#endif
+#ifndef GL_SRGB_ALPHA
+#define GL_SRGB_ALPHA 0x8C42
+#endif
+
+QT_BEGIN_NAMESPACE
+
+qsizetype QOpenGLTextureUploader::textureImage(GLenum target, const QImage &image, QOpenGLTextureUploader::BindOptions options, QSize maxSize)
+{
+ QOpenGLContext *context = QOpenGLContext::currentContext();
+ QOpenGLExtensions *funcs = static_cast<QOpenGLExtensions*>(context->functions());
+
+ QImage tx;
+ GLenum externalFormat;
+ GLenum internalFormat;
+ GLuint pixelType;
+ QImage::Format targetFormat = QImage::Format_Invalid;
+ const bool isOpenGL12orBetter = !context->isOpenGLES() && (context->format().majorVersion() >= 2 || context->format().minorVersion() >= 2);
+ const bool isOpenGLES3orBetter = context->isOpenGLES() && context->format().majorVersion() >= 3;
+ const bool sRgbBinding = (options & SRgbBindOption);
+ Q_ASSERT(isOpenGL12orBetter || context->isOpenGLES());
+ Q_ASSERT((options & (SRgbBindOption | UseRedFor8BitBindOption)) != (SRgbBindOption | UseRedFor8BitBindOption));
+
+ switch (image.format()) {
+ case QImage::Format_RGB32:
+ case QImage::Format_ARGB32:
+ case QImage::Format_ARGB32_Premultiplied:
+ if (isOpenGL12orBetter) {
+ externalFormat = GL_BGRA;
+ internalFormat = GL_RGBA;
+ pixelType = GL_UNSIGNED_INT_8_8_8_8_REV;
+ } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle) && false) {
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ GLint swizzle[4] = { GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA };
+ funcs->glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
+#else
+ GLint swizzle[4] = { GL_GREEN, GL_BLUE, GL_ALPHA, GL_RED };
+ funcs->glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
+#endif
+ externalFormat = internalFormat = GL_RGBA;
+ pixelType = GL_UNSIGNED_BYTE;
+ } else {
+#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
+ // Without GL_UNSIGNED_INT_8_8_8_8_REV, BGRA only matches ARGB on little endian.
+ if (funcs->hasOpenGLExtension(QOpenGLExtensions::BGRATextureFormat) && !sRgbBinding) {
+ // The GL_EXT_texture_format_BGRA8888 extension requires the internal format to match the external.
+ externalFormat = internalFormat = GL_BGRA;
+ pixelType = GL_UNSIGNED_BYTE;
+ } else if (context->isOpenGLES() && context->hasExtension(QByteArrayLiteral("GL_APPLE_texture_format_BGRA8888"))) {
+ // Is only allowed as an external format like OpenGL.
+ externalFormat = GL_BGRA;
+ internalFormat = GL_RGBA;
+ pixelType = GL_UNSIGNED_BYTE;
+ } else {
+ // No support for direct ARGB32 upload.
+ break;
+ }
+ }
+ targetFormat = image.format();
+#endif
+ break;
+ case QImage::Format_BGR30:
+ case QImage::Format_A2BGR30_Premultiplied:
+ if (sRgbBinding) {
+ // Always needs conversion
+ break;
+ } else if (isOpenGL12orBetter || isOpenGLES3orBetter) {
+ pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
+ externalFormat = GL_RGBA;
+ internalFormat = GL_RGB10_A2;
+ targetFormat = image.format();
+ }
+ break;
+ case QImage::Format_RGB30:
+ case QImage::Format_A2RGB30_Premultiplied:
+ if (sRgbBinding) {
+ // Always needs conversion
+ break;
+ } else if (isOpenGL12orBetter) {
+ pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
+ externalFormat = GL_BGRA;
+ internalFormat = GL_RGB10_A2;
+ targetFormat = image.format();
+ } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle) && (isOpenGL12orBetter || isOpenGLES3orBetter)) {
+ pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
+ externalFormat = GL_RGBA;
+ internalFormat = GL_RGB10_A2;
+ GLint swizzle[4] = { GL_BLUE, GL_GREEN, GL_RED, GL_ALPHA };
+ funcs->glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
+ targetFormat = image.format();
+ }
+ break;
+ case QImage::Format_RGB444:
+ case QImage::Format_RGB555:
+ case QImage::Format_RGB16:
+ if (isOpenGL12orBetter || context->isOpenGLES()) {
+ externalFormat = internalFormat = GL_RGB;
+ pixelType = GL_UNSIGNED_SHORT_5_6_5;
+ targetFormat = QImage::Format_RGB16;
+ }
+ break;
+ case QImage::Format_RGB666:
+ case QImage::Format_RGB888:
+ externalFormat = internalFormat = GL_RGB;
+ pixelType = GL_UNSIGNED_BYTE;
+ targetFormat = QImage::Format_RGB888;
+ break;
+ case QImage::Format_RGBX8888:
+ case QImage::Format_RGBA8888:
+ case QImage::Format_RGBA8888_Premultiplied:
+ externalFormat = internalFormat = GL_RGBA;
+ pixelType = GL_UNSIGNED_BYTE;
+ targetFormat = image.format();
+ break;
+ case QImage::Format_Indexed8:
+ if (sRgbBinding) {
+ // Always needs conversion
+ break;
+ } else if (options & UseRedFor8BitBindOption) {
+ externalFormat = internalFormat = GL_RED;
+ pixelType = GL_UNSIGNED_BYTE;
+ targetFormat = image.format();
+ }
+ break;
+ case QImage::Format_Alpha8:
+ if (sRgbBinding) {
+ // Always needs conversion
+ break;
+ } else if (options & UseRedFor8BitBindOption) {
+ externalFormat = internalFormat = GL_RED;
+ pixelType = GL_UNSIGNED_BYTE;
+ targetFormat = image.format();
+ } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) {
+ externalFormat = internalFormat = GL_ALPHA;
+ pixelType = GL_UNSIGNED_BYTE;
+ targetFormat = image.format();
+ } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) {
+ GLint swizzle[4] = { GL_ZERO, GL_ZERO, GL_ZERO, GL_RED };
+ funcs->glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
+ externalFormat = internalFormat = GL_RED;
+ pixelType = GL_UNSIGNED_BYTE;
+ targetFormat = image.format();
+ }
+ break;
+ case QImage::Format_Grayscale8:
+ if (sRgbBinding) {
+ // Always needs conversion
+ break;
+ } else if (options & UseRedFor8BitBindOption) {
+ externalFormat = internalFormat = GL_RED;
+ pixelType = GL_UNSIGNED_BYTE;
+ targetFormat = image.format();
+ } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) {
+ externalFormat = internalFormat = GL_LUMINANCE;
+ pixelType = GL_UNSIGNED_BYTE;
+ targetFormat = image.format();
+ } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) {
+ GLint swizzle[4] = { GL_RED, GL_RED, GL_RED, GL_ONE };
+ funcs->glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzle);
+ externalFormat = internalFormat = GL_RED;
+ pixelType = GL_UNSIGNED_BYTE;
+ targetFormat = image.format();
+ }
+ break;
+ default:
+ break;
+ }
+
+ // If no direct upload was detected above, convert to RGBA8888 and upload that
+ if (targetFormat == QImage::Format_Invalid) {
+ externalFormat = internalFormat = GL_RGBA;
+ pixelType = GL_UNSIGNED_BYTE;
+ if (!image.hasAlphaChannel())
+ targetFormat = QImage::Format_RGBX8888;
+ else
+ targetFormat = QImage::Format_RGBA8888;
+ }
+
+ if (options & PremultipliedAlphaBindOption) {
+ if (targetFormat == QImage::Format_ARGB32)
+ targetFormat = QImage::Format_ARGB32_Premultiplied;
+ else if (targetFormat == QImage::Format_RGBA8888)
+ targetFormat = QImage::Format_RGBA8888_Premultiplied;
+ } else {
+ if (targetFormat == QImage::Format_ARGB32_Premultiplied)
+ targetFormat = QImage::Format_ARGB32;
+ else if (targetFormat == QImage::Format_RGBA8888_Premultiplied)
+ targetFormat = QImage::Format_RGBA8888;
+ }
+
+ if (sRgbBinding) {
+ Q_ASSERT(internalFormat == GL_RGBA || internalFormat == GL_RGB);
+ if (image.hasAlphaChannel())
+ internalFormat = GL_SRGB_ALPHA;
+ else
+ internalFormat = GL_SRGB;
+ }
+
+ if (image.format() != targetFormat)
+ tx = image.convertToFormat(targetFormat);
+ else
+ tx = image;
+
+ QSize newSize = tx.size();
+ if (!maxSize.isEmpty())
+ newSize = newSize.boundedTo(maxSize);
+ if (options & PowerOfTwoBindOption) {
+ newSize.setWidth(qNextPowerOfTwo(newSize.width() - 1));
+ newSize.setHeight(qNextPowerOfTwo(newSize.height() - 1));
+ }
+
+ if (newSize != tx.size())
+ tx = tx.scaled(newSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+
+ funcs->glTexImage2D(target, 0, internalFormat, tx.width(), tx.height(), 0, externalFormat, pixelType, tx.constBits());
+
+ qsizetype cost = qint64(tx.width()) * tx.height() * tx.depth() / 8;
+
+ return cost;
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/opengl/qopengltextureuploader_p.h b/src/gui/opengl/qopengltextureuploader_p.h
new file mode 100644
index 0000000000..d758b3787b
--- /dev/null
+++ b/src/gui/opengl/qopengltextureuploader_p.h
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#ifndef QOPENGLTEXTUREUPLOADER_P_H
+#define QOPENGLTEXTUREUPLOADER_P_H
+
+#include <QtCore/qsize.h>
+#include <QtGui/private/qtguiglobal_p.h>
+#include <QtGui/private/qopenglcontext_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QImage;
+
+class Q_GUI_EXPORT QOpenGLTextureUploader
+{
+public:
+ enum BindOption {
+ NoBindOption = 0x0000,
+ PremultipliedAlphaBindOption = 0x0001,
+ UseRedFor8BitBindOption = 0x0002,
+ SRgbBindOption = 0x0004,
+ PowerOfTwoBindOption = 0x0008
+ };
+ Q_DECLARE_FLAGS(BindOptions, BindOption)
+ Q_FLAGS(BindOptions)
+
+ static qsizetype textureImage(GLenum target, const QImage &image, BindOptions options, QSize maxSize = QSize());
+
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QOpenGLTextureUploader::BindOptions)
+
+QT_END_NAMESPACE
+
+#endif
+