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