1 /****************************************************************************
2 **
3 ** Copyright (C) 2018 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qopengltextureuploader_p.h"
41 
42 #include <qimage.h>
43 #include <qmath.h>
44 #include <qopenglfunctions.h>
45 #include <private/qopenglcontext_p.h>
46 #include <private/qopenglextensions_p.h>
47 
48 #ifndef GL_RED
49 #define GL_RED                            0x1903
50 #endif
51 
52 #ifndef GL_GREEN
53 #define GL_GREEN                          0x1904
54 #endif
55 
56 #ifndef GL_BLUE
57 #define GL_BLUE                           0x1905
58 #endif
59 
60 #ifndef GL_RGB10_A2
61 #define GL_RGB10_A2                       0x8059
62 #endif
63 
64 #ifndef GL_RGBA16
65 #define GL_RGBA16                         0x805B
66 #endif
67 
68 #ifndef GL_BGR
69 #define GL_BGR 0x80E0
70 #endif
71 
72 #ifndef GL_BGRA
73 #define GL_BGRA 0x80E1
74 #endif
75 
76 #ifndef GL_UNSIGNED_INT_8_8_8_8_REV
77 #define GL_UNSIGNED_INT_8_8_8_8_REV       0x8367
78 #endif
79 
80 #ifndef GL_UNSIGNED_INT_2_10_10_10_REV
81 #define GL_UNSIGNED_INT_2_10_10_10_REV    0x8368
82 #endif
83 
84 #ifndef GL_TEXTURE_SWIZZLE_R
85 #define GL_TEXTURE_SWIZZLE_R              0x8E42
86 #endif
87 
88 #ifndef GL_TEXTURE_SWIZZLE_G
89 #define GL_TEXTURE_SWIZZLE_G              0x8E43
90 #endif
91 
92 #ifndef GL_TEXTURE_SWIZZLE_B
93 #define GL_TEXTURE_SWIZZLE_B              0x8E44
94 #endif
95 
96 #ifndef GL_TEXTURE_SWIZZLE_A
97 #define GL_TEXTURE_SWIZZLE_A              0x8E45
98 #endif
99 
100 #ifndef GL_SRGB
101 #define GL_SRGB                           0x8C40
102 #endif
103 #ifndef GL_SRGB_ALPHA
104 #define GL_SRGB_ALPHA                     0x8C42
105 #endif
106 
107 QT_BEGIN_NAMESPACE
108 
textureImage(GLenum target,const QImage & image,QOpenGLTextureUploader::BindOptions options,QSize maxSize)109 qsizetype QOpenGLTextureUploader::textureImage(GLenum target, const QImage &image, QOpenGLTextureUploader::BindOptions options, QSize maxSize)
110 {
111     QOpenGLContext *context = QOpenGLContext::currentContext();
112     QOpenGLExtensions *funcs = static_cast<QOpenGLExtensions*>(context->functions());
113 
114     QImage tx;
115     GLenum externalFormat;
116     GLenum internalFormat;
117     GLuint pixelType;
118     QImage::Format targetFormat = QImage::Format_Invalid;
119     const bool isOpenGL12orBetter = !context->isOpenGLES() && (context->format().majorVersion() >= 2 || context->format().minorVersion() >= 2);
120     const bool isOpenGLES3orBetter = context->isOpenGLES() && context->format().majorVersion() >= 3;
121     const bool sRgbBinding = (options & SRgbBindOption);
122     Q_ASSERT(isOpenGL12orBetter || context->isOpenGLES());
123     Q_ASSERT((options & (SRgbBindOption | UseRedForAlphaAndLuminanceBindOption)) != (SRgbBindOption | UseRedForAlphaAndLuminanceBindOption));
124 
125     switch (image.format()) {
126     case QImage::Format_RGB32:
127     case QImage::Format_ARGB32:
128     case QImage::Format_ARGB32_Premultiplied:
129         if (isOpenGL12orBetter) {
130             externalFormat = GL_BGRA;
131             internalFormat = GL_RGBA;
132             pixelType = GL_UNSIGNED_INT_8_8_8_8_REV;
133 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
134         // Without GL_UNSIGNED_INT_8_8_8_8_REV, BGRA only matches ARGB on little endian:
135         } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::BGRATextureFormat) && !sRgbBinding) {
136             // The GL_EXT_texture_format_BGRA8888 extension requires the internal format to match the external.
137             externalFormat = internalFormat = GL_BGRA;
138             pixelType = GL_UNSIGNED_BYTE;
139         } else if (context->isOpenGLES() && context->hasExtension(QByteArrayLiteral("GL_APPLE_texture_format_BGRA8888"))) {
140             // Is only allowed as an external format like OpenGL.
141             externalFormat = GL_BGRA;
142             internalFormat = GL_RGBA;
143             pixelType = GL_UNSIGNED_BYTE;
144 #endif
145         } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) {
146 #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
147             funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
148             funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_RED);
149 #else
150             funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_GREEN);
151             funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_G, GL_BLUE);
152             funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_ALPHA);
153             funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_A, GL_RED);
154 #endif
155             externalFormat = internalFormat = GL_RGBA;
156             pixelType = GL_UNSIGNED_BYTE;
157         } else {
158             // No support for direct ARGB32 upload.
159             break;
160         }
161         targetFormat = image.format();
162         break;
163     case QImage::Format_BGR30:
164     case QImage::Format_A2BGR30_Premultiplied:
165         if (sRgbBinding) {
166             // Always needs conversion
167             break;
168         } else if (isOpenGL12orBetter || isOpenGLES3orBetter) {
169             pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
170             externalFormat = GL_RGBA;
171             internalFormat = GL_RGB10_A2;
172             targetFormat =  image.format();
173         }
174         break;
175     case QImage::Format_RGB30:
176     case QImage::Format_A2RGB30_Premultiplied:
177         if (sRgbBinding) {
178             // Always needs conversion
179             break;
180         } else if (isOpenGL12orBetter) {
181             pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
182             externalFormat = GL_BGRA;
183             internalFormat = GL_RGB10_A2;
184             targetFormat = image.format();
185         } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) {
186             funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_RED);
187             funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
188             pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
189             externalFormat = GL_RGBA;
190             internalFormat = GL_RGB10_A2;
191             targetFormat = image.format();
192         }
193         break;
194     case QImage::Format_RGB444:
195     case QImage::Format_RGB555:
196     case QImage::Format_RGB16:
197         if (isOpenGL12orBetter || context->isOpenGLES()) {
198             externalFormat = internalFormat = GL_RGB;
199             pixelType = GL_UNSIGNED_SHORT_5_6_5;
200             targetFormat = QImage::Format_RGB16;
201         }
202         break;
203     case QImage::Format_RGB666:
204     case QImage::Format_RGB888:
205         externalFormat = internalFormat = GL_RGB;
206         pixelType = GL_UNSIGNED_BYTE;
207         targetFormat = QImage::Format_RGB888;
208         break;
209     case QImage::Format_BGR888:
210         if (isOpenGL12orBetter) {
211             externalFormat = GL_BGR;
212             internalFormat = GL_RGB;
213             pixelType = GL_UNSIGNED_BYTE;
214             targetFormat = QImage::Format_BGR888;
215         } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) {
216             funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_RED);
217             funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
218             externalFormat = internalFormat = GL_RGB;
219             pixelType = GL_UNSIGNED_BYTE;
220             targetFormat = QImage::Format_BGR888;
221         }
222         break;
223     case QImage::Format_RGBX8888:
224     case QImage::Format_RGBA8888:
225     case QImage::Format_RGBA8888_Premultiplied:
226         externalFormat = internalFormat = GL_RGBA;
227         pixelType = GL_UNSIGNED_BYTE;
228         targetFormat = image.format();
229         break;
230     case QImage::Format_RGBX64:
231     case QImage::Format_RGBA64:
232     case QImage::Format_RGBA64_Premultiplied:
233         externalFormat = internalFormat = GL_RGBA;
234         if (isOpenGL12orBetter || (context->isOpenGLES() && context->format().majorVersion() >= 3))
235             internalFormat = GL_RGBA16;
236         pixelType = GL_UNSIGNED_SHORT;
237         targetFormat =  image.format();
238         break;
239     case QImage::Format_Indexed8:
240         if (sRgbBinding) {
241             // Always needs conversion
242             break;
243         } else if (options & UseRedForAlphaAndLuminanceBindOption) {
244             externalFormat = internalFormat = GL_RED;
245             pixelType = GL_UNSIGNED_BYTE;
246             targetFormat = image.format();
247         }
248         break;
249     case QImage::Format_Alpha8:
250         if (sRgbBinding) {
251             // Always needs conversion
252             break;
253         } else if (options & UseRedForAlphaAndLuminanceBindOption) {
254             externalFormat = internalFormat = GL_RED;
255             pixelType = GL_UNSIGNED_BYTE;
256             targetFormat = image.format();
257         } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) {
258             externalFormat = internalFormat = GL_ALPHA;
259             pixelType = GL_UNSIGNED_BYTE;
260             targetFormat = image.format();
261         } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) {
262             funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ALPHA);
263             funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_ZERO);
264             funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_ZERO);
265             funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ZERO);
266             externalFormat = internalFormat = GL_RED;
267             pixelType = GL_UNSIGNED_BYTE;
268             targetFormat = image.format();
269         }
270         break;
271     case QImage::Format_Grayscale8:
272         if (sRgbBinding) {
273             // Always needs conversion
274             break;
275         } else if (options & UseRedForAlphaAndLuminanceBindOption) {
276             externalFormat = internalFormat = GL_RED;
277             pixelType = GL_UNSIGNED_BYTE;
278             targetFormat = image.format();
279         } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) {
280             externalFormat = internalFormat = GL_LUMINANCE;
281             pixelType = GL_UNSIGNED_BYTE;
282             targetFormat = image.format();
283         } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) {
284             funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED);
285             funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED);
286             funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
287             funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE);
288             externalFormat = internalFormat = GL_RED;
289             pixelType = GL_UNSIGNED_BYTE;
290             targetFormat = image.format();
291         }
292         break;
293     case QImage::Format_Grayscale16:
294         if (sRgbBinding) {
295             // Always needs conversion
296             break;
297         } else if (options & UseRedForAlphaAndLuminanceBindOption) {
298             externalFormat = internalFormat = GL_RED;
299             pixelType = GL_UNSIGNED_SHORT;
300             targetFormat = image.format();
301         } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) {
302             externalFormat = internalFormat = GL_LUMINANCE;
303             pixelType = GL_UNSIGNED_SHORT;
304             targetFormat = image.format();
305         } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) {
306             funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED);
307             funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED);
308             funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
309             funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE);
310             externalFormat = internalFormat = GL_RED;
311             pixelType = GL_UNSIGNED_SHORT;
312             targetFormat = image.format();
313         }
314         break;
315     default:
316         break;
317     }
318 
319     // If no direct upload was detected above, convert to RGBA8888 and upload that
320     if (targetFormat == QImage::Format_Invalid) {
321         externalFormat = internalFormat = GL_RGBA;
322         pixelType = GL_UNSIGNED_BYTE;
323         if (!image.hasAlphaChannel())
324             targetFormat = QImage::Format_RGBX8888;
325         else
326             targetFormat = QImage::Format_RGBA8888;
327     }
328 
329     if (options & PremultipliedAlphaBindOption) {
330         if (targetFormat == QImage::Format_ARGB32)
331             targetFormat = QImage::Format_ARGB32_Premultiplied;
332         else if (targetFormat == QImage::Format_RGBA8888)
333             targetFormat = QImage::Format_RGBA8888_Premultiplied;
334         else if (targetFormat == QImage::Format_RGBA64)
335             targetFormat = QImage::Format_RGBA64_Premultiplied;
336     } else {
337         if (targetFormat == QImage::Format_ARGB32_Premultiplied)
338             targetFormat = QImage::Format_ARGB32;
339         else if (targetFormat == QImage::Format_RGBA8888_Premultiplied)
340             targetFormat = QImage::Format_RGBA8888;
341         else if (targetFormat == QImage::Format_RGBA64_Premultiplied)
342             targetFormat = QImage::Format_RGBA64;
343     }
344 
345     if (sRgbBinding) {
346         Q_ASSERT(internalFormat == GL_RGBA || internalFormat == GL_RGB);
347         if (image.hasAlphaChannel())
348             internalFormat = GL_SRGB_ALPHA;
349         else
350             internalFormat = GL_SRGB;
351     }
352 
353     if (image.format() != targetFormat)
354         tx = image.convertToFormat(targetFormat);
355     else
356         tx = image;
357 
358     QSize newSize = tx.size();
359     if (!maxSize.isEmpty())
360         newSize = newSize.boundedTo(maxSize);
361     if (options & PowerOfTwoBindOption) {
362         newSize.setWidth(qNextPowerOfTwo(newSize.width() - 1));
363         newSize.setHeight(qNextPowerOfTwo(newSize.height() - 1));
364     }
365 
366     if (newSize != tx.size())
367         tx = tx.scaled(newSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
368 
369     // Handle cases where the QImage is actually a sub image of its image data:
370     qsizetype naturalBpl = ((qsizetype(tx.width()) * tx.depth() + 31) >> 5) << 2;
371     if (tx.bytesPerLine() != naturalBpl)
372         tx = tx.copy(tx.rect());
373 
374     funcs->glTexImage2D(target, 0, internalFormat, tx.width(), tx.height(), 0, externalFormat, pixelType, tx.constBits());
375 
376     qsizetype cost = qint64(tx.width()) * tx.height() * tx.depth() / 8;
377 
378     return cost;
379 }
380 
381 QT_END_NAMESPACE
382