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
4#include "qplatformbackingstore.h"
5#include <qwindow.h>
6#include <qpixmap.h>
7#include <private/qbackingstorerhisupport_p.h>
8#include <private/qbackingstoredefaultcompositor_p.h>
9#include <private/qwindow_p.h>
10
11#include <QtCore/private/qobject_p.h>
12
13QT_BEGIN_NAMESPACE
14
15Q_LOGGING_CATEGORY(lcQpaBackingStore, "qt.qpa.backingstore", QtWarningMsg);
16
17class QPlatformBackingStorePrivate
18{
19public:
20 QPlatformBackingStorePrivate(QWindow *w)
21 : window(w)
22 , backingStore(nullptr)
23 {
24 }
25
26 QWindow *window;
27 QBackingStore *backingStore;
28
29 // The order matters. if it needs to be rearranged in the future, call
30 // reset() explicitly from the dtor in the correct order.
31 // (first the compositor, then the rhiSupport)
32 QBackingStoreRhiSupport rhiSupport;
33 QBackingStoreDefaultCompositor compositor;
34};
35
36struct QBackingstoreTextureInfo
37{
38 void *source; // may be null
39 QRhiTexture *texture;
40 QRhiTexture *textureExtra;
41 QRect rect;
42 QRect clipRect;
43 QPlatformTextureList::Flags flags;
44};
45
46Q_DECLARE_TYPEINFO(QBackingstoreTextureInfo, Q_RELOCATABLE_TYPE);
47
48class QPlatformTextureListPrivate : public QObjectPrivate
49{
50public:
51 QPlatformTextureListPrivate()
52 : locked(false)
53 {
54 }
55
56 QList<QBackingstoreTextureInfo> textures;
57 bool locked;
58};
59
60QPlatformTextureList::QPlatformTextureList(QObject *parent)
61: QObject(*new QPlatformTextureListPrivate, parent)
62{
63}
64
65QPlatformTextureList::~QPlatformTextureList()
66{
67}
68
69int QPlatformTextureList::count() const
70{
71 Q_D(const QPlatformTextureList);
72 return d->textures.size();
73}
74
75QRhiTexture *QPlatformTextureList::texture(int index) const
76{
77 Q_D(const QPlatformTextureList);
78 return d->textures.at(i: index).texture;
79}
80
81QRhiTexture *QPlatformTextureList::textureExtra(int index) const
82{
83 Q_D(const QPlatformTextureList);
84 return d->textures.at(i: index).textureExtra;
85}
86
87void *QPlatformTextureList::source(int index)
88{
89 Q_D(const QPlatformTextureList);
90 return d->textures.at(i: index).source;
91}
92
93QPlatformTextureList::Flags QPlatformTextureList::flags(int index) const
94{
95 Q_D(const QPlatformTextureList);
96 return d->textures.at(i: index).flags;
97}
98
99QRect QPlatformTextureList::geometry(int index) const
100{
101 Q_D(const QPlatformTextureList);
102 return d->textures.at(i: index).rect;
103}
104
105QRect QPlatformTextureList::clipRect(int index) const
106{
107 Q_D(const QPlatformTextureList);
108 return d->textures.at(i: index).clipRect;
109}
110
111void QPlatformTextureList::lock(bool on)
112{
113 Q_D(QPlatformTextureList);
114 if (on != d->locked) {
115 d->locked = on;
116 emit locked(on);
117 }
118}
119
120bool QPlatformTextureList::isLocked() const
121{
122 Q_D(const QPlatformTextureList);
123 return d->locked;
124}
125
126void QPlatformTextureList::appendTexture(void *source, QRhiTexture *texture, const QRect &geometry,
127 const QRect &clipRect, Flags flags)
128{
129 Q_D(QPlatformTextureList);
130 QBackingstoreTextureInfo bi;
131 bi.source = source;
132 bi.texture = texture;
133 bi.textureExtra = nullptr;
134 bi.rect = geometry;
135 bi.clipRect = clipRect;
136 bi.flags = flags;
137 d->textures.append(t: bi);
138}
139
140void QPlatformTextureList::appendTexture(void *source, QRhiTexture *textureLeft, QRhiTexture *textureRight, const QRect &geometry,
141 const QRect &clipRect, Flags flags)
142{
143 Q_D(QPlatformTextureList);
144
145 QBackingstoreTextureInfo bi;
146 bi.source = source;
147 bi.texture = textureLeft;
148 bi.textureExtra = textureRight;
149 bi.rect = geometry;
150 bi.clipRect = clipRect;
151 bi.flags = flags;
152 d->textures.append(t: bi);
153}
154
155void QPlatformTextureList::clear()
156{
157 Q_D(QPlatformTextureList);
158 d->textures.clear();
159}
160
161/*!
162 \class QPlatformBackingStore
163 \since 5.0
164 \internal
165 \preliminary
166 \ingroup qpa
167
168 \brief The QPlatformBackingStore class provides the drawing area for top-level
169 windows.
170*/
171
172/*!
173 Flushes the given \a region from the specified \a window.
174
175 \note \a region is relative to the window which may not be top-level in case
176 \a window corresponds to a native child widget. \a offset is the position of
177 the native child relative to the top-level window.
178
179 Unlike rhiFlush(), this function's default implementation does nothing. It
180 is expected that subclasses provide a platform-specific (non-QRhi-based)
181 implementation, if applicable on the given platform.
182
183 \sa rhiFlush()
184 */
185void QPlatformBackingStore::flush(QWindow *window, const QRegion &region, const QPoint &offset)
186{
187 Q_UNUSED(window);
188 Q_UNUSED(region);
189 Q_UNUSED(offset);
190}
191
192/*!
193 Flushes the given \a region from the specified \a window, and compositing
194 it with the specified \a textures list.
195
196 The default implementation retrieves the contents using toTexture() and
197 composes using QRhi with OpenGL, Metal, Vulkan, or Direct 3D underneath.
198 May be reimplemented in subclasses if customization is desired.
199
200 \note \a region is relative to the window which may not be top-level in case
201 \a window corresponds to a native child widget. \a offset is the position of
202 the native child relative to the top-level window.
203
204 \sa flush()
205 */
206QPlatformBackingStore::FlushResult QPlatformBackingStore::rhiFlush(QWindow *window,
207 qreal sourceDevicePixelRatio,
208 const QRegion &region,
209 const QPoint &offset,
210 QPlatformTextureList *textures,
211 bool translucentBackground)
212{
213 return d_ptr->compositor.flush(backingStore: this, rhi: d_ptr->rhiSupport.rhi(), swapchain: d_ptr->rhiSupport.swapChainForWindow(window),
214 window, sourceDevicePixelRatio, region, offset, textures, translucentBackground);
215}
216
217/*!
218 Implemented in subclasses to return the content of the backingstore as a QImage.
219
220 If composition via a 3D graphics API is supported, either this function or
221 toTexture() must be implemented.
222
223 The returned image is only valid until the next operation (resize, paint, scroll,
224 or flush) on the backingstore. The caller must not store the return value between
225 calls, but instead call this function before each use, or make an explicit copy.
226
227 \sa toTexture()
228 */
229QImage QPlatformBackingStore::toImage() const
230{
231 return QImage();
232}
233
234/*!
235 May be reimplemented in subclasses to return the content of the
236 backingstore as an QRhiTexture. \a dirtyRegion is the part of the
237 backingstore which may have changed since the last call to this function. The
238 caller of this function must ensure that there is a current context.
239
240 The ownership of the texture is not transferred. The caller must not store
241 the return value between calls, but instead call this function before each use.
242
243 The default implementation returns a cached texture if \a dirtyRegion is
244 empty and the existing texture's size matches the backingstore size,
245 otherwise it retrieves the content using toImage() and performs a texture
246 upload.
247
248 If the red and blue components have to swapped, \a flags will be set to include \c
249 TextureSwizzle. This allows creating textures from images in formats like
250 QImage::Format_RGB32 without any further image conversion. Instead, the swizzling will
251 be done in the shaders when performing composition. Other formats, that do not need
252 such swizzling due to being already byte ordered RGBA, for example
253 QImage::Format_RGBA8888, must result in having \a needsSwizzle set to false.
254
255 If the image has to be flipped (e.g. because the texture is attached to an FBO), \a
256 flags will be set to include \c TextureFlip.
257
258 \note \a dirtyRegion is relative to the backingstore so no adjustment is needed.
259 */
260QRhiTexture *QPlatformBackingStore::toTexture(QRhiResourceUpdateBatch *resourceUpdates,
261 const QRegion &dirtyRegion,
262 TextureFlags *flags) const
263{
264 return d_ptr->compositor.toTexture(backingStore: this, rhi: d_ptr->rhiSupport.rhi(), resourceUpdates, dirtyRegion, flags);
265}
266
267/*!
268 \fn QPaintDevice* QPlatformBackingStore::paintDevice()
269
270 Implement this function to return the appropriate paint device.
271*/
272
273/*!
274 Constructs an empty surface for the given top-level \a window.
275*/
276QPlatformBackingStore::QPlatformBackingStore(QWindow *window)
277 : d_ptr(new QPlatformBackingStorePrivate(window))
278{
279}
280
281/*!
282 Destroys this surface.
283*/
284QPlatformBackingStore::~QPlatformBackingStore()
285{
286 delete d_ptr;
287}
288
289/*!
290 Returns a pointer to the top-level window associated with this
291 surface.
292*/
293QWindow* QPlatformBackingStore::window() const
294{
295 return d_ptr->window;
296}
297
298/*!
299 Sets the backing store associated with this surface.
300*/
301void QPlatformBackingStore::setBackingStore(QBackingStore *backingStore)
302{
303 d_ptr->backingStore = backingStore;
304}
305
306/*!
307 Returns a pointer to the backing store associated with this
308 surface.
309*/
310QBackingStore *QPlatformBackingStore::backingStore() const
311{
312 return d_ptr->backingStore;
313}
314
315/*!
316 This function is called before painting onto the surface begins,
317 with the \a region in which the painting will occur.
318
319 \sa endPaint(), paintDevice()
320*/
321
322void QPlatformBackingStore::beginPaint(const QRegion &)
323{
324}
325
326/*!
327 This function is called after painting onto the surface has ended.
328
329 \sa beginPaint(), paintDevice()
330*/
331
332void QPlatformBackingStore::endPaint()
333{
334}
335
336/*!
337 Accessor for a backingstores graphics buffer abstraction
338*/
339QPlatformGraphicsBuffer *QPlatformBackingStore::graphicsBuffer() const
340{
341 return nullptr;
342}
343
344/*!
345 Scrolls the given \a area \a dx pixels to the right and \a dy
346 downward; both \a dx and \a dy may be negative.
347
348 Returns \c true if the area was scrolled successfully; false otherwise.
349*/
350bool QPlatformBackingStore::scroll(const QRegion &area, int dx, int dy)
351{
352 Q_UNUSED(area);
353 Q_UNUSED(dx);
354 Q_UNUSED(dy);
355
356 return false;
357}
358
359void QPlatformBackingStore::setRhiConfig(const QPlatformBackingStoreRhiConfig &config)
360{
361 if (!config.isEnabled())
362 return;
363
364 d_ptr->rhiSupport.setConfig(config);
365 d_ptr->rhiSupport.setWindow(d_ptr->window);
366 d_ptr->rhiSupport.setFormat(d_ptr->window->format());
367 d_ptr->rhiSupport.create();
368}
369
370QRhi *QPlatformBackingStore::rhi() const
371{
372 // Returning null is valid, and means this is not a QRhi-capable backingstore.
373 return d_ptr->rhiSupport.rhi();
374}
375
376void QPlatformBackingStore::graphicsDeviceReportedLost()
377{
378 if (!d_ptr->rhiSupport.rhi())
379 return;
380
381 qWarning(msg: "Rhi backingstore: graphics device lost, attempting to reinitialize");
382 d_ptr->compositor.reset();
383 d_ptr->rhiSupport.reset();
384 d_ptr->rhiSupport.create();
385 if (!d_ptr->rhiSupport.rhi())
386 qWarning(msg: "Rhi backingstore: failed to reinitialize after losing the device");
387}
388
389QT_END_NAMESPACE
390
391#include "moc_qplatformbackingstore.cpp"
392

source code of qtbase/src/gui/painting/qplatformbackingstore.cpp