Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qcocoabackingstore.mm
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
4#include <AppKit/AppKit.h>
5
7
8#include "qcocoawindow.h"
9#include "qcocoahelpers.h"
10
11#include <QtCore/qmath.h>
12#include <QtCore/private/qcore_mac_p.h>
13#include <QtGui/qpainter.h>
14
15#include <QuartzCore/CATransaction.h>
16
18
21{
22}
23
25{
26 NSView *view = static_cast<QCocoaWindow *>(window()->handle())->view();
27 return QCFType<CGColorSpaceRef>::constructFromGet(view.window.colorSpace.CGColorSpace);
28}
29
30// ----------------------------------------------------------------------------
31
34{
35 qCDebug(lcQpaBackingStore) << "Creating QCALayerBackingStore for" << window
36 << "with" << window->format();
37
38 m_buffers.resize(1);
39
40 observeBackingPropertiesChanges();
42}
43
45{
46}
47
48void QCALayerBackingStore::observeBackingPropertiesChanges()
49{
51 NSView *view = static_cast<QCocoaWindow *>(window()->handle())->view();
52 m_backingPropertiesObserver = QMacNotificationObserver(view.window,
53 NSWindowDidChangeBackingPropertiesNotification, [this]() {
54 backingPropertiesChanged();
55 });
56}
57
59{
60 Q_ASSERT(watched == window());
61
62 if (event->type() == QEvent::PlatformSurface) {
63 auto *surfaceEvent = static_cast<QPlatformSurfaceEvent*>(event);
64 if (surfaceEvent->surfaceEventType() == QPlatformSurfaceEvent::SurfaceCreated)
65 observeBackingPropertiesChanges();
66 else
67 m_backingPropertiesObserver = QMacNotificationObserver();
68 }
69
70 return false;
71}
72
73void QCALayerBackingStore::resize(const QSize &size, const QRegion &staticContents)
74{
75 qCDebug(lcQpaBackingStore) << "Resize requested to" << size;
76
77 if (!staticContents.isNull())
78 qCWarning(lcQpaBackingStore) << "QCALayerBackingStore does not support static contents";
79
80 m_requestedSize = size;
81}
82
84{
85 Q_UNUSED(region);
86
88
89 qCInfo(lcQpaBackingStore) << "Beginning paint of" << region << "into backingstore of" << m_requestedSize;
90
91 ensureBackBuffer(); // Find an unused back buffer, or reserve space for a new one
92
93 const bool bufferWasRecreated = recreateBackBufferIfNeeded();
94
95 m_buffers.back()->lock(QPlatformGraphicsBuffer::SWWriteAccess);
96
97 // Although undocumented, QBackingStore::beginPaint expects the painted region
98 // to be cleared before use if the window has a surface format with an alpha.
99 // Fresh IOSurfaces are already cleared, so we don't need to clear those.
100 if (m_clearSurfaceOnPaint && !bufferWasRecreated && window()->format().hasAlpha()) {
101 qCDebug(lcQpaBackingStore) << "Clearing" << region << "before use";
102 QPainter painter(m_buffers.back()->asImage());
104 for (const QRect &rect : region)
106 }
107
108 // We assume the client is going to paint the entire region
109 updateDirtyStates(region);
110}
111
112void QCALayerBackingStore::ensureBackBuffer()
113{
114 if (window()->format().swapBehavior() == QSurfaceFormat::SingleBuffer)
115 return;
116
117 if (Q_UNLIKELY(lcQpaBackingStore().isDebugEnabled())) {
118 // ┌───────┬───────┬───────┬─────┬──────┐
119 // │ front ┊ spare ┊ spare ┊ ... ┊ back │
120 // └───────┴───────┴───────┴─────┴──────┘
121 for (const auto &buffer : m_buffers) {
122 qCDebug(lcQpaBackingStore).nospace() << " "
123 << (buffer == m_buffers.front() ? "front" :
124 buffer == m_buffers.back() ? " back" :
125 "spare"
126 ) << ": " << buffer.get();
127 }
128 }
129
130 // Ensure our back buffer is ready to draw into. If not, find a buffer that
131 // is not in use, or reserve space for a new buffer if none can be found.
132 for (auto &buffer : backwards(m_buffers)) {
133 if (!buffer || !buffer->isInUse()) {
134 // Buffer is okey to use, swap if necessary
135 if (buffer != m_buffers.back())
136 std::swap(buffer, m_buffers.back());
137 qCDebug(lcQpaBackingStore) << "Using back buffer" << m_buffers.back().get();
138
139 static const int kMaxSwapChainDepth = 3;
140 if (m_buffers.size() > kMaxSwapChainDepth) {
141 qCDebug(lcQpaBackingStore) << "Reducing swap chain depth to" << kMaxSwapChainDepth;
142 m_buffers.erase(std::next(m_buffers.begin(), 1), std::prev(m_buffers.end(), 2));
143 }
144
145 break;
146 } else if (buffer == m_buffers.front()) {
147 // We've exhausted the available buffers, make room for a new one
148 const int swapChainDepth = m_buffers.size() + 1;
149 qCDebug(lcQpaBackingStore) << "Available buffers exhausted, increasing swap chain depth to" << swapChainDepth;
150 m_buffers.resize(swapChainDepth);
151 break;
152 }
153 }
154
155 Q_ASSERT(!m_buffers.back() || !m_buffers.back()->isInUse());
156}
157
158// Disabled until performance issue on 5K iMac Pro has been investigated further,
159// as rounding up during resize will typically result in full screen buffer sizes
160// and low frame rate also for smaller window sizes.
161#define USE_LAZY_BUFFER_ALLOCATION_DURING_LIVE_WINDOW_RESIZE 0
162
163bool QCALayerBackingStore::recreateBackBufferIfNeeded()
164{
165 const QCocoaWindow *platformWindow = static_cast<QCocoaWindow *>(window()->handle());
166 const qreal devicePixelRatio = platformWindow->devicePixelRatio();
167 QSize requestedBufferSize = m_requestedSize * devicePixelRatio;
168
169 const NSView *backingStoreView = platformWindow->view();
170 Q_UNUSED(backingStoreView);
171
172 auto bufferSizeMismatch = [&](const QSize requested, const QSize actual) {
173#if USE_LAZY_BUFFER_ALLOCATION_DURING_LIVE_WINDOW_RESIZE
174 if (backingStoreView.inLiveResize) {
175 // Prevent over-eager buffer allocation during window resize by reusing larger buffers
176 return requested.width() > actual.width() || requested.height() > actual.height();
177 }
178#endif
179 return requested != actual;
180 };
181
182 if (!m_buffers.back() || bufferSizeMismatch(requestedBufferSize, m_buffers.back()->size())) {
183#if USE_LAZY_BUFFER_ALLOCATION_DURING_LIVE_WINDOW_RESIZE
184 if (backingStoreView.inLiveResize) {
185 // Prevent over-eager buffer allocation during window resize by rounding up
186 QSize nativeScreenSize = window()->screen()->geometry().size() * devicePixelRatio;
187 requestedBufferSize = QSize(qNextPowerOfTwo(requestedBufferSize.width()),
188 qNextPowerOfTwo(requestedBufferSize.height())).boundedTo(nativeScreenSize);
189 }
190#endif
191
192 qCInfo(lcQpaBackingStore) << "Creating surface of" << requestedBufferSize
193 << "based on requested" << m_requestedSize << "and dpr =" << devicePixelRatio;
194
196 m_buffers.back().reset(new GraphicsBuffer(requestedBufferSize, devicePixelRatio, pixelFormat, colorSpace()));
197 return true;
198 }
199
200 return false;
201}
202
204{
205 Q_ASSERT(m_buffers.back());
206 return m_buffers.back()->asImage();
207}
208
210{
211 qCInfo(lcQpaBackingStore) << "Paint ended. Back buffer valid region is now" << m_buffers.back()->validRegion();
212 m_buffers.back()->unlock();
213
214 // Since we can have multiple begin/endPaint rounds before a flush
215 // we defer finalizing the back buffer until its content is needed.
216}
217
218bool QCALayerBackingStore::scroll(const QRegion &region, int dx, int dy)
219{
220 if (!m_buffers.back()) {
221 qCInfo(lcQpaBackingStore) << "Scroll requested with no back buffer. Ignoring.";
222 return false;
223 }
224
225 const QPoint scrollDelta(dx, dy);
226 qCInfo(lcQpaBackingStore) << "Scrolling" << region << "by" << scrollDelta;
227
228 ensureBackBuffer();
229 recreateBackBufferIfNeeded();
230
231 const QRegion inPlaceRegion = region - m_buffers.back()->dirtyRegion;
232 const QRegion frontBufferRegion = region - inPlaceRegion;
233
235
236 m_buffers.back()->lock(QPlatformGraphicsBuffer::SWWriteAccess);
237
238 if (!inPlaceRegion.isEmpty()) {
239 // We have to scroll everything in one go, instead of scrolling the
240 // individual rects of the region, as otherwise we may end up reading
241 // already overwritten (scrolled) pixels.
242 const QRect inPlaceBoundingRect = inPlaceRegion.boundingRect();
243
244 qCDebug(lcQpaBackingStore) << "Scrolling" << inPlaceBoundingRect << "in place";
245 QImage *backBufferImage = m_buffers.back()->asImage();
246 const qreal devicePixelRatio = backBufferImage->devicePixelRatio();
247 const QPoint devicePixelDelta = scrollDelta * devicePixelRatio;
248
249 extern void qt_scrollRectInImage(QImage &, const QRect &, const QPoint &);
250
251 qt_scrollRectInImage(*backBufferImage,
252 QRect(inPlaceBoundingRect.topLeft() * devicePixelRatio,
253 inPlaceBoundingRect.size() * devicePixelRatio),
254 devicePixelDelta);
255 }
256
257 if (!frontBufferRegion.isEmpty()) {
258 qCDebug(lcQpaBackingStore) << "Scrolling" << frontBufferRegion << "by copying from front buffer";
259 preserveFromFrontBuffer(frontBufferRegion, scrollDelta);
260 }
261
262 m_buffers.back()->unlock();
263
264 // Mark the target region as filled. Note: We do not mark the source region
265 // as dirty, even though the content has conceptually been "moved", as that
266 // would complicate things when preserving from the front buffer. This matches
267 // the behavior of other backingstore implementations using qt_scrollRectInImage.
268 updateDirtyStates(region.translated(scrollDelta));
269
270 qCInfo(lcQpaBackingStore) << "Scroll ended. Back buffer valid region is now" << m_buffers.back()->validRegion();
271
272 return true;
273}
274
275void QCALayerBackingStore::flush(QWindow *flushedWindow, const QRegion &region, const QPoint &offset)
276{
277 Q_UNUSED(region);
279
280 if (!m_buffers.back()) {
281 qCWarning(lcQpaBackingStore) << "Tried to flush backingstore without painting to it first";
282 return;
283 }
284
285 finalizeBackBuffer();
286
287 if (flushedWindow != window()) {
288 flushSubWindow(flushedWindow);
289 return;
290 }
291
292 if (m_buffers.front()->isInUse() && !m_buffers.front()->isDirty()) {
293 qCInfo(lcQpaBackingStore) << "Asked to flush, but front buffer is up to date. Ignoring.";
294 return;
295 }
296
298
299 NSView *flushedView = static_cast<QCocoaWindow *>(flushedWindow->handle())->view();
300
301 // If the backingstore is just flushed, without being painted to first, then we may
302 // end in a situation where the backingstore is flushed to a layer with a different
303 // scale factor than the one it was created for in beginPaint. This is the client's
304 // fault in not picking up the change in scale factor of the window and re-painting
305 // the backingstore accordingly. To smoothing things out, we warn about this situation,
306 // and change the layer's contentsScale to match the scale of the back buffer, so that
307 // we at least cover the whole layer. This is necessary since we set the view's
308 // contents placement policy to NSViewLayerContentsPlacementTopLeft, which means
309 // AppKit will not do any scaling on our behalf.
310 if (m_buffers.back()->devicePixelRatio() != flushedView.layer.contentsScale) {
311 qCWarning(lcQpaBackingStore) << "Back buffer dpr of" << m_buffers.back()->devicePixelRatio()
312 << "doesn't match" << flushedView.layer << "contents scale of" << flushedView.layer.contentsScale
313 << "- updating layer to match.";
314 flushedView.layer.contentsScale = m_buffers.back()->devicePixelRatio();
315 }
316
317 const bool isSingleBuffered = window()->format().swapBehavior() == QSurfaceFormat::SingleBuffer;
318
319 id backBufferSurface = (__bridge id)m_buffers.back()->surface();
320
321 // Trigger a new display cycle if there isn't one. This ensures that our layer updates
322 // are committed as part of a display-cycle instead of on the next runloop pass. This
323 // means CA won't try to throttle us if we flush too fast, and we'll coalesce our flush
324 // with other pending view and layer updates.
325 flushedView.window.viewsNeedDisplay = YES;
326
327 if (isSingleBuffered) {
328 // The private API [CALayer reloadValueForKeyPath:@"contents"] would be preferable,
329 // but barring any side effects or performance issues we opt for the hammer for now.
330 flushedView.layer.contents = nil;
331 }
332
333 qCInfo(lcQpaBackingStore) << "Flushing" << backBufferSurface
334 << "to" << flushedView.layer << "of" << flushedView;
335
336 flushedView.layer.contents = backBufferSurface;
337
338 if (!isSingleBuffered) {
339 // Mark the surface as in use, so that we don't end up rendering
340 // to it while it's assigned to a layer.
341 IOSurfaceIncrementUseCount(m_buffers.back()->surface());
342
343 if (m_buffers.back() != m_buffers.front()) {
344 qCInfo(lcQpaBackingStore) << "Swapping back buffer to front";
345 std::swap(m_buffers.back(), m_buffers.front());
346 IOSurfaceDecrementUseCount(m_buffers.back()->surface());
347 }
348 }
349}
350
351void QCALayerBackingStore::flushSubWindow(QWindow *subWindow)
352{
353 qCInfo(lcQpaBackingStore) << "Flushing sub-window" << subWindow
354 << "via its own backingstore";
355
356 auto &subWindowBackingStore = m_subWindowBackingstores[subWindow];
357 if (!subWindowBackingStore) {
358 subWindowBackingStore.reset(new QCALayerBackingStore(subWindow));
359 QObject::connect(subWindow, &QObject::destroyed, this, &QCALayerBackingStore::windowDestroyed);
360 subWindowBackingStore->m_clearSurfaceOnPaint = false;
361 }
362
363 auto subWindowSize = subWindow->size();
364 static const auto kNoStaticContents = QRegion();
365 subWindowBackingStore->resize(subWindowSize, kNoStaticContents);
366
367 auto subWindowLocalRect = QRect(QPoint(), subWindowSize);
368 subWindowBackingStore->beginPaint(subWindowLocalRect);
369
370 QPainter painter(subWindowBackingStore->m_buffers.back()->asImage());
372
373 NSView *backingStoreView = static_cast<QCocoaWindow *>(window()->handle())->view();
374 NSView *flushedView = static_cast<QCocoaWindow *>(subWindow->handle())->view();
375 auto subviewRect = [flushedView convertRect:flushedView.bounds toView:backingStoreView];
376 auto scale = flushedView.layer.contentsScale;
377 subviewRect = CGRectApplyAffineTransform(subviewRect, CGAffineTransformMakeScale(scale, scale));
378
379 m_buffers.back()->lock(QPlatformGraphicsBuffer::SWReadAccess);
380 const QImage *backingStoreImage = m_buffers.back()->asImage();
381 painter.drawImage(subWindowLocalRect, *backingStoreImage, QRectF::fromCGRect(subviewRect));
382 m_buffers.back()->unlock();
383
384 painter.end();
385 subWindowBackingStore->endPaint();
386 subWindowBackingStore->flush(subWindow, subWindowLocalRect, QPoint());
387
388 qCInfo(lcQpaBackingStore) << "Done flushing sub-window" << subWindow;
389}
390
391void QCALayerBackingStore::windowDestroyed(QObject *object)
392{
393 auto *window = static_cast<QWindow*>(object);
394 qCInfo(lcQpaBackingStore) << "Removing backingstore for sub-window" << window;
395 m_subWindowBackingstores.erase(window);
396}
397
399 qreal sourceDevicePixelRatio,
400 const QRegion &region,
401 const QPoint &offset,
403 bool translucentBackground)
404{
405 if (!m_buffers.back()) {
406 qCWarning(lcQpaBackingStore) << "Tried to flush backingstore without painting to it first";
407 return FlushFailed;
408 }
409
410 finalizeBackBuffer();
411
412 return QPlatformBackingStore::rhiFlush(window, sourceDevicePixelRatio, region, offset, textures, translucentBackground);
413}
414
416{
417 if (!m_buffers.back())
418 return QImage();
419
420 const_cast<QCALayerBackingStore*>(this)->finalizeBackBuffer();
421
422 // We need to make a copy here, as the returned image could be used just
423 // for reading, in which case it won't detach, and then the underlying
424 // image data might change under the feet of the client when we re-use
425 // the buffer at a later point.
426 m_buffers.back()->lock(QPlatformGraphicsBuffer::SWReadAccess);
427 QImage imageCopy = m_buffers.back()->asImage()->copy();
428 m_buffers.back()->unlock();
429 return imageCopy;
430}
431
432void QCALayerBackingStore::backingPropertiesChanged()
433{
434 // Ideally this would be plumbed from the platform layer to QtGui, and
435 // the QBackingStore would be recreated, but we don't have that code yet,
436 // so at least make sure we update our backingstore when the backing
437 // properties (color space e.g.) are changed.
438
439 Q_ASSERT(window()->handle());
440
441 qCDebug(lcQpaBackingStore) << "Backing properties for" << window() << "did change";
442
443 qCDebug(lcQpaBackingStore) << "Updating color space of existing buffers";
444 for (auto &buffer : m_buffers) {
445 if (buffer)
446 buffer->setColorSpace(colorSpace());
447 }
448}
449
451{
452 return m_buffers.back().get();
453}
454
455void QCALayerBackingStore::updateDirtyStates(const QRegion &paintedRegion)
456{
457 // Update dirty state of buffers based on what was painted. The back buffer will be
458 // less dirty, since we painted to it, while other buffers will become more dirty.
459 // This allows us to minimize copies between front and back buffers on swap in the
460 // cases where the painted region overlaps with the previous frame (front buffer).
461 for (const auto &buffer : m_buffers) {
462 if (buffer == m_buffers.back())
463 buffer->dirtyRegion -= paintedRegion;
464 else
465 buffer->dirtyRegion += paintedRegion;
466 }
467}
468
469void QCALayerBackingStore::finalizeBackBuffer()
470{
471 // After painting, the back buffer is only guaranteed to have content for the painted
472 // region, and may still have dirty areas that need to be synced up with the front buffer,
473 // if we have one. We know that the front buffer is always up to date.
474
475 if (!m_buffers.back()->isDirty())
476 return;
477
478 m_buffers.back()->lock(QPlatformGraphicsBuffer::SWWriteAccess);
479 preserveFromFrontBuffer(m_buffers.back()->dirtyRegion);
480 m_buffers.back()->unlock();
481
482 // The back buffer is now completely in sync, ready to be presented
483 m_buffers.back()->dirtyRegion = QRegion();
484}
485
486void QCALayerBackingStore::preserveFromFrontBuffer(const QRegion &region, const QPoint &offset)
487{
488
489 if (m_buffers.front() == m_buffers.back())
490 return; // Nothing to preserve from
491
492 qCDebug(lcQpaBackingStore) << "Preserving" << region << "of front buffer to"
493 << region.translated(offset) << "of back buffer";
494
495 Q_ASSERT(m_buffers.back()->isLocked() == QPlatformGraphicsBuffer::SWWriteAccess);
496
497 m_buffers.front()->lock(QPlatformGraphicsBuffer::SWReadAccess);
498 const QImage *frontBuffer = m_buffers.front()->asImage();
499
500 const QRect frontSurfaceBounds(QPoint(0, 0), m_buffers.front()->size());
501 const qreal sourceDevicePixelRatio = frontBuffer->devicePixelRatio();
502
503 QPainter painter(m_buffers.back()->asImage());
505
506 // Let painter operate in device pixels, to make it easier to compare coordinates
507 const qreal targetDevicePixelRatio = painter.device()->devicePixelRatio();
508 painter.scale(1.0 / targetDevicePixelRatio, 1.0 / targetDevicePixelRatio);
509
510 for (const QRect &rect : region) {
511 QRect sourceRect(rect.topLeft() * sourceDevicePixelRatio,
512 rect.size() * sourceDevicePixelRatio);
513 QRect targetRect((rect.topLeft() + offset) * targetDevicePixelRatio,
514 rect.size() * targetDevicePixelRatio);
515
516#ifdef QT_DEBUG
517 if (Q_UNLIKELY(!frontSurfaceBounds.contains(sourceRect.bottomRight()))) {
518 qCWarning(lcQpaBackingStore) << "Front buffer too small to preserve"
519 << QRegion(sourceRect).subtracted(frontSurfaceBounds);
520 }
521#endif
522 painter.drawImage(targetRect, *frontBuffer, sourceRect);
523 }
524
525 m_buffers.front()->unlock();
526}
527
528// ----------------------------------------------------------------------------
529
530QCALayerBackingStore::GraphicsBuffer::GraphicsBuffer(const QSize &size, qreal devicePixelRatio,
533 , dirtyRegion(QRect(QPoint(0, 0), size / devicePixelRatio))
534 , m_devicePixelRatio(devicePixelRatio)
535{
536 setColorSpace(colorSpace);
537}
538
539QRegion QCALayerBackingStore::GraphicsBuffer::validRegion() const
540{
541
542 QRegion fullRegion = QRect(QPoint(0, 0), size() / m_devicePixelRatio);
543 return fullRegion - dirtyRegion;
544}
545
546QImage *QCALayerBackingStore::GraphicsBuffer::asImage()
547{
548 if (m_image.isNull()) {
549 qCDebug(lcQpaBackingStore) << "Setting up paint device for" << this;
550 CFRetain(surface());
551 m_image = QImage(data(), size().width(), size().height(),
552 bytesPerLine(), QImage::toImageFormat(format()),
553 QImageCleanupFunction(CFRelease), surface());
554 m_image.setDevicePixelRatio(m_devicePixelRatio);
555 }
556
557 Q_ASSERT_X(m_image.constBits() == data(), "QCALayerBackingStore",
558 "IOSurfaces should have have a fixed location in memory once created");
559
560 return &m_image;
561}
562
564
565#include "moc_qcocoabackingstore.cpp"
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.
bool scroll(const QRegion &region, int dx, int dy) override
Scrolls the given area dx pixels to the right and dy downward; both dx and dy may be negative.
void endPaint() override
This function is called after painting onto the surface has ended.
void flush(QWindow *, const QRegion &, const QPoint &) override
Flushes the given region from the specified window.
void beginPaint(const QRegion &region) override
This function is called before painting onto the surface begins, with the region in which the paintin...
QPlatformGraphicsBuffer * graphicsBuffer() const override
Accessor for a backingstores graphics buffer abstraction.
QCALayerBackingStore(QWindow *window)
bool eventFilter(QObject *watched, QEvent *event) override
Filters events if this object has been installed as an event filter for the watched object.
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...
void resize(const QSize &size, const QRegion &staticContents) override
static QCFType constructFromGet(const T &t)
QCFType< CGColorSpaceRef > colorSpace() const
QCocoaBackingStore(QWindow *window)
NSView * view() const
qreal devicePixelRatio() const override
Reimplement this function in subclass to return the device pixel ratio for the window.
\inmodule QtCore
Definition qcoreevent.h:45
@ PlatformSurface
Definition qcoreevent.h:278
\inmodule QtGui
Definition qimage.h:37
static QPixelFormat toPixelFormat(QImage::Format format) noexcept
Converts format into a QPixelFormat.
Definition qimage.cpp:5721
@ Format_ARGB32_Premultiplied
Definition qimage.h:48
qreal devicePixelRatio() const
Returns the device pixel ratio for the image.
Definition qimage.cpp:1460
static QImage::Format toImageFormat(QPixelFormat format) noexcept
Converts format into a QImage::Format.
Definition qimage.cpp:5730
\inmodule QtCore
Definition qobject.h:90
void installEventFilter(QObject *filterObj)
Installs an event filter filterObj on this object.
Definition qobject.cpp:2269
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
qreal devicePixelRatio() const
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
QPaintDevice * device() const
Returns the paint device on which this painter is currently painting, or \nullptr if the painter is n...
void scale(qreal sx, qreal sy)
Scales the coordinate system by ({sx}, {sy}).
void setCompositionMode(CompositionMode mode)
Sets the composition mode to the given mode.
void drawImage(const QRectF &targetRect, const QImage &image, const QRectF &sourceRect, Qt::ImageConversionFlags flags=Qt::AutoColor)
Draws the rectangular portion source of the given image into the target rectangle in the paint device...
bool end()
Ends painting.
@ CompositionMode_Source
Definition qpainter.h:101
void fillRect(const QRectF &, const QBrush &)
Fills the given rectangle with the brush specified.
\inmodule QtGui
The QPlatformBackingStore class provides the drawing area for top-level windows.
QWindow * window() const
Returns a pointer to the top-level window associated with this surface.
virtual FlushResult rhiFlush(QWindow *window, qreal sourceDevicePixelRatio, const QRegion &region, const QPoint &offset, QPlatformTextureList *textures, bool translucentBackground)
Flushes the given region from the specified window, and compositing it with the specified textures li...
The QPlatformSurfaceEvent class is used to notify about native platform surface events....
Definition qevent.h:530
\inmodule QtCore\reentrant
Definition qpoint.h:23
\inmodule QtCore\reentrant
Definition qrect.h:30
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
Definition qrect.h:220
constexpr QSize size() const noexcept
Returns the size of the rectangle.
Definition qrect.h:241
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
QRect boundingRect() const noexcept
Returns the bounding rectangle of this region.
bool isNull() const
bool isEmpty() const
Returns true if the region is empty; otherwise returns false.
QRegion subtracted(const QRegion &r) const
QRegion translated(int dx, int dy) const
Definition qregion.cpp:593
QRect geometry
the screen's geometry in pixels
Definition qscreen.h:45
\inmodule QtCore
Definition qsize.h:25
constexpr QSize boundedTo(const QSize &) const noexcept
Returns a size holding the minimum width and height of this size and the given otherSize.
Definition qsize.h:196
constexpr int height() const noexcept
Returns the height.
Definition qsize.h:132
constexpr int width() const noexcept
Returns the width.
Definition qsize.h:129
SwapBehavior swapBehavior() const
Returns the configured swap behaviour.
\inmodule QtGui
Definition qwindow.h:63
QSurfaceFormat format() const override
Returns the actual format of this window.
Definition qwindow.cpp:888
QSize size() const override
Returns the size of the window excluding any window frame.
Definition qwindow.h:210
rect
[4]
Combined button and popup list for selecting options.
@ transparent
Definition qnamespace.h:46
#define Q_UNLIKELY(x)
void(* QImageCleanupFunction)(void *)
Definition qimage.h:34
#define qCInfo(category,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
constexpr quint32 qNextPowerOfTwo(quint32 v)
Definition qmath.h:335
GLuint64 GLenum void * handle
GLint GLsizei GLsizei height
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint const GLuint GLuint const GLuint * textures
GLenum GLuint id
[7]
GLuint object
[3]
GLenum GLuint buffer
GLint GLsizei width
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
GLint GLsizei GLsizei GLenum format
struct _cl_event * event
GLenum GLenum GLenum GLenum GLenum scale
void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset)
static bool hasAlpha(const QImage &image)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
#define Q_UNUSED(x)
double qreal
Definition qtypes.h:92
QPainter painter(this)
[7]
aWidget window() -> setWindowTitle("New Window Title")
[2]
QQuickView * view
[0]