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>
This commit is contained in:
parent
318b15db15
commit
ede3791df8
@ -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
|
||||
|
||||
|
@ -90,7 +90,8 @@ public:
|
||||
MapBufferRange = 0x00100000,
|
||||
Sized8Formats = 0x00200000,
|
||||
DiscardFramebuffer = 0x00400000,
|
||||
Sized16Formats = 0x00800000
|
||||
Sized16Formats = 0x00800000,
|
||||
TextureSwizzle = 0x01000000,
|
||||
};
|
||||
Q_DECLARE_FLAGS(OpenGLExtensions, OpenGLExtension)
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -263,7 +263,7 @@ GLuint QOpenGL2PaintEngineExPrivate::bindTexture(const QGradient &gradient)
|
||||
struct ImageWithBindOptions
|
||||
{
|
||||
const QImage ℑ
|
||||
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;
|
||||
|
@ -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);
|
||||
int cost = QOpenGLTextureUploader::textureImage(GL_TEXTURE_2D, image, options);
|
||||
|
||||
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 = 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);
|
||||
}
|
||||
|
@ -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
|
||||
|
303
src/gui/opengl/qopengltextureuploader.cpp
Normal file
303
src/gui/opengl/qopengltextureuploader.cpp
Normal file
@ -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
|
84
src/gui/opengl/qopengltextureuploader_p.h
Normal file
84
src/gui/opengl/qopengltextureuploader_p.h
Normal file
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user