Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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
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
84
85qsizetype QOpenGLTextureUploader::textureImage(GLenum target, const QImage &image, QOpenGLTextureUploader::BindOptions options, QSize maxSize)
86{
88 QOpenGLExtensions *funcs = static_cast<QOpenGLExtensions*>(context->functions());
89
90 QImage tx;
91 GLenum externalFormat;
93 GLuint pixelType;
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());
100
101 switch (image.format()) {
105 if (isOpenGL12orBetter) {
106 externalFormat = GL_BGRA;
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(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;
119 pixelType = GL_UNSIGNED_BYTE;
120#endif
121 } else if (funcs->hasOpenGLExtension(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;
141 if (sRgbBinding) {
142 // Always needs conversion
143 break;
144 } else if (isOpenGL12orBetter || isOpenGLES3orBetter) {
146 externalFormat = GL_RGBA;
148 targetFormat = image.format();
149 }
150 break;
153 if (sRgbBinding) {
154 // Always needs conversion
155 break;
156 } else if (isOpenGL12orBetter) {
158 externalFormat = GL_BGRA;
160 targetFormat = image.format();
161 } else if (funcs->hasOpenGLExtension(QOpenGLExtensions::TextureSwizzle)) {
162 funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_RED);
163 funcs->glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_BLUE);
165 externalFormat = GL_RGBA;
167 targetFormat = image.format();
168 }
169 break;
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;
181 externalFormat = internalFormat = GL_RGB;
182 pixelType = GL_UNSIGNED_BYTE;
183 targetFormat = QImage::Format_RGB888;
184 break;
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(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;
202 externalFormat = internalFormat = GL_RGBA;
203 pixelType = GL_UNSIGNED_BYTE;
204 targetFormat = image.format();
205 break;
209 externalFormat = internalFormat = GL_RGBA;
210 if (isOpenGL12orBetter || (context->isOpenGLES() && context->format().majorVersion() >= 3))
212 pixelType = GL_UNSIGNED_SHORT;
213 targetFormat = image.format();
214 break;
218 if (context->format().majorVersion() >= 3) {
219 externalFormat = GL_RGBA;
221 pixelType = GL_HALF_FLOAT;
222 targetFormat = image.format();
223 }
224 break;
228 externalFormat = internalFormat = GL_RGBA;
229 if (context->format().majorVersion() >= 3)
231 pixelType = GL_FLOAT;
232 targetFormat = image.format();
233 break;
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;
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(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;
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(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;
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(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)
327 else if (targetFormat == QImage::Format_RGBA8888)
329 else if (targetFormat == QImage::Format_RGBA64)
331 else if (targetFormat == QImage::Format_RGBA16FPx4)
333 else if (targetFormat == QImage::Format_RGBA32FPx4)
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) {
350 if (image.hasAlphaChannel())
352 else
354 }
355
356 if (image.format() != targetFormat)
357 tx = image.convertToFormat(targetFormat);
358 else
359 tx = image;
360
361 QSize newSize = tx.size();
362 if (!maxSize.isEmpty())
363 newSize = newSize.boundedTo(maxSize);
364 if (options & PowerOfTwoBindOption) {
365 newSize.setWidth(qNextPowerOfTwo(newSize.width() - 1));
366 newSize.setHeight(qNextPowerOfTwo(newSize.height() - 1));
367 }
368
369 if (newSize != tx.size())
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(tx.rect());
376
377 funcs->glTexImage2D(target, 0, internalFormat, tx.width(), tx.height(), 0, externalFormat, pixelType, tx.constBits());
378
379 qsizetype cost = qint64(tx.width()) * tx.height() * tx.depth() / 8;
380
381 return cost;
382}
383
\inmodule QtGui
Definition qimage.h:37
QImage scaled(int w, int h, Qt::AspectRatioMode aspectMode=Qt::IgnoreAspectRatio, Qt::TransformationMode mode=Qt::FastTransformation) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qimage.h:209
qsizetype bytesPerLine() const
Returns the number of bytes per image scanline.
Definition qimage.cpp:1560
QImage copy(const QRect &rect=QRect()) const
Returns a sub-area of the image as a new image.
QSize size() const
Returns the size of the image, i.e.
int width() const
Returns the width of the image.
int height() const
Returns the height of the image.
Format
The following image formats are available in Qt.
Definition qimage.h:41
@ Format_Grayscale16
Definition qimage.h:70
@ Format_Alpha8
Definition qimage.h:65
@ Format_RGBA8888
Definition qimage.h:59
@ Format_RGB30
Definition qimage.h:63
@ Format_RGB888
Definition qimage.h:55
@ Format_RGBA16FPx4
Definition qimage.h:73
@ Format_RGBA32FPx4_Premultiplied
Definition qimage.h:77
@ Format_RGB32
Definition qimage.h:46
@ Format_Invalid
Definition qimage.h:42
@ Format_RGB666
Definition qimage.h:51
@ Format_RGBX32FPx4
Definition qimage.h:75
@ Format_RGBA64_Premultiplied
Definition qimage.h:69
@ Format_RGB444
Definition qimage.h:56
@ Format_RGBA8888_Premultiplied
Definition qimage.h:60
@ Format_RGB555
Definition qimage.h:53
@ Format_RGBA64
Definition qimage.h:68
@ Format_RGBA32FPx4
Definition qimage.h:76
@ Format_RGBA16FPx4_Premultiplied
Definition qimage.h:74
@ Format_RGBX64
Definition qimage.h:67
@ Format_A2BGR30_Premultiplied
Definition qimage.h:62
@ Format_RGBX16FPx4
Definition qimage.h:72
@ Format_Indexed8
Definition qimage.h:45
@ Format_BGR30
Definition qimage.h:61
@ Format_ARGB32_Premultiplied
Definition qimage.h:48
@ Format_A2RGB30_Premultiplied
Definition qimage.h:64
@ Format_RGB16
Definition qimage.h:49
@ Format_BGR888
Definition qimage.h:71
@ Format_ARGB32
Definition qimage.h:47
@ Format_RGBX8888
Definition qimage.h:58
@ Format_Grayscale8
Definition qimage.h:66
QRect rect() const
Returns the enclosing rectangle (0, 0, width(), height()) of the image.
const uchar * constBits() const
Returns a pointer to the first pixel data.
Definition qimage.cpp:1733
int depth() const
\inmodule QtGui
static QOpenGLContext * currentContext()
Returns the last context which called makeCurrent in the current thread, or \nullptr,...
static qsizetype textureImage(GLenum target, const QImage &image, BindOptions options, QSize maxSize=QSize())
\inmodule QtCore
Definition qsize.h:25
constexpr QSize boundedTo(const QSize &) const noexcept
Returns a size holding the minimum width and height of this size and the given otherSize.
Definition qsize.h:197
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:133
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:130
constexpr void setWidth(int w) noexcept
Sets the width to the given width.
Definition qsize.h:136
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
Definition qsize.h:124
constexpr void setHeight(int h) noexcept
Sets the height to the given height.
Definition qsize.h:139
static VulkanServerBufferGlFunctions * funcs
Combined button and popup list for selecting options.
@ SmoothTransformation
@ IgnoreAspectRatio
Definition image.cpp:4
static void * context
#define QByteArrayLiteral(str)
Definition qbytearray.h:52
constexpr quint32 qNextPowerOfTwo(quint32 v)
Definition qmath.h:335
typedef GLenum(GL_APIENTRYP PFNGLGETGRAPHICSRESETSTATUSKHRPROC)(void)
GLenum target
GLsizei GLenum internalFormat
#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_UNSIGNED_SHORT_5_6_5
Definition qopenglext.h:90
#define GL_TEXTURE_SWIZZLE_R
#define GL_RGBA16
#define GL_BLUE
#define GL_GREEN
static qsizetype cost(const QPixmap &pixmap)
#define GL_UNSIGNED_INT_2_10_10_10_REV
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define GL_RED
#define GLuint
#define GL_FLOAT
#define GL_UNSIGNED_BYTE
#define GL_RGBA
ptrdiff_t qsizetype
Definition qtypes.h:165
long long qint64
Definition qtypes.h:60