Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qquickrendercontrol.cpp
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
6
7#include <QtCore/QCoreApplication>
8#include <QtCore/QTime>
9#include <QtQuick/private/qquickanimatorcontroller_p.h>
10#include <QtQuick/private/qsgdefaultrendercontext_p.h>
11#include <QtQuick/private/qsgrhisupport_p.h>
12
13#include <private/qsgrhishadereffectnode_p.h>
14
15#include <QtGui/private/qguiapplication_p.h>
16#include <qpa/qplatformintegration.h>
17#include <QtGui/qoffscreensurface.h>
18
19#include <QtQml/private/qqmlglobal_p.h>
20
21#include <QtQuick/QQuickWindow>
22#include <QtQuick/QQuickRenderTarget>
23#include <QtQuick/private/qquickwindow_p.h>
24#include <QtQuick/private/qquickitem_p.h>
25#include <QtQuick/private/qsgsoftwarerenderer_p.h>
26#include <QtCore/private/qobject_p.h>
27
28#include <QtQuick/private/qquickwindow_p.h>
29#include <rhi/qrhi.h>
30
32
115
117 : q(renderControl),
118 initialized(false),
120 rhi(nullptr),
121 ownRhi(true),
122 cb(nullptr),
123 offscreenSurface(nullptr),
124 sampleCount(1),
125 frameStatus(NotRecordingFrame)
126{
127 if (!sg) {
130 }
132}
133
135{
136 delete sg;
137 sg = nullptr;
138}
139
146{
147}
148
153 : QObject(dd, parent)
154{
155}
156
163{
165
166 invalidate();
167
169 if (d->window) {
171 wd->renderControl = nullptr;
173 }
174
175 // It is likely that the cleanup in windowDestroyed() is not called since
176 // the standard pattern is to destroy the rendercontrol before the QQuickWindow.
177 // Do it here.
178 d->windowDestroyed();
179
180 delete d->rc;
181
182 // Only call rhi related cleanup when we actually got to initialize() and
183 // managed to get a QRhi. The software backend for instance would mean
184 // using the rendercontrol without ever calling initialize() - it is then
185 // important to completely skip calling any QSGRhiSupport functions.
186 if (d->rhi)
187 d->resetRhi(config);
188}
189
191{
192 if (window) {
195
196 rc->invalidate();
197
199
200#if QT_CONFIG(quick_shadereffect)
202#endif
203
204 window = nullptr;
205 }
206}
207
216{
218 d->rc->moveToThread(targetThread);
220}
221
236{
238 d->sampleCount = qMax(1, sampleCount);
239}
240
247{
248 Q_D(const QQuickRenderControl);
249 return d->sampleCount;
250}
251
289{
291 if (!d->window) {
292 qWarning("QQuickRenderControl::initialize called with no associated window");
293 return false;
294 }
295
296 if (!d->initRhi())
297 return false;
298
300 wd->rhi = d->rhi;
301
302 QSGDefaultRenderContext *renderContext = qobject_cast<QSGDefaultRenderContext *>(d->rc);
303 if (renderContext) {
305 params.rhi = d->rhi;
306 params.sampleCount = d->sampleCount;
307 params.initialSurfacePixelSize = d->window->size() * d->window->effectiveDevicePixelRatio();
308 params.maybeSurface = d->window;
309 renderContext->initialize(&params);
310 d->initialized = true;
311 } else {
312 qWarning("QRhi is only compatible with default adaptation");
313 return false;
314 }
315 return true;
316}
317
324{
326 if (!d->window)
327 return;
328
331 if (!d->window)
332 return;
333 cd->polishItems();
334 emit d->window->afterAnimating();
335}
336
347{
349 if (!d->window)
350 return false;
351
353 // we may not have a d->rhi (software backend) hence the check is important
354 if (d->rhi) {
355 if (!d->rhi->isRecordingFrame()) {
356 qWarning("QQuickRenderControl can only sync when beginFrame() has been called");
357 return false;
358 }
359 if (!d->cb) {
360 qWarning("QQuickRenderControl cannot be used with QRhi when no QRhiCommandBuffer is provided");
361 return false;
362 }
363 cd->setCustomCommandBuffer(d->cb);
364 }
365
366 cd->syncSceneGraph();
367 d->rc->endSync();
368
369 return true;
370}
371
390{
392 if (!d->window)
393 return;
394
396 cd->fireAboutToStop();
398
399 if (!d->initialized)
400 return;
401
402 // We must invalidate since the context can potentially be destroyed by the
403 // application right after returning from this function. Invalidating is
404 // also essential to allow a subsequent initialize() to succeed.
405 d->rc->invalidate();
406
408 d->initialized = false;
409}
410
415{
417 if (!d->window)
418 return;
419
421 // we may not have a d->rhi (software backend) hence the check is important
422 if (d->rhi) {
423 if (!d->rhi->isRecordingFrame()) {
424 qWarning("QQuickRenderControl can only render when beginFrame() has been called");
425 return;
426 }
427 if (!d->cb) {
428 qWarning("QQuickRenderControl cannot be used with QRhi when no QRhiCommandBuffer is provided");
429 return;
430 }
431 cd->setCustomCommandBuffer(d->cb);
432 }
433
434 cd->renderSceneGraph();
435}
436
460{
461 if (!window)
462 return QImage();
463
464 QImage grabContent;
465
466 if (rhi) {
467
468 // As documented by QQuickWindow::grabWindow(): Nothing to do here, we
469 // do not support "grabbing" with an application-provided render target
470 // in Qt 6. (with the exception of the software backend because that
471 // does not support custom render targets, so the grab implementation
472 // here is still valuable)
473
474#if QT_CONFIG(thread)
475 } else if (window->rendererInterface()->graphicsApi() == QSGRendererInterface::Software) {
477 cd->polishItems();
478 cd->syncSceneGraph();
479 QSGSoftwareRenderer *softwareRenderer = static_cast<QSGSoftwareRenderer *>(cd->renderer);
480 if (softwareRenderer) {
481 const qreal dpr = window->effectiveDevicePixelRatio();
482 const QSize imageSize = window->size() * dpr;
484 grabContent.setDevicePixelRatio(dpr);
485 QPaintDevice *prevDev = softwareRenderer->currentPaintDevice();
486 softwareRenderer->setCurrentPaintDevice(&grabContent);
487 softwareRenderer->markDirty();
488 rc->endSync();
489 q->render();
490 softwareRenderer->setCurrentPaintDevice(prevDev);
491 }
492#endif
493 } else {
494 qWarning("QQuickRenderControl: grabs are not supported with the current Qt Quick backend");
495 }
496
497 return grabContent;
498}
499
501{
503 emit q->renderRequested();
504}
505
507{
509 emit q->sceneChanged();
510}
511
535{
536 if (!win)
537 return nullptr;
539 if (rc)
540 return rc->renderWindow(offset);
541 return nullptr;
542}
543
545{
547 if (rc)
549 return false;
550}
551
553{
555
556 if (window && w)
557 return q->renderWindowFor(window, nullptr) == w;
558
559 return false;
560}
561
572{
573 Q_D(const QQuickRenderControl);
574 return d->window;
575}
576
586{
587 Q_D(const QQuickRenderControl);
588 return d->rhi;
589}
590
605{
606 Q_D(const QQuickRenderControl);
607 return d->cb;
608}
609
651{
653 if (!d->rhi || d->rhi->isRecordingFrame())
654 return;
655
656 emit d->window->beforeFrameBegin();
657
658 QRhi::FrameOpResult result = d->rhi->beginOffscreenFrame(&d->cb);
659
660 switch (result) {
664 break;
667 break;
670 break;
671 default:
673 break;
674 }
675}
676
690{
692 if (!d->rhi || !d->rhi->isRecordingFrame())
693 return;
694
695 d->rhi->endOffscreenFrame();
696 d->cb = nullptr;
698
699 emit d->window->afterFrameEnd();
700}
701
703{
704 // initialize() - invalidate() - initialize() uses the QRhi the first
705 // initialize() created, so if already exists, we are done. Does not apply
706 // when wrapping an externally created QRhi, because we may be associated
707 // with a new one now.
708 if (rhi && ownRhi)
709 return true;
710
712
713 // sanity check for Vulkan
714#if QT_CONFIG(vulkan)
715 if (rhiSupport->rhiBackend() == QRhi::Vulkan && !window->vulkanInstance()) {
716 qWarning("QQuickRenderControl: No QVulkanInstance set for QQuickWindow, cannot initialize");
717 return false;
718 }
719#endif
720
721 // for OpenGL
722 if (!offscreenSurface)
724
726 if (!result.rhi) {
727 qWarning("QQuickRenderControl: Failed to initialize QRhi");
728 return false;
729 }
730
731 rhi = result.rhi;
732 ownRhi = result.own;
733
734 return true;
735}
736
738{
739 if (ownRhi)
741
742 rhi = nullptr;
743
744 delete offscreenSurface;
745 offscreenSurface = nullptr;
746}
747
749
750#include "moc_qquickrendercontrol.cpp"
\inmodule QtGui
Definition qimage.h:37
@ Format_ARGB32_Premultiplied
Definition qimage.h:48
void setDevicePixelRatio(qreal scaleFactor)
Sets the device pixel ratio for the image.
Definition qimage.cpp:1488
\inmodule QtCore
Definition qobject.h:90
void moveToThread(QThread *thread)
Changes the thread affinity for this object and its children.
Definition qobject.cpp:1606
\inmodule QtCore\reentrant
Definition qpoint.h:23
void flushFrameSynchronousEvents(QQuickWindow *win)
QQuickGraphicsConfiguration controls lower level graphics settings for the QQuickWindow.
void resetRhi(const QQuickGraphicsConfiguration &config)
QQuickRenderControlPrivate(QQuickRenderControl *renderControl)
QOffscreenSurface * offscreenSurface
static QQuickRenderControlPrivate * get(QQuickRenderControl *renderControl)
virtual bool isRenderWindow(const QWindow *w)
static bool isRenderWindowFor(QQuickWindow *quickWin, const QWindow *renderWin)
The QQuickRenderControl class provides a mechanism for rendering the Qt Quick scenegraph onto an offs...
virtual QWindow * renderWindow(QPoint *offset)
Reimplemented in subclasses to return the real window this render control is rendering into.
bool initialize()
Initializes the scene graph resources.
void endFrame()
Specifies the end of a graphics frame.
void prepareThread(QThread *targetThread)
Prepares rendering the Qt Quick scene outside the GUI thread.
void render()
Renders the scenegraph using the current context.
void setSamples(int sampleCount)
Sets the number of samples to use for multisampling.
~QQuickRenderControl() override
Destroys the instance.
QQuickRenderControl(QObject *parent=nullptr)
Constructs a QQuickRenderControl object, with parent object parent.
static QWindow * renderWindowFor(QQuickWindow *win, QPoint *offset=nullptr)
Returns the real window that win is being rendered to, if any.
QRhiCommandBuffer * commandBuffer() const
void beginFrame()
Specifies the start of a graphics frame.
void polishItems()
This function should be called as late as possible before sync().
QQuickWindow * window() const
bool sync()
This function is used to synchronize the QML scene with the rendering scene graph.
void invalidate()
Stop rendering and release resources.
QQuickGraphicsConfiguration graphicsConfig
static QQuickWindowPrivate * get(QQuickWindow *c)
QSGRenderer * renderer
QQuickRenderControl * renderControl
void setCustomCommandBuffer(QRhiCommandBuffer *cb)
QQuickDeliveryAgentPrivate * deliveryAgentPrivate() const
QScopedPointer< QQuickAnimatorController > animationController
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
\inmodule QtGui
Definition qrhi.h:1614
\inmodule QtGui
Definition qrhi.h:1767
@ Vulkan
Definition qrhi.h:1771
FrameOpResult
Describes the result of operations that can have a soft failure.
Definition qrhi.h:1786
@ FrameOpSuccess
Definition qrhi.h:1787
@ FrameOpSwapChainOutOfDate
Definition qrhi.h:1789
@ FrameOpDeviceLost
Definition qrhi.h:1790
@ FrameOpError
Definition qrhi.h:1788
The QSGContext holds the scene graph entry points for one QML engine.
virtual QSGRenderContext * createRenderContext()=0
static QSGContext * createDefaultContext()
Creates a default scene graph context for the current hardware.
void initialize(const QSGRenderContext::InitParams *params) override
Initializes the scene graph render context with the GL context context.
virtual void invalidate()
virtual void endSync()
virtual GraphicsApi graphicsApi() const =0
Returns the graphics API that is in use by the Qt Quick scenegraph.
static void resetMaterialTypeCache(void *materialTypeCacheKey)
QOffscreenSurface * maybeCreateOffscreenSurface(QWindow *window)
QRhi::Implementation rhiBackend() const
void destroyRhi(QRhi *rhi, const QQuickGraphicsConfiguration &config)
static QSGRhiSupport * instance()
RhiCreateResult createRhi(QQuickWindow *window, QSurface *offscreenSurface)
QPaintDevice * currentPaintDevice() const
void setCurrentPaintDevice(QPaintDevice *device)
void reset(T *other=nullptr) noexcept(noexcept(Cleanup::cleanup(std::declval< T * >())))
Deletes the existing object it is pointing to (if any), and sets its pointer to other.
\inmodule QtCore
Definition qsize.h:25
\inmodule QtGui
Definition qwindow.h:63
#define this
Definition dialogs.cpp:9
Combined button and popup list for selecting options.
void qAddPostRoutine(QtCleanUpFunction p)
EGLConfig config
#define qWarning
Definition qlogging.h:162
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLfloat GLfloat GLfloat w
[0]
GLenum GLuint GLintptr offset
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei imageSize
void ** params
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLuint64EXT * result
[6]
static QT_BEGIN_NAMESPACE qreal dpr(const QWindow *w)
SSL_CTX int(* cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
#define emit
double qreal
Definition qtypes.h:92
QWidget * win
Definition settings.cpp:6
QObject::connect nullptr
aWidget window() -> setWindowTitle("New Window Title")
[2]
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent