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_BGRA
69#define GL_BGRA 0x80E1
70#endif
71
72#ifndef GL_UNSIGNED_INT_8_8_8_8_REV
73#define GL_UNSIGNED_INT_8_8_8_8_REV 0x8367
74#endif
75
76#ifndef GL_UNSIGNED_INT_2_10_10_10_REV
77#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
78#endif
79
80#ifndef GL_TEXTURE_SWIZZLE_R
81#define GL_TEXTURE_SWIZZLE_R 0x8E42
82#endif
83
84#ifndef GL_TEXTURE_SWIZZLE_G
85#define GL_TEXTURE_SWIZZLE_G 0x8E43
86#endif
87
88#ifndef GL_TEXTURE_SWIZZLE_B
89#define GL_TEXTURE_SWIZZLE_B 0x8E44
90#endif
91
92#ifndef GL_TEXTURE_SWIZZLE_A
93#define GL_TEXTURE_SWIZZLE_A 0x8E45
94#endif
95
96#ifndef GL_SRGB
97#define GL_SRGB 0x8C40
98#endif
99#ifndef GL_SRGB_ALPHA
100#define GL_SRGB_ALPHA 0x8C42
101#endif
102
103QT_BEGIN_NAMESPACE
104
105qsizetype QOpenGLTextureUploader::textureImage(GLenum target, const QImage &image, QOpenGLTextureUploader::BindOptions options, QSize maxSize)
106{
107 QOpenGLContext *context = QOpenGLContext::currentContext();
108 QOpenGLExtensions *funcs = static_cast<QOpenGLExtensions*>(context->functions());
109
110 QImage tx;
111 GLenum externalFormat;
112 GLenum internalFormat;
113 GLuint pixelType;
114 QImage::Format targetFormat = QImage::Format_Invalid;
115 const bool isOpenGL12orBetter = !context->isOpenGLES() && (context->format().majorVersion() >= 2 || context->format().minorVersion() >= 2);
116 const bool isOpenGLES3orBetter = context->isOpenGLES() && context->format().majorVersion() >= 3;
117 const bool sRgbBinding = (options & SRgbBindOption);
118 Q_ASSERT(isOpenGL12orBetter || context->isOpenGLES());
119 Q_ASSERT((options & (SRgbBindOption | UseRedForAlphaAndLuminanceBindOption)) != (SRgbBindOption | UseRedForAlphaAndLuminanceBindOption));
120
121 switch (image.format()) {
122 case QImage::Format_RGB32:
123 case QImage::Format_ARGB32:
124 case QImage::Format_ARGB32_Premultiplied:
125 if (isOpenGL12orBetter) {
126 externalFormat = GL_BGRA;
127 internalFormat = GL_RGBA;
128 pixelType = GL_UNSIGNED_INT_8_8_8_8_REV;
129#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
130 // Without GL_UNSIGNED_INT_8_8_8_8_REV, BGRA only matches ARGB on little endian:
131 } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::BGRATextureFormat) && !sRgbBinding) {
132 // The GL_EXT_texture_format_BGRA8888 extension requires the internal format to match the external.
133 externalFormat = internalFormat = GL_BGRA;
134 pixelType = GL_UNSIGNED_BYTE;
135 } else if (context->isOpenGLES() && context->hasExtension(QByteArrayLiteral("GL_APPLE_texture_format_BGRA8888"))) {
136 // Is only allowed as an external format like OpenGL.
137 externalFormat = GL_BGRA;
138 internalFormat = GL_RGBA;
139 pixelType = GL_UNSIGNED_BYTE;
140#endif
141 } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) {
142#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
143 funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
144 funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_RED);
145#else
146 funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_GREEN);
147 funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_G, GL_BLUE);
148 funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_ALPHA);
149 funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_A, GL_RED);
150#endif
151 externalFormat = internalFormat = GL_RGBA;
152 pixelType = GL_UNSIGNED_BYTE;
153 } else {
154 // No support for direct ARGB32 upload.
155 break;
156 }
157 targetFormat = image.format();
158 break;
159 case QImage::Format_BGR30:
160 case QImage::Format_A2BGR30_Premultiplied:
161 if (sRgbBinding) {
162 // Always needs conversion
163 break;
164 } else if (isOpenGL12orBetter || isOpenGLES3orBetter) {
165 pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
166 externalFormat = GL_RGBA;
167 internalFormat = GL_RGB10_A2;
168 targetFormat = image.format();
169 }
170 break;
171 case QImage::Format_RGB30:
172 case QImage::Format_A2RGB30_Premultiplied:
173 if (sRgbBinding) {
174 // Always needs conversion
175 break;
176 } else if (isOpenGL12orBetter) {
177 pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
178 externalFormat = GL_BGRA;
179 internalFormat = GL_RGB10_A2;
180 targetFormat = image.format();
181 } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) {
182 funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_RED);
183 funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
184 pixelType = GL_UNSIGNED_INT_2_10_10_10_REV;
185 externalFormat = GL_RGBA;
186 internalFormat = GL_RGB10_A2;
187 targetFormat = image.format();
188 }
189 break;
190 case QImage::Format_RGB444:
191 case QImage::Format_RGB555:
192 case QImage::Format_RGB16:
193 if (isOpenGL12orBetter || context->isOpenGLES()) {
194 externalFormat = internalFormat = GL_RGB;
195 pixelType = GL_UNSIGNED_SHORT_5_6_5;
196 targetFormat = QImage::Format_RGB16;
197 }
198 break;
199 case QImage::Format_RGB666:
200 case QImage::Format_RGB888:
201 externalFormat = internalFormat = GL_RGB;
202 pixelType = GL_UNSIGNED_BYTE;
203 targetFormat = QImage::Format_RGB888;
204 break;
205 case QImage::Format_RGBX8888:
206 case QImage::Format_RGBA8888:
207 case QImage::Format_RGBA8888_Premultiplied:
208 externalFormat = internalFormat = GL_RGBA;
209 pixelType = GL_UNSIGNED_BYTE;
210 targetFormat = image.format();
211 break;
212 case QImage::Format_RGBX64:
213 case QImage::Format_RGBA64:
214 case QImage::Format_RGBA64_Premultiplied:
215 externalFormat = internalFormat = GL_RGBA;
216 if (isOpenGL12orBetter || (context->isOpenGLES() && context->format().majorVersion() >= 3))
217 internalFormat = GL_RGBA16;
218 pixelType = GL_UNSIGNED_SHORT;
219 targetFormat = image.format();
220 break;
221 case QImage::Format_Indexed8:
222 if (sRgbBinding) {
223 // Always needs conversion
224 break;
225 } else if (options & UseRedForAlphaAndLuminanceBindOption) {
226 externalFormat = internalFormat = GL_RED;
227 pixelType = GL_UNSIGNED_BYTE;
228 targetFormat = image.format();
229 }
230 break;
231 case QImage::Format_Alpha8:
232 if (sRgbBinding) {
233 // Always needs conversion
234 break;
235 } else if (options & UseRedForAlphaAndLuminanceBindOption) {
236 externalFormat = internalFormat = GL_RED;
237 pixelType = GL_UNSIGNED_BYTE;
238 targetFormat = image.format();
239 } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) {
240 externalFormat = internalFormat = GL_ALPHA;
241 pixelType = GL_UNSIGNED_BYTE;
242 targetFormat = image.format();
243 } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) {
244 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_ALPHA);
245 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_ZERO);
246 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_ZERO);
247 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ZERO);
248 externalFormat = internalFormat = GL_RED;
249 pixelType = GL_UNSIGNED_BYTE;
250 targetFormat = image.format();
251 }
252 break;
253 case QImage::Format_Grayscale8:
254 if (sRgbBinding) {
255 // Always needs conversion
256 break;
257 } else if (options & UseRedForAlphaAndLuminanceBindOption) {
258 externalFormat = internalFormat = GL_RED;
259 pixelType = GL_UNSIGNED_BYTE;
260 targetFormat = image.format();
261 } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) {
262 externalFormat = internalFormat = GL_LUMINANCE;
263 pixelType = GL_UNSIGNED_BYTE;
264 targetFormat = image.format();
265 } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) {
266 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED);
267 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED);
268 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
269 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE);
270 externalFormat = internalFormat = GL_RED;
271 pixelType = GL_UNSIGNED_BYTE;
272 targetFormat = image.format();
273 }
274 break;
275 case QImage::Format_Grayscale16:
276 if (sRgbBinding) {
277 // Always needs conversion
278 break;
279 } else if (options & UseRedForAlphaAndLuminanceBindOption) {
280 externalFormat = internalFormat = GL_RED;
281 pixelType = GL_UNSIGNED_SHORT;
282 targetFormat = image.format();
283 } else if (context->isOpenGLES() || context->format().profile() != QSurfaceFormat::CoreProfile) {
284 externalFormat = internalFormat = GL_LUMINANCE;
285 pixelType = GL_UNSIGNED_SHORT;
286 targetFormat = image.format();
287 } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) {
288 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED);
289 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED);
290 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);
291 funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_ONE);
292 externalFormat = internalFormat = GL_RED;
293 pixelType = GL_UNSIGNED_SHORT;
294 targetFormat = image.format();
295 }
296 break;
297 default:
298 break;
299 }
300
301 // If no direct upload was detected above, convert to RGBA8888 and upload that
302 if (targetFormat == QImage::Format_Invalid) {
303 externalFormat = internalFormat = GL_RGBA;
304 pixelType = GL_UNSIGNED_BYTE;
305 if (!image.hasAlphaChannel())
306 targetFormat = QImage::Format_RGBX8888;
307 else
308 targetFormat = QImage::Format_RGBA8888;
309 }
310
311 if (options & PremultipliedAlphaBindOption) {
312 if (targetFormat == QImage::Format_ARGB32)
313 targetFormat = QImage::Format_ARGB32_Premultiplied;
314 else if (targetFormat == QImage::Format_RGBA8888)
315 targetFormat = QImage::Format_RGBA8888_Premultiplied;
316 else if (targetFormat == QImage::Format_RGBA64)
317 targetFormat = QImage::Format_RGBA64_Premultiplied;
318 } else {
319 if (targetFormat == QImage::Format_ARGB32_Premultiplied)
320 targetFormat = QImage::Format_ARGB32;
321 else if (targetFormat == QImage::Format_RGBA8888_Premultiplied)
322 targetFormat = QImage::Format_RGBA8888;
323 else if (targetFormat == QImage::Format_RGBA64_Premultiplied)
324 targetFormat = QImage::Format_RGBA64;
325 }
326
327 if (sRgbBinding) {
328 Q_ASSERT(internalFormat == GL_RGBA || internalFormat == GL_RGB);
329 if (image.hasAlphaChannel())
330 internalFormat = GL_SRGB_ALPHA;
331 else
332 internalFormat = GL_SRGB;
333 }
334
335 if (image.format() != targetFormat)
336 tx = image.convertToFormat(targetFormat);
337 else
338 tx = image;
339
340 QSize newSize = tx.size();
341 if (!maxSize.isEmpty())
342 newSize = newSize.boundedTo(maxSize);
343 if (options & PowerOfTwoBindOption) {
344 newSize.setWidth(qNextPowerOfTwo(newSize.width() - 1));
345 newSize.setHeight(qNextPowerOfTwo(newSize.height() - 1));
346 }
347
348 if (newSize != tx.size())
349 tx = tx.scaled(newSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
350
351 // Handle cases where the QImage is actually a sub image of its image data:
352 qsizetype naturalBpl = ((qsizetype(tx.width()) * tx.depth() + 31) >> 5) << 2;
353 if (tx.bytesPerLine() != naturalBpl)
354 tx = tx.copy(tx.rect());
355
356 funcs->glTexImage2D(target, 0, internalFormat, tx.width(), tx.height(), 0, externalFormat, pixelType, tx.constBits());
357
358 qsizetype cost = qint64(tx.width()) * tx.height() * tx.depth() / 8;
359
360 return cost;
361}
362
363QT_END_NAMESPACE
364