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

source code of qtbase/src/opengl/qopengltextureuploader.cpp