Coverage Report

Created: 2026-09-28 08:21

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