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
107QT_BEGIN_NAMESPACE
108
109qsizetype 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(extension: 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(extension: 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(extension: 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(extension: 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(extension: 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(extension: 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(extension: 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(f: targetFormat);
355 else
356 tx = image;
357
358 QSize newSize = tx.size();
359 if (!maxSize.isEmpty())
360 newSize = newSize.boundedTo(otherSize: maxSize);
361 if (options & PowerOfTwoBindOption) {
362 newSize.setWidth(qNextPowerOfTwo(v: newSize.width() - 1));
363 newSize.setHeight(qNextPowerOfTwo(v: newSize.height() - 1));
364 }
365
366 if (newSize != tx.size())
367 tx = tx.scaled(s: newSize, aspectMode: Qt::IgnoreAspectRatio, mode: 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(rect: tx.rect());
373
374 funcs->glTexImage2D(target, level: 0, internalformat: internalFormat, width: tx.width(), height: tx.height(), border: 0, format: externalFormat, type: pixelType, pixels: tx.constBits());
375
376 qsizetype cost = qint64(tx.width()) * tx.height() * tx.depth() / 8;
377
378 return cost;
379}
380
381QT_END_NAMESPACE
382

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