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