Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qopenglcompositorbackingstore.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 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 <QtGui/QOpenGLContext>
5#include <QtGui/QWindow>
6#include <QtGui/QPainter>
7#include <qpa/qplatformbackingstore.h>
8#include <private/qwindow_p.h>
9#include <rhi/qrhi.h>
10
12#include "qopenglcompositor_p.h"
13
14#ifndef GL_UNPACK_ROW_LENGTH
15#define GL_UNPACK_ROW_LENGTH 0x0CF2
16#endif
17
19
44 m_window(window),
45 m_bsTexture(0),
46 m_bsTextureWrapper(nullptr),
47 m_bsTextureContext(0),
48 m_textures(new QPlatformTextureList),
49 m_lockedWidgetTextures(0),
50 m_rhi(nullptr)
51{
52}
53
55{
56 if (m_bsTexture && m_rhi) {
57 delete m_bsTextureWrapper;
58 // Contexts are sharing resources, won't matter which one is
59 // current here, use the rhi's shortcut.
61 glDeleteTextures(1, &m_bsTexture);
62 }
63
64 delete m_textures; // this does not actually own any GL resources
65}
66
68{
69 return &m_image;
70}
71
72void QOpenGLCompositorBackingStore::updateTexture()
73{
74 if (!m_bsTexture) {
75 m_bsTextureContext = QOpenGLContext::currentContext();
76 Q_ASSERT(m_bsTextureContext);
77 glGenTextures(1, &m_bsTexture);
78 glBindTexture(GL_TEXTURE_2D, m_bsTexture);
79 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
80 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
81 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
82 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
83 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_image.width(), m_image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
84 } else {
85 glBindTexture(GL_TEXTURE_2D, m_bsTexture);
86 }
87
88 if (!m_dirty.isNull()) {
90 QRect imageRect = m_image.rect();
91
93 if (!ctx->isOpenGLES() || ctx->format().majorVersion() >= 3) {
94 for (const QRect &rect : m_dirty) {
95 QRect r = imageRect & rect;
96 glPixelStorei(GL_UNPACK_ROW_LENGTH, m_image.width());
97 glTexSubImage2D(GL_TEXTURE_2D, 0, r.x(), r.y(), r.width(), r.height(), GL_RGBA, GL_UNSIGNED_BYTE,
98 m_image.constScanLine(r.y()) + r.x() * 4);
99 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
100 }
101 } else {
102 for (const QRect &rect : m_dirty) {
103 // intersect with image rect to be sure
104 QRect r = imageRect & rect;
105
106 // if the rect is wide enough it's cheaper to just
107 // extend it instead of doing an image copy
108 if (r.width() >= imageRect.width() / 2) {
109 r.setX(0);
110 r.setWidth(imageRect.width());
111 }
112
113 fixed |= r;
114 }
115 for (const QRect &rect : fixed) {
116 // if the sub-rect is full-width we can pass the image data directly to
117 // OpenGL instead of copying, since there's no gap between scanlines
118 if (rect.width() == imageRect.width()) {
119 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
120 m_image.constScanLine(rect.y()));
121 } else {
122 glTexSubImage2D(GL_TEXTURE_2D, 0, rect.x(), rect.y(), rect.width(), rect.height(), GL_RGBA, GL_UNSIGNED_BYTE,
123 m_image.copy(rect).constBits());
124 }
125 }
126 }
127
128 m_dirty = QRegion();
129 }
130
131 if (!m_bsTextureWrapper) {
132 m_bsTextureWrapper = m_rhi->newTexture(QRhiTexture::RGBA8, m_image.size());
133 m_bsTextureWrapper->createFrom({m_bsTexture, 0});
134 }
135}
136
138{
139 // Called for ordinary raster windows.
140
141 Q_UNUSED(region);
143
144 m_rhi = rhi();
145 if (!m_rhi) {
147 m_rhi = rhi();
148 }
149 Q_ASSERT(m_rhi);
150
152 QOpenGLContext *dstCtx = compositor->context();
153 if (!dstCtx)
154 return;
155
156 QWindow *dstWin = compositor->targetWindow();
157 if (!dstWin)
158 return;
159
160 if (!dstCtx->makeCurrent(dstWin))
161 return;
162
163 updateTexture();
164 m_textures->clear();
165 m_textures->appendTexture(nullptr, m_bsTextureWrapper, window->geometry());
166
168}
169
171 qreal sourceDevicePixelRatio,
172 const QRegion &region,
173 const QPoint &offset,
175 bool translucentBackground)
176{
177 // QOpenGLWidget/QQuickWidget content provided as textures. The raster content goes on top.
178
179 Q_UNUSED(region);
181 Q_UNUSED(translucentBackground);
182 Q_UNUSED(sourceDevicePixelRatio);
183
184 m_rhi = rhi();
185 if (!m_rhi) {
187 m_rhi = rhi();
188 }
189 Q_ASSERT(m_rhi);
190
192 QOpenGLContext *dstCtx = compositor->context();
193 if (!dstCtx)
194 return FlushFailed;
195
196 QWindow *dstWin = compositor->targetWindow();
197 if (!dstWin)
198 return FlushFailed;
199
200 if (!dstCtx->makeCurrent(dstWin))
201 return FlushFailed;
202
204
205 m_textures->clear();
206 for (int i = 0; i < textures->count(); ++i) {
207 m_textures->appendTexture(textures->source(i), textures->texture(i), textures->geometry(i),
208 textures->clipRect(i), textures->flags(i));
209 }
210
211 updateTexture();
212 m_textures->appendTexture(nullptr, m_bsTextureWrapper, window->geometry());
213
214 textures->lock(true);
215 m_lockedWidgetTextures = textures;
216
218
219 return FlushSuccess;
220}
221
223{
224 if (m_lockedWidgetTextures) {
225 QPlatformTextureList *textureList = m_lockedWidgetTextures;
226 m_lockedWidgetTextures = 0; // may reenter so null before unlocking
227 textureList->lock(false);
228 }
229}
230
232{
233 m_dirty |= region;
234
235 if (m_image.hasAlphaChannel()) {
236 QPainter p(&m_image);
237 p.setCompositionMode(QPainter::CompositionMode_Source);
238 for (const QRect &r : region)
239 p.fillRect(r, Qt::transparent);
240 }
241}
242
243void QOpenGLCompositorBackingStore::resize(const QSize &size, const QRegion &staticContents)
244{
245 Q_UNUSED(staticContents);
246
248 QOpenGLContext *dstCtx = compositor->context();
249 QWindow *dstWin = compositor->targetWindow();
250 if (!dstWin)
251 return;
252
254
255 m_window->create();
256
257 dstCtx->makeCurrent(dstWin);
258 if (m_bsTexture) {
259 delete m_bsTextureWrapper;
260 m_bsTextureWrapper = nullptr;
261 glDeleteTextures(1, &m_bsTexture);
262 m_bsTexture = 0;
263 m_bsTextureContext = nullptr;
264 }
265}
266
268{
269 return m_image;
270}
271
void start() noexcept
Starts this timer.
\inmodule QtGui
Definition qimage.h:37
bool hasAlphaChannel() const
Returns true if the image has a format that respects the alpha channel, otherwise returns false.
Definition qimage.cpp:4571
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_RGBA8888
Definition qimage.h:59
const uchar * constScanLine(int) const
Returns a pointer to the pixel data at the scanline with index i.
Definition qimage.cpp:1657
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:1713
void flush(QWindow *window, const QRegion &region, const QPoint &offset) override
Flushes the given region from the specified window.
FlushResult rhiFlush(QWindow *window, qreal sourceDevicePixelRatio, const QRegion &region, const QPoint &offset, QPlatformTextureList *textures, bool translucentBackground) override
Flushes the given region from the specified window, and compositing it with the specified textures li...
QPaintDevice * paintDevice() override
Implement this function to return the appropriate paint device.
QImage toImage() const override
Implemented in subclasses to return the content of the backingstore as a QImage.
void resize(const QSize &size, const QRegion &staticContents) override
void beginPaint(const QRegion &region) override
This function is called before painting onto the surface begins, with the region in which the paintin...
const QPlatformTextureList * textures() const
A generic OpenGL-based compositor.
static QOpenGLCompositor * instance()
QOpenGLContext * context() const
QWindow * targetWindow() const
\inmodule QtGui
bool makeCurrent(QSurface *surface)
Makes the context current in the current thread, against the given surface.
static QOpenGLContext * currentContext()
Returns the last context which called makeCurrent in the current thread, or \nullptr,...
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
@ CompositionMode_Source
Definition qpainter.h:101
The QPlatformBackingStore class provides the drawing area for top-level windows.
void setRhiConfig(const QPlatformBackingStoreRhiConfig &config)
QWindow * window() const
Returns a pointer to the top-level window associated with this surface.
void appendTexture(void *source, QRhiTexture *texture, const QRect &geometry, const QRect &clipRect=QRect(), Flags flags={ })
\inmodule QtCore\reentrant
Definition qpoint.h:23
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr int width() const noexcept
Returns the width of the rectangle.
Definition qrect.h:235
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
bool isNull() const
virtual bool createFrom(NativeTexture src)
Similar to create(), except that no new native textures are created.
Definition qrhi.cpp:4361
bool makeThreadLocalNativeContextCurrent()
With OpenGL this makes the OpenGL context current on the current thread.
Definition qrhi.cpp:9729
QRhiTexture * newTexture(QRhiTexture::Format format, const QSize &pixelSize, int sampleCount=1, QRhiTexture::Flags flags={})
Definition qrhi.cpp:10133
\inmodule QtCore
Definition qsize.h:25
static QWindowPrivate * get(QWindow *window)
Definition qwindow_p.h:94
QElapsedTimer lastComposeTime
Definition qwindow_p.h:147
\inmodule QtGui
Definition qwindow.h:63
EGLContext ctx
rect
[4]
Combined button and popup list for selecting options.
@ transparent
Definition qnamespace.h:46
QTextStream & fixed(QTextStream &stream)
Calls QTextStream::setRealNumberNotation(QTextStream::FixedNotation) on stream and returns stream.
static QOpenGLCompositor * compositor
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLuint const GLuint GLuint const GLuint * textures
GLenum GLuint GLintptr offset
GLfloat GLfloat p
[1]
#define GL_CLAMP_TO_EDGE
Definition qopenglext.h:100
#define GL_UNPACK_ROW_LENGTH
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define GL_UNSIGNED_BYTE
#define GL_RGBA
#define Q_UNUSED(x)
double qreal
Definition qtypes.h:92
QObject::connect nullptr
aWidget window() -> setWindowTitle("New Window Title")
[2]