From f3ecda32e0f7bd21b44e7737d2939dcce2c26517 Mon Sep 17 00:00:00 2001 From: Johan Klokkhammer Helsing Date: Wed, 11 Dec 2019 14:50:40 +0100 Subject: Move QOpenGLPaintEngine and related classes from QtGui to QtOpenGL Also moves the openglwindow test to the opengl folder, as it makes use of these classes. Task-number: QTBUG-74409 Change-Id: Id9f0013cedcc8bd1e87122c005641d7298525045 Reviewed-by: Laszlo Agocs --- src/opengl/qopengltextureuploader.cpp | 381 ++++++++++++++++++++++++++++++++++ 1 file changed, 381 insertions(+) create mode 100644 src/opengl/qopengltextureuploader.cpp (limited to 'src/opengl/qopengltextureuploader.cpp') diff --git a/src/opengl/qopengltextureuploader.cpp b/src/opengl/qopengltextureuploader.cpp new file mode 100644 index 0000000000..469ddc56c1 --- /dev/null +++ b/src/opengl/qopengltextureuploader.cpp @@ -0,0 +1,381 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtOpenGL module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qopengltextureuploader_p.h" + +#include +#include +#include +#include +#include + +#ifndef GL_RED +#define GL_RED 0x1903 +#endif + +#ifndef GL_GREEN +#define GL_GREEN 0x1904 +#endif + +#ifndef GL_BLUE +#define GL_BLUE 0x1905 +#endif + +#ifndef GL_RGB10_A2 +#define GL_RGB10_A2 0x8059 +#endif + +#ifndef GL_RGBA16 +#define GL_RGBA16 0x805B +#endif + +#ifndef GL_BGR +#define GL_BGR 0x80E0 +#endif + +#ifndef GL_BGRA +#define GL_BGRA 0x80E1 +#endif + +#ifndef GL_UNSIGNED_INT_8_8_8_8_REV +#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367 +#endif + +#ifndef GL_UNSIGNED_INT_2_10_10_10_REV +#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 +#endif + +#ifndef GL_TEXTURE_SWIZZLE_R +#define GL_TEXTURE_SWIZZLE_R 0x8E42 +#endif + +#ifndef GL_TEXTURE_SWIZZLE_G +#define GL_TEXTURE_SWIZZLE_G 0x8E43 +#endif + +#ifndef GL_TEXTURE_SWIZZLE_B +#define GL_TEXTURE_SWIZZLE_B 0x8E44 +#endif + +#ifndef GL_TEXTURE_SWIZZLE_A +#define GL_TEXTURE_SWIZZLE_A 0x8E45 +#endif + +#ifndef GL_SRGB +#define GL_SRGB 0x8C40 +#endif +#ifndef GL_SRGB_ALPHA +#define GL_SRGB_ALPHA 0x8C42 +#endif + +QT_BEGIN_NAMESPACE + +qsizetype QOpenGLTextureUploader::textureImage(GLenum target, const QImage &image, QOpenGLTextureUploader::BindOptions options, QSize maxSize) +{ + QOpenGLContext *context = QOpenGLContext::currentContext(); + QOpenGLExtensions *funcs = static_cast(context->functions()); + + QImage tx; + GLenum externalFormat; + GLenum internalFormat; + GLuint pixelType; + QImage::Format targetFormat = QImage::Format_Invalid; + const bool isOpenGL12orBetter = !context->isOpenGLES() && (context->format().majorVersion() >= 2 || context->format().minorVersion() >= 2); + const bool isOpenGLES3orBetter = context->isOpenGLES() && context->format().majorVersion() >= 3; + const bool sRgbBinding = (options & SRgbBindOption); + Q_ASSERT(isOpenGL12orBetter || context->isOpenGLES()); + Q_ASSERT((options & (SRgbBindOption | UseRedForAlphaAndLuminanceBindOption)) != (SRgbBindOption | UseRedForAlphaAndLuminanceBindOption)); + + switch (image.format()) { + case QImage::Format_RGB32: + case QImage::Format_ARGB32: + case QImage::Format_ARGB32_Premultiplied: + if (isOpenGL12orBetter) { + externalFormat = GL_BGRA; + internalFormat = GL_RGBA; + pixelType = GL_UNSIGNED_INT_8_8_8_8_REV; +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + // Without GL_UNSIGNED_INT_8_8_8_8_REV, BGRA only matches ARGB on little endian: + } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::BGRATextureFormat) && !sRgbBinding) { + // The GL_EXT_texture_format_BGRA8888 extension requires the internal format to match the external. + externalFormat = internalFormat = GL_BGRA; + pixelType = GL_UNSIGNED_BYTE; + } else if (context->isOpenGLES() && context->hasExtension(QByteArrayLiteral("GL_APPLE_texture_format_BGRA8888"))) { + // Is only allowed as an external format like OpenGL. + externalFormat = GL_BGRA; + internalFormat = GL_RGBA; + pixelType = GL_UNSIGNED_BYTE; +#endif + } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) { +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_BLUE); + funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_RED); +#else + funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_GREEN); + funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_G, GL_BLUE); + funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_ALPHA); + funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_A, GL_RED); +#endif + externalFormat = internalFormat = GL_RGBA; + pixelType = GL_UNSIGNED_BYTE; + } else { + // No support for direct ARGB32 upload. + break; + } + targetFormat = image.format(); + break; + case QImage::Format_BGR30: + case QImage::Format_A2BGR30_Premultiplied: + if (sRgbBinding) { + // Always needs conversion + break; + } else if (isOpenGL12orBetter || isOpenGLES3orBetter) { + pixelType = GL_UNSIGNED_INT_2_10_10_10_REV; + externalFormat = GL_RGBA; + internalFormat = GL_RGB10_A2; + targetFormat = image.format(); + } + break; + case QImage::Format_RGB30: + case QImage::Format_A2RGB30_Premultiplied: + if (sRgbBinding) { + // Always needs conversion + break; + } else if (isOpenGL12orBetter) { + pixelType = GL_UNSIGNED_INT_2_10_10_10_REV; + externalFormat = GL_BGRA; + internalFormat = GL_RGB10_A2; + targetFormat = image.format(); + } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) { + funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_RED); + funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_BLUE); + pixelType = GL_UNSIGNED_INT_2_10_10_10_REV; + externalFormat = GL_RGBA; + internalFormat = GL_RGB10_A2; + targetFormat = image.format(); + } + break; + case QImage::Format_RGB444: + case QImage::Format_RGB555: + case QImage::Format_RGB16: + if (isOpenGL12orBetter || context->isOpenGLES()) { + externalFormat = internalFormat = GL_RGB; + pixelType = GL_UNSIGNED_SHORT_5_6_5; + targetFormat = QImage::Format_RGB16; + } + break; + case QImage::Format_RGB666: + case QImage::Format_RGB888: + externalFormat = internalFormat = GL_RGB; + pixelType = GL_UNSIGNED_BYTE; + targetFormat = QImage::Format_RGB888; + break; + case QImage::Format_BGR888: + if (isOpenGL12orBetter) { + externalFormat = GL_BGR; + internalFormat = GL_RGB; + pixelType = GL_UNSIGNED_BYTE; + targetFormat = QImage::Format_BGR888; + } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) { + funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_RED); + funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_BLUE); + externalFormat = internalFormat = GL_RGB; + pixelType = GL_UNSIGNED_BYTE; + targetFormat = QImage::Format_BGR888; + } + break; + case QImage::Format_RGBX8888: + case QImage::Format_RGBA8888: + case QImage::Format_RGBA8888_Premultiplied: + externalFormat = internalFormat = GL_RGBA; + pixelType = GL_UNSIGNED_BYTE; + targetFormat = image.format(); + break; + case QImage::Format_RGBX64: + case QImage::Format_RGBA64: + case QImage::Format_RGBA64_Premultiplied: + externalFormat = internalFormat = GL_RGBA; + if (isOpenGL12orBetter || (context->isOpenGLES() && context->format().majorVersion() >= 3)) + internalFormat = GL_RGBA16; + pixelType = GL_UNSIGNED_SHORT; + targetFormat = image.format(); + break; + case QImage::Format_Indexed8: + if (sRgbBinding) { + // Always needs conversion + break; + } else if (options & UseRedForAlphaAndLuminanceBindOption) { + externalFormat = internalFormat = GL_RED; + pixelType = GL_UNSIGNED_BYTE; + targetFormat = image.format(); + } + break; + case QImage::Format_Alpha8: + if (sRgbBinding) { + // Always needs conversion + break; + } else if (options & UseRedForAlphaAndLuminanceBindOption) { + externalFormat = internalFormat = GL_RED; + pixelType = GL_UNSIGNED_BYTE; + targetFormat = image.format(); + } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) { + externalFormat = internalFormat = GL_ALPHA; + pixelType = GL_UNSIGNED_BYTE; + targetFormat = image.format(); + } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) { + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ALPHA); + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_ZERO); + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_ZERO); + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ZERO); + externalFormat = internalFormat = GL_RED; + pixelType = GL_UNSIGNED_BYTE; + targetFormat = image.format(); + } + break; + case QImage::Format_Grayscale8: + if (sRgbBinding) { + // Always needs conversion + break; + } else if (options & UseRedForAlphaAndLuminanceBindOption) { + externalFormat = internalFormat = GL_RED; + pixelType = GL_UNSIGNED_BYTE; + targetFormat = image.format(); + } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) { + externalFormat = internalFormat = GL_LUMINANCE; + pixelType = GL_UNSIGNED_BYTE; + targetFormat = image.format(); + } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) { + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED); + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED); + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE); + externalFormat = internalFormat = GL_RED; + pixelType = GL_UNSIGNED_BYTE; + targetFormat = image.format(); + } + break; + case QImage::Format_Grayscale16: + if (sRgbBinding) { + // Always needs conversion + break; + } else if (options & UseRedForAlphaAndLuminanceBindOption) { + externalFormat = internalFormat = GL_RED; + pixelType = GL_UNSIGNED_SHORT; + targetFormat = image.format(); + } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) { + externalFormat = internalFormat = GL_LUMINANCE; + pixelType = GL_UNSIGNED_SHORT; + targetFormat = image.format(); + } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) { + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED); + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED); + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED); + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE); + externalFormat = internalFormat = GL_RED; + pixelType = GL_UNSIGNED_SHORT; + targetFormat = image.format(); + } + break; + default: + break; + } + + // If no direct upload was detected above, convert to RGBA8888 and upload that + if (targetFormat == QImage::Format_Invalid) { + externalFormat = internalFormat = GL_RGBA; + pixelType = GL_UNSIGNED_BYTE; + if (!image.hasAlphaChannel()) + targetFormat = QImage::Format_RGBX8888; + else + targetFormat = QImage::Format_RGBA8888; + } + + if (options & PremultipliedAlphaBindOption) { + if (targetFormat == QImage::Format_ARGB32) + targetFormat = QImage::Format_ARGB32_Premultiplied; + else if (targetFormat == QImage::Format_RGBA8888) + targetFormat = QImage::Format_RGBA8888_Premultiplied; + else if (targetFormat == QImage::Format_RGBA64) + targetFormat = QImage::Format_RGBA64_Premultiplied; + } else { + if (targetFormat == QImage::Format_ARGB32_Premultiplied) + targetFormat = QImage::Format_ARGB32; + else if (targetFormat == QImage::Format_RGBA8888_Premultiplied) + targetFormat = QImage::Format_RGBA8888; + else if (targetFormat == QImage::Format_RGBA64_Premultiplied) + targetFormat = QImage::Format_RGBA64; + } + + if (sRgbBinding) { + Q_ASSERT(internalFormat == GL_RGBA || internalFormat == GL_RGB); + if (image.hasAlphaChannel()) + internalFormat = GL_SRGB_ALPHA; + else + internalFormat = GL_SRGB; + } + + if (image.format() != targetFormat) + tx = image.convertToFormat(targetFormat); + else + tx = image; + + QSize newSize = tx.size(); + if (!maxSize.isEmpty()) + newSize = newSize.boundedTo(maxSize); + if (options & PowerOfTwoBindOption) { + newSize.setWidth(qNextPowerOfTwo(newSize.width() - 1)); + newSize.setHeight(qNextPowerOfTwo(newSize.height() - 1)); + } + + if (newSize != tx.size()) + tx = tx.scaled(newSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); + + // Handle cases where the QImage is actually a sub image of its image data: + qsizetype naturalBpl = ((qsizetype(tx.width()) * tx.depth() + 31) >> 5) << 2; + if (tx.bytesPerLine() != naturalBpl) + tx = tx.copy(tx.rect()); + + funcs->glTexImage2D(target, 0, internalFormat, tx.width(), tx.height(), 0, externalFormat, pixelType, tx.constBits()); + + qsizetype cost = qint64(tx.width()) * tx.height() * tx.depth() / 8; + + return cost; +} + +QT_END_NAMESPACE -- cgit v1.2.3