Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
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 }
131 rc = sg->createRenderContext();
132}
133
135{
136 delete sg;
137 sg = nullptr;
138}
139
148
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
198 QQuickWindowPrivate::get(window)->animationController.reset();
199
200#if QT_CONFIG(quick_shadereffect)
202#endif
203
204 window = nullptr;
205 }
206}
207
216{
218 d->rc->moveToThread(targetThread);
219 QQuickWindowPrivate::get(d->window)->animationController->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
300{
302 if (!d->window) {
303 qWarning("QQuickRenderControl::initialize called with no associated window");
304 return false;
305 }
306
307 if (!d->initRhi())
308 return false;
309
311 wd->rhi = d->rhi;
312
313 QSGDefaultRenderContext *renderContext = qobject_cast<QSGDefaultRenderContext *>(d->rc);
314 if (renderContext) {
316 params.rhi = d->rhi;
317 params.sampleCount = d->sampleCount;
318 params.initialSurfacePixelSize = d->window->size() * d->window->effectiveDevicePixelRatio();
319 params.maybeSurface = d->window;
320 renderContext->initialize(&params);
321 d->initialized = true;
322 } else {
323 qWarning("QRhi is only compatible with default adaptation");
324 return false;
325 }
326 return true;
327}
328
335{
337 if (!d->window)
338 return;
339
342 if (!d->window)
343 return;
344 cd->polishItems();
345 emit d->window->afterAnimating();
346}
347
358{
360 if (!d->window)
361 return false;
362
364 // we may not have a d->rhi (software backend) hence the check is important
365 if (d->rhi) {
366 if (!d->rhi->isRecordingFrame()) {
367 qWarning("QQuickRenderControl can only sync when beginFrame() has been called");
368 return false;
369 }
370 if (!d->cb) {
371 qWarning("QQuickRenderControl cannot be used with QRhi when no QRhiCommandBuffer is provided "
372 "(perhaps beginFrame() was not called or it was unsuccessful?)");
373 return false;
374 }
375 cd->setCustomCommandBuffer(d->cb);
376 }
377
378 cd->syncSceneGraph();
379 d->rc->endSync();
380
381 return true;
382}
383
402{
404 if (!d->window)
405 return;
406
408 cd->fireAboutToStop();
410
411 if (!d->initialized)
412 return;
413
414 // We must invalidate since the context can potentially be destroyed by the
415 // application right after returning from this function. Invalidating is
416 // also essential to allow a subsequent initialize() to succeed.
417 d->rc->invalidate();
418
420 d->initialized = false;
421}
422
427{
429 if (!d->window)
430 return;
431
433 // we may not have a d->rhi (software backend) hence the check is important
434 if (d->rhi) {
435 if (!d->rhi->isRecordingFrame()) {
436 qWarning("QQuickRenderControl can only render when beginFrame() has been called");
437 return;
438 }
439 if (!d->cb) {
440 qWarning("QQuickRenderControl cannot be used with QRhi when no QRhiCommandBuffer is provided");
441 return;
442 }
443 cd->setCustomCommandBuffer(d->cb);
444 }
445
446 cd->renderSceneGraph();
447}
448
472{
473 if (!window)
474 return QImage();
475
476 QImage grabContent;
477
478 if (rhi) {
479
480 // As documented by QQuickWindow::grabWindow(): Nothing to do here, we
481 // do not support "grabbing" with an application-provided render target
482 // in Qt 6. (with the exception of the software backend because that
483 // does not support custom render targets, so the grab implementation
484 // here is still valuable)
485
486#if QT_CONFIG(thread)
487 } else if (window->rendererInterface()->graphicsApi() == QSGRendererInterface::Software) {
489 cd->polishItems();
490 cd->syncSceneGraph();
491 QSGSoftwareRenderer *softwareRenderer = static_cast<QSGSoftwareRenderer *>(cd->renderer);
492 if (softwareRenderer) {
493 const qreal dpr = window->effectiveDevicePixelRatio();
494 const QSize imageSize = window->size() * dpr;
496 grabContent.setDevicePixelRatio(dpr);
497 QPaintDevice *prevDev = softwareRenderer->currentPaintDevice();
498 softwareRenderer->setCurrentPaintDevice(&grabContent);
499 softwareRenderer->markDirty();
500 rc->endSync();
501 q->render();
502 softwareRenderer->setCurrentPaintDevice(prevDev);
503 }
504#endif
505 } else {
506 qWarning("QQuickRenderControl: grabs are not supported with the current Qt Quick backend");
507 }
508
509 return grabContent;
510}
511
513{
515 emit q->renderRequested();
516}
517
519{
521 emit q->sceneChanged();
522}
523
547{
548 if (!win)
549 return nullptr;
551 if (rc)
552 return rc->renderWindow(offset);
553 return nullptr;
554}
555
557{
558 QQuickRenderControl *rc = QQuickWindowPrivate::get(quickWin)->renderControl;
559 if (rc)
560 return QQuickRenderControlPrivate::get(rc)->isRenderWindow(renderWin);
561 return false;
562}
563
565{
567
568 if (window && w)
569 return q->renderWindowFor(window, nullptr) == w;
570
571 return false;
572}
573
584{
585 Q_D(const QQuickRenderControl);
586 return d->window;
587}
588
603{
604 Q_D(const QQuickRenderControl);
605 return d->rhi;
606}
607
631{
632 Q_D(const QQuickRenderControl);
633 return d->cb;
634}
635
686{
688 if (!d->rhi) {
689 qWarning("QQuickRenderControl: No QRhi in beginFrame()");
690 return;
691 }
692 if (d->frameStatus == QQuickRenderControlPrivate::RecordingFrame) {
693 qWarning("QQuickRenderControl: beginFrame() must be followed by a call to endFrame() before calling beginFrame() again");
694 return;
695 }
696 if (d->rhi->isRecordingFrame()) {
697 qWarning("QQuickRenderControl: Attempted to beginFrame() while the QRhi is already recording a frame");
698 return;
699 }
700
701 emit d->window->beforeFrameBegin();
702
703 QRhi::FrameOpResult result = d->rhi->beginOffscreenFrame(&d->cb);
704
705 switch (result) {
709 break;
712 break;
715 break;
716 default:
718 break;
719 }
720}
721
738{
740 if (!d->rhi) {
741 qWarning("QQuickRenderControl: No QRhi in endFrame()");
742 return;
743 }
744 if (d->frameStatus != QQuickRenderControlPrivate::RecordingFrame) {
745 qWarning("QQuickRenderControl: endFrame() must only be called after a successful beginFrame()");
746 return;
747 }
748 if (!d->rhi->isRecordingFrame()) {
749 qWarning("QQuickRenderControl: Attempted to endFrame() while the QRhi is not recording a frame");
750 return;
751 }
752
753 d->rhi->endOffscreenFrame();
754 // do not null out d->cb; this allows calling lastCompletedGpuTime() for example
755
757
758 emit d->window->afterFrameEnd();
759}
760
762{
763 // initialize() - invalidate() - initialize() uses the QRhi the first
764 // initialize() created, so if already exists, we are done. Does not apply
765 // when wrapping an externally created QRhi, because we may be associated
766 // with a new one now.
767 if (rhi && ownRhi)
768 return true;
769
771
772 // sanity check for Vulkan
773#if QT_CONFIG(vulkan)
774 if (rhiSupport->rhiBackend() == QRhi::Vulkan && !window->vulkanInstance()) {
775 qWarning("QQuickRenderControl: No QVulkanInstance set for QQuickWindow, cannot initialize");
776 return false;
777 }
778#endif
779
780 // for OpenGL
781 if (!offscreenSurface)
783
785 if (!result.rhi) {
786 qWarning("QQuickRenderControl: Failed to initialize QRhi");
787 return false;
788 }
789
790 rhi = result.rhi;
791 ownRhi = result.own;
792
793 return true;
794}
795
797{
798 if (ownRhi)
799 QSGRhiSupport::instance()->destroyRhi(rhi, config);
800
801 rhi = nullptr;
802
803 delete offscreenSurface;
804 offscreenSurface = nullptr;
805}
806
808
809#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:1510
\inmodule QtCore
Definition qobject.h:103
\inmodule QtCore\reentrant
Definition qpoint.h:25
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
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
\inmodule QtGui
Definition qrhi.h:1651
\inmodule QtGuiPrivate \inheaderfile rhi/qrhi.h
Definition qrhi.h:1804
@ Vulkan
Definition qrhi.h:1808
FrameOpResult
Describes the result of operations that can have a soft failure.
Definition qrhi.h:1824
@ FrameOpSuccess
Definition qrhi.h:1825
@ FrameOpSwapChainOutOfDate
Definition qrhi.h:1827
@ FrameOpDeviceLost
Definition qrhi.h:1828
@ FrameOpError
Definition qrhi.h:1826
The QSGContext holds the scene graph entry points for one QML engine.
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)
RhiCreateResult createRhi(QQuickWindow *window, QSurface *offscreenSurface, bool forcePreferSwRenderer=false)
QRhi::Implementation rhiBackend() const
static QSGRhiSupport * instance()
\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:166
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:187
QWidget * win
Definition settings.cpp:6
QObject::connect nullptr
aWidget window() -> setWindowTitle("New Window Title")
[2]