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
qplatformgraphicsbufferhelper.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 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
5#include <QtGui/qpa/qplatformgraphicsbuffer.h>
6
8#include <QtCore/QDebug>
9#include <QtGui/qopengl.h>
10#include <QtGui/QImage>
11#include <QtGui/QOpenGLContext>
12#include <QtGui/QOpenGLFunctions>
13
14#ifndef GL_UNPACK_ROW_LENGTH
15#define GL_UNPACK_ROW_LENGTH 0x0CF2
16#endif
17
18#ifndef GL_RGB10_A2
19#define GL_RGB10_A2 0x8059
20#endif
21
22#ifndef GL_UNSIGNED_INT_2_10_10_10_REV
23#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368
24#endif
25
27
28/*!
29 \namespace QPlatformGraphicsBufferHelper
30 \inmodule QtGui
31 \internal
32*/
33
34/*!
35 Convenience function to both lock and bind the \a graphicsBuffer to a texture.
36 This function will first try to lock with texture read and texture write
37 access. If this succeeds it will use the bindToTexture function to bind the
38 content to the currently bound texture, and if \a premultiplied is provided,
39 it is set to false.
40
41 If it fails, it will try to lock with SWReadAccess and then use the
42 bindSWToTexture convenience function. If \a premultiplied is provided, it is
43 passed to the bindSWToTexture() function.
44
45 \a swizzle is meant to be used by the caller to figure out if the Red and
46 Blue color channels need to be swizzled when rendering.
47
48 \a rect is the subrect which is desired to be bounded to the texture. This
49 argument has a not less than semantic, meaning more (if not all) of the buffer
50 can be bounded to the texture. An empty QRect is interpreted as entire buffer
51 should be bound.
52
53 The user should use the AccessTypes returned by isLocked to figure out what
54 lock has been obtained.
55
56 Returns true if the buffer has successfully been bound to the currently
57 bound texture, otherwise returns false.
58*/
59bool QPlatformGraphicsBufferHelper::lockAndBindToTexture(QPlatformGraphicsBuffer *graphicsBuffer,
60 bool *swizzle, bool *premultiplied,
61 const QRect &rect)
62{
63 if (graphicsBuffer->lock(QPlatformGraphicsBuffer::TextureAccess)) {
64 if (!graphicsBuffer->bindToTexture(rect)) {
65 qWarning("Failed to bind %sgraphicsbuffer to texture", "");
66 return false;
67 }
68 if (swizzle)
69 *swizzle = false;
70 if (premultiplied)
71 *premultiplied = false;
72 } else if (graphicsBuffer->lock(QPlatformGraphicsBuffer::SWReadAccess)) {
73 if (!bindSWToTexture(graphicsBuffer, swizzle, premultiplied, rect)) {
74 qWarning("Failed to bind %sgraphicsbuffer to texture", "SW ");
75 return false;
76 }
77 } else {
78 qWarning("Failed to lock");
79 return false;
80 }
81 return true;
82}
83
84/*!
85 Convenience function that uploads the current raster content to the currently
86 bound texture.
87
88 \a swizzleRandB is meant to be used by the caller to decide if the Red and
89 Blue color channels need to be swizzled when rendering. This is an
90 optimization. Qt often renders to software buffers interpreting pixels as
91 unsigned ints. When these buffers are uploaded to textures and each color
92 channel per pixel is interpreted as a byte (read sequentially), then the
93 Red and Blue channels are swapped. Conveniently, the Alpha buffer will be
94 correct, since Qt historically has had the alpha channel as the first
95 channel, while OpenGL typically expects the alpha channel to be the last
96 channel.
97
98 \a subRect is the region to be bound to the texture. This argument has a
99 not less than semantic, meaning more (if not all) of the buffer can be
100 bound to the texture. An empty QRect is interpreted as meaning the entire
101 buffer should be bound.
102
103 This function fails if the \a graphicsBuffer is not locked to SWAccess.
104
105 Returns true on success, otherwise false. If \a premultipliedB is
106 provided, it is set according to what happens, if the function returns
107 true.
108*/
109bool QPlatformGraphicsBufferHelper::bindSWToTexture(const QPlatformGraphicsBuffer *graphicsBuffer,
110 bool *swizzleRandB, bool *premultipliedB,
111 const QRect &subRect)
112{
113#ifndef QT_NO_OPENGL
114 QOpenGLContext *ctx = QOpenGLContext::currentContext();
115 if (!ctx)
116 return false;
117
118 if (!(graphicsBuffer->isLocked() & QPlatformGraphicsBuffer::SWReadAccess))
119 return false;
120
121 QSize size = graphicsBuffer->size();
122
123 Q_ASSERT(subRect.isEmpty() || QRect(QPoint(0,0), size).contains(subRect));
124
125 GLenum internalFormat = GL_RGBA;
126 GLuint pixelType = GL_UNSIGNED_BYTE;
127
128 bool needsConversion = false;
129 bool swizzle = false;
130 bool premultiplied = false;
131 QImage::Format imageformat = QImage::toImageFormat(graphicsBuffer->format());
132 QImage image(graphicsBuffer->data(), size.width(), size.height(), graphicsBuffer->bytesPerLine(), imageformat);
133 switch (imageformat) {
134 case QImage::Format_ARGB32_Premultiplied:
135 premultiplied = true;
136 Q_FALLTHROUGH();
137 case QImage::Format_RGB32:
138 case QImage::Format_ARGB32:
139 swizzle = true;
140 break;
141 case QImage::Format_RGBA8888_Premultiplied:
142 premultiplied = true;
143 Q_FALLTHROUGH();
144 case QImage::Format_RGBX8888:
145 case QImage::Format_RGBA8888:
146 break;
147 case QImage::Format_BGR30:
148 case QImage::Format_A2BGR30_Premultiplied:
149 if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
151 internalFormat = GL_RGB10_A2;
152 premultiplied = true;
153 } else {
154 needsConversion = true;
155 }
156 break;
157 case QImage::Format_RGB30:
158 case QImage::Format_A2RGB30_Premultiplied:
159 if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
161 internalFormat = GL_RGB10_A2;
162 premultiplied = true;
163 swizzle = true;
164 } else {
165 needsConversion = true;
166 }
167 break;
168 default:
169 needsConversion = true;
170 break;
171 }
172 if (!needsConversion && image.bytesPerLine() != (size.width() * 4) && ctx->isOpenGLES() && ctx->format().majorVersion() < 3)
173 needsConversion = true;
174 if (needsConversion)
175 image.convertTo(QImage::Format_RGBA8888);
176
177 bool needsRowLength = (image.bytesPerLine() != image.width() * 4);
178 QOpenGLFunctions *funcs = ctx->functions();
179
180 QRect rect = subRect;
181 if (rect.isNull() || rect == QRect(QPoint(0,0),size)) {
182 if (needsRowLength)
183 funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, GLint(image.bytesPerLine() / 4));
184 funcs->glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, size.width(), size.height(), 0, GL_RGBA, pixelType, image.constBits());
185 if (needsRowLength)
186 funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
187 } else {
188 if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
189 // OpenGL 2.1+ or OpenGL ES/3+
190 funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, GLint(image.bytesPerLine() / 4));
191 funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, pixelType,
192 image.constScanLine(rect.y()) + rect.x() * 4);
193 funcs->glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
194 } else
195 {
196 // if the rect is wide enough it's cheaper to just
197 // extend it instead of doing an image copy
198 if (rect.width() >= size.width() / 2) {
199 rect.setX(0);
200 rect.setWidth(size.width());
201 }
202
203 // if the sub-rect is full-width we can pass the image data directly to
204 // OpenGL instead of copying, since there's no gap between scanlines
205
206 if (rect.width() == image.bytesPerLine() / 4) {
207 funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, pixelType,
208 image.constScanLine(rect.y()));
209 } else {
210 funcs->glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, pixelType,
211 image.copy(rect).constBits());
212 }
213 }
214 }
215 if (swizzleRandB)
216 *swizzleRandB = swizzle;
217 if (premultipliedB)
218 *premultipliedB = premultiplied;
219
220 return true;
221
222#else
223 Q_UNUSED(graphicsBuffer);
224 Q_UNUSED(swizzleRandB);
225 Q_UNUSED(premultipliedB);
226 Q_UNUSED(subRect);
227 return false;
228#endif // QT_NO_OPENGL
229}
230
231QT_END_NAMESPACE
Q_GUI_EXPORT bool lockAndBindToTexture(QPlatformGraphicsBuffer *graphicsBuffer, bool *swizzleRandB, bool *premultipliedB, const QRect &rect=QRect())
Convenience function to both lock and bind the graphicsBuffer to a texture.
bool bindSWToTexture(const QPlatformGraphicsBuffer *graphicsBuffer, bool *swizzleRandB=nullptr, bool *premultipliedB=nullptr, const QRect &rect=QRect())
Convenience function that uploads the current raster content to the currently bound texture.
Combined button and popup list for selecting options.
#define GL_UNSIGNED_INT_2_10_10_10_REV
#define GL_UNPACK_ROW_LENGTH