aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items')
-rw-r--r--src/quick/items/items.pri10
-rw-r--r--src/quick/items/qquickgraphicsdevice.cpp216
-rw-r--r--src/quick/items/qquickgraphicsdevice.h73
-rw-r--r--src/quick/items/qquickgraphicsdevice_p.h105
-rw-r--r--src/quick/items/qquickrendercontrol.cpp316
-rw-r--r--src/quick/items/qquickrendercontrol.h19
-rw-r--r--src/quick/items/qquickrendercontrol_p.h18
-rw-r--r--src/quick/items/qquickrendertarget.cpp293
-rw-r--r--src/quick/items/qquickrendertarget.h78
-rw-r--r--src/quick/items/qquickrendertarget_p.h90
-rw-r--r--src/quick/items/qquickwindow.cpp295
-rw-r--r--src/quick/items/qquickwindow.h21
-rw-r--r--src/quick/items/qquickwindow_p.h40
13 files changed, 1482 insertions, 92 deletions
diff --git a/src/quick/items/items.pri b/src/quick/items/items.pri
index c2078b0e04..2d232a0b0a 100644
--- a/src/quick/items/items.pri
+++ b/src/quick/items/items.pri
@@ -65,7 +65,11 @@ HEADERS += \
$$PWD/qquickpalette_p.h \
$$PWD/qquickcolorgroup_p.h \
$$PWD/qquickpalettecolorprovider_p.h \
- $$PWD/qquickpaletteproviderprivatebase_p.h
+ $$PWD/qquickpaletteproviderprivatebase_p.h \
+ $$PWD/qquickrendertarget.h \
+ $$PWD/qquickrendertarget_p.h \
+ $$PWD/qquickgraphicsdevice.h \
+ $$PWD/qquickgraphicsdevice_p.h
SOURCES += \
$$PWD/qquickevents.cpp \
@@ -108,7 +112,9 @@ SOURCES += \
$$PWD/qquickitemgrabresult.cpp \
$$PWD/qquickpalettecolorprovider.cpp \
$$PWD/qquickcolorgroup.cpp \
- $$PWD/qquickpalette.cpp
+ $$PWD/qquickpalette.cpp \
+ $$PWD/qquickrendertarget.cpp \
+ $$PWD/qquickgraphicsdevice.cpp
qtConfig(quick-draganddrop) {
HEADERS += \
diff --git a/src/quick/items/qquickgraphicsdevice.cpp b/src/quick/items/qquickgraphicsdevice.cpp
new file mode 100644
index 0000000000..029546a5f8
--- /dev/null
+++ b/src/quick/items/qquickgraphicsdevice.cpp
@@ -0,0 +1,216 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickgraphicsdevice_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QQuickGraphicsDevice
+ \since 6.0
+ \inmodule QtQuick
+
+ \brief The QQuickGraphicsDevice class provides an opaque container for
+ native graphics objects representing graphics devices or contexts.
+
+ \sa QQuickWindow::setGraphicsDevice(), QQuickRenderTarget
+*/
+
+/*!
+ Constructs a default QQuickGraphicsDEvice that does not reference any native
+ objects.
+ */
+QQuickGraphicsDevice::QQuickGraphicsDevice()
+ : d(new QQuickGraphicsDevicePrivate)
+{
+}
+
+/*!
+ \internal
+ */
+void QQuickGraphicsDevice::detach()
+{
+ qAtomicDetach(d);
+}
+
+/*!
+ \internal
+ */
+QQuickGraphicsDevice::QQuickGraphicsDevice(const QQuickGraphicsDevice &other)
+ : d(other.d)
+{
+ d->ref.ref();
+}
+
+/*!
+ \internal
+ */
+QQuickGraphicsDevice &QQuickGraphicsDevice::operator=(const QQuickGraphicsDevice &other)
+{
+ qAtomicAssign(d, other.d);
+ return *this;
+}
+
+/*!
+ Destructor.
+ */
+QQuickGraphicsDevice::~QQuickGraphicsDevice()
+{
+ if (!d->ref.deref())
+ delete d;
+}
+
+/*!
+ Constructs a default QQuickRenderTarget that does not reference any native
+ objects.
+ */
+bool QQuickGraphicsDevice::isNull() const
+{
+ return d->type == QQuickGraphicsDevicePrivate::Type::Null;
+}
+
+/*!
+ \return a new QQuickGraphicsDevice referencing an existing QOpenGLContext.
+
+ This factory function is suitable for OpenGL.
+ */
+QQuickGraphicsDevice QQuickGraphicsDevice::fromOpenGLContext(QOpenGLContext *context)
+{
+ QQuickGraphicsDevice dev;
+ QQuickGraphicsDevicePrivate *d = QQuickGraphicsDevicePrivate::get(&dev);
+ d->type = QQuickGraphicsDevicePrivate::Type::OpenGLContext;
+ d->u.context = context;
+ return dev;
+}
+
+/*!
+ \return a new QQuickGraphicsDevice referencing a native device and context
+ object.
+
+ This factory function is suitable for:
+
+ \list
+
+ \li Direct3D11 - \a device is expected to be a \c{ID3D11Device*}, \a
+ context is expected to be a \c{ID3D11DeviceContext*}.
+
+ \endlist
+
+ \note the resulting QQuickGraphicsDevice does not own any native resources,
+ it merely contains references. It is the caller's responsibility to ensure
+ that the native resource exists as long as necessary.
+
+ */
+QQuickGraphicsDevice QQuickGraphicsDevice::fromDeviceAndContext(void *device, void *context)
+{
+ QQuickGraphicsDevice dev;
+ QQuickGraphicsDevicePrivate *d = QQuickGraphicsDevicePrivate::get(&dev);
+ d->type = QQuickGraphicsDevicePrivate::Type::DeviceAndContext;
+ d->u.deviceAndContext = { device, context };
+ return dev;
+}
+
+/*!
+ \return a new QQuickGraphicsDevice referencing a native device and command
+ queue object.
+
+ This factory function is suitable for:
+
+ \list
+
+ \li Metal - \a device is expected to be a \c{MTLDevice*}, \a cmdQueue is
+ expected to be a \c{MTLCommandQueue*}.
+
+ \endlist
+
+ \note the resulting QQuickGraphicsDevice does not own any native resources,
+ it merely contains references. It is the caller's responsibility to ensure
+ that the native resource exists as long as necessary.
+
+ */
+QQuickGraphicsDevice QQuickGraphicsDevice::fromDeviceAndCommandQueue(void *device, void *cmdQueue)
+{
+ QQuickGraphicsDevice dev;
+ QQuickGraphicsDevicePrivate *d = QQuickGraphicsDevicePrivate::get(&dev);
+ d->type = QQuickGraphicsDevicePrivate::Type::DeviceAndCommandQueue;
+ d->u.deviceAndCommandQueue = { device, cmdQueue };
+ return dev;
+}
+
+/*!
+ \return a new QQuickGraphicsDevice referencing a native device and related
+ objects.
+
+ This factory function is suitable for:
+
+ \list
+
+ \li Vulkan - \a physicalDevice is expected to be \c VkPhysicalDevice, \a
+ device is expected to be a \a VkDevice, while \a queueFamilyIndex is the
+ index of the graphics queue family on the device.
+
+ \endlist
+
+ \note the resulting QQuickGraphicsDevice does not own any native resources,
+ it merely contains references. It is the caller's responsibility to ensure
+ that the native resource exists as long as necessary.
+
+ */
+QQuickGraphicsDevice QQuickGraphicsDevice::fromDeviceObjects(void *physicalDevice, void *device, int queueFamilyIndex)
+{
+ QQuickGraphicsDevice dev;
+ QQuickGraphicsDevicePrivate *d = QQuickGraphicsDevicePrivate::get(&dev);
+ d->type = QQuickGraphicsDevicePrivate::Type::DeviceObjects;
+ d->u.deviceObjects = { physicalDevice, device, queueFamilyIndex };
+ return dev;
+}
+
+QQuickGraphicsDevicePrivate::QQuickGraphicsDevicePrivate()
+ : ref(1)
+{
+}
+
+QQuickGraphicsDevicePrivate::QQuickGraphicsDevicePrivate(const QQuickGraphicsDevicePrivate *other)
+ : ref(1),
+ type(other->type),
+ u(other->u)
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/items/qquickgraphicsdevice.h b/src/quick/items/qquickgraphicsdevice.h
new file mode 100644
index 0000000000..811d510a5f
--- /dev/null
+++ b/src/quick/items/qquickgraphicsdevice.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKGRAPHICSDEVICE_H
+#define QQUICKGRAPHICSDEVICE_H
+
+#include <QtQuick/qtquickglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickGraphicsDevicePrivate;
+class QOpenGLContext;
+
+class Q_QUICK_EXPORT QQuickGraphicsDevice
+{
+public:
+ QQuickGraphicsDevice();
+ ~QQuickGraphicsDevice();
+ QQuickGraphicsDevice(const QQuickGraphicsDevice &other);
+ QQuickGraphicsDevice &operator=(const QQuickGraphicsDevice &other);
+
+ bool isNull() const;
+
+ static QQuickGraphicsDevice fromOpenGLContext(QOpenGLContext *context);
+ static QQuickGraphicsDevice fromDeviceAndContext(void *device, void *context);
+ static QQuickGraphicsDevice fromDeviceAndCommandQueue(void *device, void *cmdQueue);
+ static QQuickGraphicsDevice fromDeviceObjects(void *physicalDevice, void *device, int queueFamilyIndex);
+
+private:
+ void detach();
+ QQuickGraphicsDevicePrivate *d;
+ friend class QQuickGraphicsDevicePrivate;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKGRAPHICSDEVICE_H
diff --git a/src/quick/items/qquickgraphicsdevice_p.h b/src/quick/items/qquickgraphicsdevice_p.h
new file mode 100644
index 0000000000..0a206725a6
--- /dev/null
+++ b/src/quick/items/qquickgraphicsdevice_p.h
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKGRAPHICSDEVICE_P_H
+#define QQUICKGRAPHICSDEVICE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuick/private/qtquickglobal_p.h>
+#include <QAtomicInt>
+#include "qquickgraphicsdevice.h"
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICK_PRIVATE_EXPORT QQuickGraphicsDevicePrivate
+{
+public:
+ static QQuickGraphicsDevicePrivate *get(QQuickGraphicsDevice *p) { return p->d; }
+ static const QQuickGraphicsDevicePrivate *get(const QQuickGraphicsDevice *p) { return p->d; }
+ QQuickGraphicsDevicePrivate();
+ QQuickGraphicsDevicePrivate(const QQuickGraphicsDevicePrivate *other);
+
+ enum class Type {
+ Null,
+ OpenGLContext,
+ DeviceAndContext,
+ DeviceAndCommandQueue,
+ DeviceObjects
+ };
+
+ QAtomicInt ref;
+ Type type = Type::Null;
+
+ struct DeviceAndContext {
+ void *device;
+ void *context;
+ };
+
+ struct DeviceAndCommandQueue {
+ void *device;
+ void *cmdQueue;
+ };
+
+ struct DeviceObjects {
+ void *physicalDevice;
+ void *device;
+ int queueFamilyIndex;
+ };
+
+ union {
+ QOpenGLContext *context;
+ DeviceAndContext deviceAndContext;
+ DeviceAndCommandQueue deviceAndCommandQueue;
+ DeviceObjects deviceObjects;
+ } u;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKGRAPHICSDEVICE_P_H
diff --git a/src/quick/items/qquickrendercontrol.cpp b/src/quick/items/qquickrendercontrol.cpp
index 190e0942ab..b14a3f35f7 100644
--- a/src/quick/items/qquickrendercontrol.cpp
+++ b/src/quick/items/qquickrendercontrol.cpp
@@ -43,29 +43,36 @@
#include <QtCore/QCoreApplication>
#include <QtCore/QTime>
#include <QtQuick/private/qquickanimatorcontroller_p.h>
+#include <QtQuick/private/qsgdefaultrendercontext_p.h>
+#include <QtQuick/private/qsgrhisupport_p.h>
#if QT_CONFIG(opengl)
# include <QOpenGLContext>
-# include <QtQuick/private/qsgdefaultrendercontext_p.h>
#if QT_CONFIG(quick_shadereffect)
# include <QtQuick/private/qquickopenglshadereffectnode_p.h>
#endif
#endif
#include <QtGui/private/qguiapplication_p.h>
#include <qpa/qplatformintegration.h>
+#include <QtGui/qoffscreensurface.h>
#include <QtQml/private/qqmlglobal_p.h>
#include <QtQuick/QQuickWindow>
+#include <QtQuick/QQuickRenderTarget>
#include <QtQuick/private/qquickwindow_p.h>
#include <QtQuick/private/qquickitem_p.h>
#include <QtQuick/private/qsgsoftwarerenderer_p.h>
#include <QtCore/private/qobject_p.h>
+#include <QtQuick/private/qquickwindow_p.h>
+#include <QtGui/private/qrhi_p.h>
+
QT_BEGIN_NAMESPACE
#if QT_CONFIG(opengl)
extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha);
#endif
+
/*!
\class QQuickRenderControl
@@ -136,9 +143,14 @@ extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_
QSGContext *QQuickRenderControlPrivate::sg = nullptr;
-QQuickRenderControlPrivate::QQuickRenderControlPrivate()
- : initialized(0),
- window(nullptr)
+QQuickRenderControlPrivate::QQuickRenderControlPrivate(QQuickRenderControl *renderControl)
+ : q(renderControl),
+ initialized(false),
+ window(nullptr),
+ rhi(nullptr),
+ cb(nullptr),
+ offscreenSurface(nullptr),
+ sampleCount(1)
{
if (!sg) {
qAddPostRoutine(cleanup);
@@ -158,7 +170,7 @@ void QQuickRenderControlPrivate::cleanup()
object \a parent.
*/
QQuickRenderControl::QQuickRenderControl(QObject *parent)
- : QObject(*(new QQuickRenderControlPrivate), parent)
+ : QObject(*(new QQuickRenderControlPrivate(this)), parent)
{
}
@@ -182,11 +194,16 @@ QQuickRenderControl::~QQuickRenderControl()
d->windowDestroyed();
delete d->rc;
+
+ d->resetRhi();
}
void QQuickRenderControlPrivate::windowDestroyed()
{
if (window) {
+ QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
+ cd->cleanupNodesOnShutdown();
+
rc->invalidate();
QQuickWindowPrivate::get(window)->animationController.reset();
@@ -215,6 +232,90 @@ void QQuickRenderControl::prepareThread(QThread *targetThread)
}
/*!
+ Sets the number of samples to use for multisampling. When \a sampleCount is
+ 0 or 1, multisampling is disabled.
+
+ \note This function is always used in combination with a multisample render
+ target, which means \a sampleCount must match the sample count passed to
+ QQuickRenderTarget::fromNativeTexture(), which in turn must match the
+ sample count of the native texture.
+
+ \since 6.0
+
+ \sa initialize(), QQuickRenderTarget
+ */
+void QQuickRenderControl::setSamples(int sampleCount)
+{
+ Q_D(QQuickRenderControl);
+ d->sampleCount = qMax(1, sampleCount);
+}
+
+/*!
+ \return the current sample count. 1 or 0 means no multisampling.
+
+ \since 6.0
+ */
+int QQuickRenderControl::samples() const
+{
+ Q_D(const QQuickRenderControl);
+ return d->sampleCount;
+}
+
+/*!
+ Initializes the scene graph resources. When using a graphics API, such as
+ Vulkan, Metal, OpenGL, or Direct3D, for Qt Quick rendering,
+ QQuickRenderControl will set up an appropriate rendering engine when this
+ function is called. This rendering infrastructure exists as long as the
+ QQuickRenderControl exists.
+
+ To control what graphics API Qt Quick uses, call
+ QQuickWindow::setSceneGraphBackend() with one of the
+ QSGRendererInterface:GraphicsApi constants. That must be done before
+ calling this function.
+
+ To prevent the scenegraph from creating its own device and context objects,
+ specify an appropriate QQuickGraphicsDevice, wrapping existing graphics
+ objects, by calling QQuickWindow::setGraphicsDevice().
+
+ \note This function does not need to be, and must not be, called when using
+ the \c software adaptation of Qt Quick.
+
+ \since 6.0
+
+ \sa QQuickRenderTarget, QQuickGraphicsDevice
+ */
+bool QQuickRenderControl::initialize()
+{
+ Q_D(QQuickRenderControl);
+
+ if (!d->window) {
+ qWarning("QQuickRenderControl::initialize called with no associated window");
+ return false;
+ }
+
+ if (!d->initRhi())
+ return false;
+
+ QQuickWindowPrivate *wd = QQuickWindowPrivate::get(d->window);
+ wd->rhi = d->rhi;
+
+ QSGDefaultRenderContext *renderContext = qobject_cast<QSGDefaultRenderContext *>(d->rc);
+ if (renderContext) {
+ QSGDefaultRenderContext::InitParams params;
+ params.rhi = d->rhi;
+ params.sampleCount = d->sampleCount;
+ params.initialSurfacePixelSize = d->window->size() * d->window->effectiveDevicePixelRatio();
+ params.maybeSurface = d->window;
+ renderContext->initialize(&params);
+ } else {
+ qWarning("QRhi is only compatible with default adaptation");
+ return false;
+ }
+
+ return true;
+}
+
+/*!
Initializes the scene graph resources. The context \a gl has to be the
current OpenGL context or null if it is not relevant because a Qt Quick
backend other than OpenGL is in use.
@@ -295,24 +396,33 @@ bool QQuickRenderControl::sync()
return false;
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(d->window);
+ // we may not have a d->rhi (software backend) hence the check is important
+ if (d->rhi) {
+ if (!d->rhi->isRecordingFrame()) {
+ qWarning("QQuickRenderControl can only sync when beginFrame() has been called");
+ return false;
+ }
+ if (!d->cb) {
+ qWarning("QQuickRenderControl cannot be used with QRhi when no QRhiCommandBuffer is provided");
+ return false;
+ }
+ cd->setCustomCommandBuffer(d->cb);
+ }
+
cd->syncSceneGraph();
d->rc->endSync();
- // TODO: find out if the sync actually caused a scenegraph update.
return true;
}
/*!
- Stop rendering and release resources. Requires a current context.
+ Stop rendering and release resources.
This is the equivalent of the cleanup operations that happen with a
real QQuickWindow when the window becomes hidden.
This function is called from the destructor. Therefore there will
- typically be no need to call it directly. Pay attention however to
- the fact that this requires the context, that was passed to
- initialize(), to be the current one at the time of destroying the
- QQuickRenderControl instance.
+ typically be no need to call it directly.
Once invalidate() has been called, it is possible to reuse the
QQuickRenderControl instance by calling initialize() again.
@@ -353,6 +463,19 @@ void QQuickRenderControl::render()
return;
QQuickWindowPrivate *cd = QQuickWindowPrivate::get(d->window);
+ // we may not have a d->rhi (software backend) hence the check is important
+ if (d->rhi) {
+ if (!d->rhi->isRecordingFrame()) {
+ qWarning("QQuickRenderControl can only render when beginFrame() has been called");
+ return;
+ }
+ if (!d->cb) {
+ qWarning("QQuickRenderControl cannot be used with QRhi when no QRhiCommandBuffer is provided");
+ return;
+ }
+ cd->setCustomCommandBuffer(d->cb);
+ }
+
cd->renderSceneGraph(d->window->size());
}
@@ -378,48 +501,50 @@ void QQuickRenderControl::render()
for example. This will lead to better performance.
*/
-/*!
- Grabs the contents of the scene and returns it as an image.
-
- \note Requires the context to be current.
- */
-QImage QQuickRenderControl::grab()
+QImage QQuickRenderControlPrivate::grab()
{
- Q_D(QQuickRenderControl);
- if (!d->window)
+ if (!window)
return QImage();
QImage grabContent;
- if (d->window->rendererInterface()->graphicsApi() == QSGRendererInterface::OpenGL) {
+ if (rhi) {
+
+ // As documented by QQuickWindow::grabWindow(): Nothing to do here, we
+ // do not support "grabbing" with an application-provided render target
+ // in Qt 6. (with the exception of the software backend because that
+ // does not support custom render targets, so the grab implementation
+ // here is still valuable)
+
+ } else if (window->rendererInterface()->graphicsApi() == QSGRendererInterface::OpenGL) {
#if QT_CONFIG(opengl)
- QQuickWindowPrivate *cd = QQuickWindowPrivate::get(d->window);
+ QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
cd->polishItems();
cd->syncSceneGraph();
- d->rc->endSync();
- render();
- const bool alpha = d->window->format().alphaBufferSize() > 0 && d->window->color().alpha() < 255;
- grabContent = qt_gl_read_framebuffer(d->window->size() * d->window->effectiveDevicePixelRatio(), alpha, alpha);
- if (QQuickRenderControl::renderWindowFor(d->window)) {
- grabContent.setDevicePixelRatio(d->window->effectiveDevicePixelRatio());
+ rc->endSync();
+ q->render();
+ const bool alpha = window->format().alphaBufferSize() > 0 && window->color().alpha() < 255;
+ grabContent = qt_gl_read_framebuffer(window->size() * window->effectiveDevicePixelRatio(), alpha, alpha);
+ if (QQuickRenderControl::renderWindowFor(window)) {
+ grabContent.setDevicePixelRatio(window->effectiveDevicePixelRatio());
}
#endif
#if QT_CONFIG(thread)
- } else if (d->window->rendererInterface()->graphicsApi() == QSGRendererInterface::Software) {
- QQuickWindowPrivate *cd = QQuickWindowPrivate::get(d->window);
+ } else if (window->rendererInterface()->graphicsApi() == QSGRendererInterface::Software) {
+ QQuickWindowPrivate *cd = QQuickWindowPrivate::get(window);
cd->polishItems();
cd->syncSceneGraph();
QSGSoftwareRenderer *softwareRenderer = static_cast<QSGSoftwareRenderer *>(cd->renderer);
if (softwareRenderer) {
- const qreal dpr = d->window->effectiveDevicePixelRatio();
- const QSize imageSize = d->window->size() * dpr;
+ const qreal dpr = window->effectiveDevicePixelRatio();
+ const QSize imageSize = window->size() * dpr;
grabContent = QImage(imageSize, QImage::Format_ARGB32_Premultiplied);
grabContent.setDevicePixelRatio(dpr);
QPaintDevice *prevDev = softwareRenderer->currentPaintDevice();
softwareRenderer->setCurrentPaintDevice(&grabContent);
softwareRenderer->markDirty();
- d->rc->endSync();
- render();
+ rc->endSync();
+ q->render();
softwareRenderer->setCurrentPaintDevice(prevDev);
}
#endif
@@ -474,6 +599,131 @@ QWindow *QQuickRenderControl::renderWindowFor(QQuickWindow *win, QPoint *offset)
return nullptr;
}
+/*!
+ \return the QQuickWindow this QQuickRenderControl is associated with.
+
+ \note A QQuickRenderControl gets associated with a QQuickWindow when
+ constructing the QQuickWindow. The return value from this function is null
+ before that point.
+
+ \since 6.0
+ */
+QQuickWindow *QQuickRenderControl::window() const
+{
+ Q_D(const QQuickRenderControl);
+ return d->window;
+}
+
+/*!
+ Specifies the start of a graphics frame. Calls to sync() or render() must
+ be enclosed by calls to beginFrame() and endFrame().
+
+ Unlike the earlier OpenGL-only world of Qt 5, rendering with other graphics
+ APIs requires more well-defined points of starting and ending a frame. When
+ manually driving the rendering loop via QQuickRenderControl, it now falls
+ to the user of QQuickRenderControl to specify these points.
+
+ A typical update step, including initialization of rendering into an
+ existing texture, could like like the following. The example snippet
+ assumes Direct3D 11 but the same concepts apply other graphics APIs as
+ well.
+
+ \badcode
+ if (!m_quickInitialized) {
+ m_quickWindow->setGraphicsDevice(QQuickGraphicsDevice::fromDeviceAndContext(m_engine->device(), m_engine->context()));
+
+ if (!m_renderControl->initialize())
+ qWarning("Failed to initialize redirected Qt Quick rendering");
+
+ m_quickWindow->setRenderTarget(QQuickRenderTarget::fromNativeTexture({ &m_res.texture, 0 },
+ QSize(QML_WIDTH, QML_HEIGHT),
+ SAMPLE_COUNT));
+
+ m_quickInitialized = true;
+ }
+
+ m_renderControl->polishItems();
+
+ m_renderControl->beginFrame();
+ m_renderControl->sync();
+ m_renderControl->render();
+ m_renderControl->endFrame(); // Qt Quick's rendering commands are submitted to the device context here
+ \endcode
+
+ \since 6.0
+
+ \sa endFrame(), initialize(), sync(), render(), QQuickGraphicsDevice, QQuickRenderTarget
+ */
+void QQuickRenderControl::beginFrame()
+{
+ Q_D(QQuickRenderControl);
+ if (!d->rhi || d->rhi->isRecordingFrame())
+ return;
+
+ d->rhi->beginOffscreenFrame(&d->cb, QRhi::ExternalContentsInPass); // must specify ExternalContents since we do not know in advance
+}
+
+/*!
+ Specifies the end of a graphics frame. Calls to sync() or render() must be
+ enclosed by calls to beginFrame() and endFrame().
+
+ When this function is called, any graphics commands enqueued by the
+ scenegraph are submitted to the context or command queue, whichever is
+ applicable.
+
+ \since 6.0
+
+ \sa beginFrame(), initialize(), sync(), render(), QQuickGraphicsDevice, QQuickRenderTarget
+ */
+void QQuickRenderControl::endFrame()
+{
+ Q_D(QQuickRenderControl);
+ if (!d->rhi || !d->rhi->isRecordingFrame())
+ return;
+
+ d->rhi->endOffscreenFrame();
+ d->cb = nullptr;
+}
+
+bool QQuickRenderControlPrivate::initRhi()
+{
+ // initialize() - invalidate() - initialize() uses the QRhi the first
+ // initialize() created, so if already exists, we are done
+ if (rhi)
+ return true;
+
+ QSGRhiSupport *rhiSupport = QSGRhiSupport::instance();
+
+ // sanity check for Vulkan
+#if QT_CONFIG(vulkan)
+ if (rhiSupport->rhiBackend() == QRhi::Vulkan && !window->vulkanInstance()) {
+ qWarning("QQuickRenderControl: No QVulkanInstance set for QQuickWindow, cannot initialize");
+ return false;
+ }
+#endif
+
+ // for OpenGL
+ if (!offscreenSurface)
+ offscreenSurface = rhiSupport->maybeCreateOffscreenSurface(window);
+
+ rhi = rhiSupport->createRhi(window, offscreenSurface);
+ if (!rhi) {
+ qWarning("QQuickRenderControl: Failed to initialize QRhi");
+ return false;
+ }
+
+ return true;
+}
+
+void QQuickRenderControlPrivate::resetRhi()
+{
+ delete rhi;
+ rhi = nullptr;
+
+ delete offscreenSurface;
+ offscreenSurface = nullptr;
+}
+
QT_END_NAMESPACE
#include "moc_qquickrendercontrol.cpp"
diff --git a/src/quick/items/qquickrendercontrol.h b/src/quick/items/qquickrendercontrol.h
index 8ec9b8aafc..cdcad589f6 100644
--- a/src/quick/items/qquickrendercontrol.h
+++ b/src/quick/items/qquickrendercontrol.h
@@ -41,7 +41,7 @@
#define QQUICKRENDERCONTROL_H
#include <QtQuick/qtquickglobal.h>
-#include <QtGui/QImage>
+#include <QtGui/qimage.h>
QT_BEGIN_NAMESPACE
@@ -59,18 +59,27 @@ public:
~QQuickRenderControl() override;
void prepareThread(QThread *targetThread);
- void initialize(QOpenGLContext *gl);
+
+ void setSamples(int sampleCount);
+ int samples() const;
+
+ bool initialize();
+ void initialize(QOpenGLContext *gl); // ### Qt 6 remove
+
void invalidate();
+ void beginFrame();
+ void endFrame();
+
void polishItems();
- void render();
bool sync();
-
- QImage grab();
+ void render();
static QWindow *renderWindowFor(QQuickWindow *win, QPoint *offset = nullptr);
virtual QWindow *renderWindow(QPoint *offset) { Q_UNUSED(offset); return nullptr; }
+ QQuickWindow *window() const;
+
Q_SIGNALS:
void renderRequested();
void sceneChanged();
diff --git a/src/quick/items/qquickrendercontrol_p.h b/src/quick/items/qquickrendercontrol_p.h
index 487af45db5..c24ea9b8c6 100644
--- a/src/quick/items/qquickrendercontrol_p.h
+++ b/src/quick/items/qquickrendercontrol_p.h
@@ -56,12 +56,16 @@
QT_BEGIN_NAMESPACE
-class QQuickRenderControlPrivate : public QObjectPrivate
+class QRhi;
+class QRhiCommandBuffer;
+class QOffscreenSurface;
+
+class Q_AUTOTEST_EXPORT QQuickRenderControlPrivate : public QObjectPrivate
{
public:
Q_DECLARE_PUBLIC(QQuickRenderControl)
- QQuickRenderControlPrivate();
+ QQuickRenderControlPrivate(QQuickRenderControl *renderControl);
static QQuickRenderControlPrivate *get(QQuickRenderControl *renderControl) {
return renderControl->d_func();
@@ -74,10 +78,20 @@ public:
void update();
void maybeUpdate();
+ bool initRhi();
+ void resetRhi();
+
+ QImage grab();
+
+ QQuickRenderControl *q;
bool initialized;
QQuickWindow *window;
static QSGContext *sg;
QSGRenderContext *rc;
+ QRhi *rhi;
+ QRhiCommandBuffer *cb;
+ QOffscreenSurface *offscreenSurface;
+ int sampleCount;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickrendertarget.cpp b/src/quick/items/qquickrendertarget.cpp
new file mode 100644
index 0000000000..924824e456
--- /dev/null
+++ b/src/quick/items/qquickrendertarget.cpp
@@ -0,0 +1,293 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickrendertarget_p.h"
+#include <QtGui/private/qrhi_p.h>
+#include <QtQuick/private/qquickitem_p.h>
+#include <QtQuick/private/qquickwindow_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QQuickRenderTarget
+ \since 6.0
+ \inmodule QtQuick
+
+ \brief The QQuickRenderTarget class provides an opaque container for native
+ graphics resources specifying a render target, and associated metadata.
+
+ \sa QQuickWindow::setRenderTarget(), QQuickGraphicsDevice
+*/
+
+QQuickRenderTargetPrivate::QQuickRenderTargetPrivate()
+ : ref(1)
+{
+}
+
+QQuickRenderTargetPrivate::QQuickRenderTargetPrivate(const QQuickRenderTargetPrivate *other)
+ : ref(1),
+ type(other->type),
+ pixelSize(other->pixelSize),
+ sampleCount(other->sampleCount),
+ u(other->u)
+{
+}
+
+/*!
+ Constructs a default QQuickRenderTarget that does not reference any native
+ objects.
+ */
+QQuickRenderTarget::QQuickRenderTarget()
+ : d(new QQuickRenderTargetPrivate)
+{
+}
+
+/*!
+ \internal
+ */
+void QQuickRenderTarget::detach()
+{
+ qAtomicDetach(d);
+}
+
+/*!
+ \internal
+ */
+QQuickRenderTarget::QQuickRenderTarget(const QQuickRenderTarget &other)
+ : d(other.d)
+{
+ d->ref.ref();
+}
+
+/*!
+ \internal
+ */
+QQuickRenderTarget &QQuickRenderTarget::operator=(const QQuickRenderTarget &other)
+{
+ qAtomicAssign(d, other.d);
+ return *this;
+}
+
+/*!
+ Destructor.
+ */
+QQuickRenderTarget::~QQuickRenderTarget()
+{
+ if (!d->ref.deref())
+ delete d;
+}
+
+/*!
+ \return true if this QQuickRenderTarget is default constructed, referencing
+ no native objects.
+ */
+bool QQuickRenderTarget::isNull() const
+{
+ return d->type == QQuickRenderTargetPrivate::Type::Null;
+}
+
+/*!
+ \return a new QQuickRenderTarget referencing a native texture or image
+ object.
+
+ \a nativeTexture references a native resource, for example, a \c VkImage,
+ \c ID3D11Texture2D*, c MTLTexture*, or \c GLuint. Where applicable, this
+ must be complemented by the current layout of the image.
+
+ \note the \c object field in \a nativeTexture must always be a pointer to
+ the native object, even if the type is already a pointer.
+
+ \a pixelSize specifies the size of the image, in pixels. Currently only 2D
+ textures are supported.
+
+ \a sampleCount specific the number of samples. 0 or 1 means no
+ multisampling, while a value like 4 or 8 states that the native object is a
+ multisample texture.
+
+ \note the resulting QQuickRenderTarget does not own any native resources,
+ it merely contains references and the associated metadata of the size and
+ sample count. It is the caller's responsibility to ensure that the native
+ resource exists as long as necessary.
+
+ \sa QQuickWindow::setRenderTarget(), QQuickRenderControl
+ */
+QQuickRenderTarget QQuickRenderTarget::fromNativeTexture(const QSGTexture::NativeTexture &nativeTexture,
+ const QSize &pixelSize,
+ int sampleCount)
+{
+ QQuickRenderTarget rt;
+ QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(&rt);
+
+ if (!nativeTexture.object) {
+ qWarning("QQuickRenderTarget: nativeTexture.object is null");
+ return rt;
+ }
+
+ if (pixelSize.isEmpty()) {
+ qWarning("QQuickRenderTarget: Cannot create with empty size");
+ return rt;
+ }
+
+ d->type = QQuickRenderTargetPrivate::Type::NativeTexture;
+ d->pixelSize = pixelSize;
+ d->sampleCount = qMax(1, sampleCount);
+ d->u.nativeTexture = nativeTexture;
+
+ return rt;
+}
+
+/*!
+ \internal
+ */
+QQuickRenderTarget QQuickRenderTarget::fromRhiRenderTarget(QRhiRenderTarget *renderTarget)
+{
+ QQuickRenderTarget rt;
+ QQuickRenderTargetPrivate *d = QQuickRenderTargetPrivate::get(&rt);
+
+ if (!renderTarget) {
+ qWarning("QQuickRenderTarget: Needs a valid QRhiRenderTarget");
+ return rt;
+ }
+
+ d->type = QQuickRenderTargetPrivate::Type::RhiRenderTarget;
+ d->pixelSize = renderTarget->pixelSize();
+ d->sampleCount = renderTarget->sampleCount();
+ d->u.rhiRt = renderTarget;
+
+ return rt;
+}
+
+/*!
+ \return true if \a a and \a b refer to the same set of native objects and
+ have matching associated data (size, sample count).
+ */
+bool operator==(const QQuickRenderTarget &a, const QQuickRenderTarget &b) Q_DECL_NOTHROW
+{
+ const QQuickRenderTargetPrivate *da = QQuickRenderTargetPrivate::get(&a);
+ const QQuickRenderTargetPrivate *db = QQuickRenderTargetPrivate::get(&b);
+ if (da->type != db->type
+ || da->pixelSize != db->pixelSize
+ || da->sampleCount != db->sampleCount)
+ {
+ return false;
+ }
+
+ switch (da->type) {
+ case QQuickRenderTargetPrivate::Type::Null:
+ break;
+ case QQuickRenderTargetPrivate::Type::NativeTexture:
+ if (da->u.nativeTexture.object != db->u.nativeTexture.object
+ || da->u.nativeTexture.layout != db->u.nativeTexture.layout)
+ return false;
+ break;
+ case QQuickRenderTargetPrivate::Type::RhiRenderTarget:
+ if (da->u.rhiRt != db->u.rhiRt)
+ return false;
+ break;
+ default:
+ break;
+ }
+
+ return true;
+}
+
+/*!
+ \return true if \a a and \a b refer to a different set of native objects,
+ or the associated data (size, sample count) does not match.
+ */
+bool operator!=(const QQuickRenderTarget &a, const QQuickRenderTarget &b) Q_DECL_NOTHROW
+{
+ return !(a == b);
+}
+
+bool QQuickRenderTargetPrivate::resolve(QRhi *rhi, QQuickWindowRenderTarget *dst)
+{
+ switch (type) {
+ case Type::Null:
+ dst->renderTarget = nullptr;
+ dst->owns = false;
+ return true;
+
+ case Type::NativeTexture:
+ {
+ QRhiTexture *texture = rhi->newTexture(QRhiTexture::RGBA8, pixelSize, sampleCount, QRhiTexture::RenderTarget);
+ if (!texture->buildFrom({ u.nativeTexture.object, u.nativeTexture.layout })) {
+ qWarning("Failed to build texture for QQuickRenderTarget");
+ return false;
+ }
+ QRhiRenderBuffer *depthStencil = rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, pixelSize, sampleCount);
+ if (!depthStencil->build()) {
+ qWarning("Failed to build depth-stencil buffer for QQuickRenderTarget");
+ delete texture;
+ return false;
+ }
+
+ QRhiColorAttachment att(texture);
+ QRhiTextureRenderTargetDescription rtDesc(att);
+ rtDesc.setDepthStencilBuffer(depthStencil);
+ QRhiTextureRenderTarget *rt = rhi->newTextureRenderTarget(rtDesc);
+ QRhiRenderPassDescriptor *rp = rt->newCompatibleRenderPassDescriptor();
+ rt->setRenderPassDescriptor(rp);
+ if (!rt->build()) {
+ qWarning("Failed to build texture render target for QQuickRenderTarget");
+ delete rp;
+ delete depthStencil;
+ delete texture;
+ return false;
+ }
+ dst->renderTarget = rt;
+ dst->rpDesc = rp;
+ dst->texture = texture;
+ dst->depthStencil = depthStencil;
+ dst->owns = true; // ownership of the native resource itself is not transferred but the QRhi objects are on us now
+ }
+ return true;
+
+ case Type::RhiRenderTarget:
+ dst->renderTarget = u.rhiRt;
+ dst->owns = false;
+ return true;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quick/items/qquickrendertarget.h b/src/quick/items/qquickrendertarget.h
new file mode 100644
index 0000000000..5139046ad4
--- /dev/null
+++ b/src/quick/items/qquickrendertarget.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKRENDERTARGET_H
+#define QQUICKRENDERTARGET_H
+
+#include <QtQuick/qtquickglobal.h>
+#include <QtQuick/qsgtexture.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickRenderTargetPrivate;
+class QRhiRenderTarget;
+
+class Q_QUICK_EXPORT QQuickRenderTarget
+{
+public:
+ QQuickRenderTarget();
+ ~QQuickRenderTarget();
+ QQuickRenderTarget(const QQuickRenderTarget &other);
+ QQuickRenderTarget &operator=(const QQuickRenderTarget &other);
+
+ bool isNull() const;
+
+ static QQuickRenderTarget fromNativeTexture(const QSGTexture::NativeTexture &nativeTexture,
+ const QSize &pixelSize,
+ int sampleCount = 1);
+
+ static QQuickRenderTarget fromRhiRenderTarget(QRhiRenderTarget *renderTarget);
+
+private:
+ void detach();
+ QQuickRenderTargetPrivate *d;
+ friend class QQuickRenderTargetPrivate;
+};
+
+Q_QUICK_EXPORT bool operator==(const QQuickRenderTarget &a, const QQuickRenderTarget &b) Q_DECL_NOTHROW;
+Q_QUICK_EXPORT bool operator!=(const QQuickRenderTarget &a, const QQuickRenderTarget &b) Q_DECL_NOTHROW;
+
+QT_END_NAMESPACE
+
+#endif // QQUICKRENDERTARGET_H
diff --git a/src/quick/items/qquickrendertarget_p.h b/src/quick/items/qquickrendertarget_p.h
new file mode 100644
index 0000000000..628e5c277b
--- /dev/null
+++ b/src/quick/items/qquickrendertarget_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtQuick module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKRENDERTARGET_P_H
+#define QQUICKRENDERTARGET_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuick/private/qtquickglobal_p.h>
+#include "qquickrendertarget.h"
+#include <QAtomicInt>
+
+QT_BEGIN_NAMESPACE
+
+class QRhi;
+class QQuickWindowRenderTarget;
+
+class Q_QUICK_PRIVATE_EXPORT QQuickRenderTargetPrivate
+{
+public:
+ static QQuickRenderTargetPrivate *get(QQuickRenderTarget *rt) { return rt->d; }
+ static const QQuickRenderTargetPrivate *get(const QQuickRenderTarget *rt) { return rt->d; }
+ QQuickRenderTargetPrivate();
+ QQuickRenderTargetPrivate(const QQuickRenderTargetPrivate *other);
+ bool resolve(QRhi *rhi, QQuickWindowRenderTarget *dst);
+
+ enum class Type {
+ Null,
+ NativeTexture,
+ RhiRenderTarget
+ };
+
+ QAtomicInt ref;
+ Type type = Type::Null;
+ QSize pixelSize;
+ int sampleCount = 1;
+ union {
+ QSGTexture::NativeTexture nativeTexture;
+ QRhiRenderTarget *rhiRt;
+ } u;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKRENDERTARGET_P_H
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 4874af44ed..bb3aff0cd6 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -43,6 +43,7 @@
#include "qquickitem.h"
#include "qquickitem_p.h"
#include "qquickevents_p_p.h"
+#include "qquickgraphicsdevice_p.h"
#if QT_CONFIG(quick_draganddrop)
#include <private/qquickdrag_p.h>
@@ -424,16 +425,66 @@ void forceUpdate(QQuickItem *item)
forceUpdate(items.at(i));
}
+void QQuickWindowRenderTarget::reset(QRhi *rhi)
+{
+ if (rhi && owns) {
+ delete renderTarget;
+ delete rpDesc;
+ delete texture;
+ delete depthStencil;
+ }
+
+ renderTarget = nullptr;
+ rpDesc = nullptr;
+ texture = nullptr;
+ depthStencil = nullptr;
+ owns = false;
+}
+
+void QQuickWindowPrivate::ensureCustomRenderTarget()
+{
+ // resolve() can be expensive when importing an existing native texture, so
+ // it is important to only do it when the QQuickRenderTarget* was really changed
+ if (!redirect.renderTargetDirty || !rhi)
+ return;
+
+ redirect.renderTargetDirty = false;
+
+ redirect.rt.reset(rhi);
+
+ // a default constructed QQuickRenderTarget means no redirection
+ if (customRenderTarget.isNull())
+ return;
+
+ QQuickRenderTargetPrivate::get(&customRenderTarget)->resolve(rhi, &redirect.rt);
+}
+
+void QQuickWindowPrivate::setCustomCommandBuffer(QRhiCommandBuffer *cb)
+{
+ // ownership not transferred
+ redirect.commandBuffer = cb;
+}
+
void QQuickWindowPrivate::syncSceneGraph()
{
Q_Q(QQuickWindow);
+ ensureCustomRenderTarget();
+
// Calculate the dpr the same way renderSceneGraph() will.
qreal devicePixelRatio = q->effectiveDevicePixelRatio();
- if (renderTargetId && !QQuickRenderControl::renderWindowFor(q))
+ const bool hasCustomRenderTarget = customRenderTargetGl.renderTargetId || redirect.rt.renderTarget;
+ if (hasCustomRenderTarget && !QQuickRenderControl::renderWindowFor(q))
devicePixelRatio = 1;
- context->prepareSync(devicePixelRatio, rhi ? swapchain->currentFrameCommandBuffer() : nullptr);
+ QRhiCommandBuffer *cb = nullptr;
+ if (rhi) {
+ if (redirect.commandBuffer)
+ cb = redirect.commandBuffer;
+ else
+ cb = swapchain->currentFrameCommandBuffer();
+ }
+ context->prepareSync(devicePixelRatio, cb);
animationController->beforeNodeSync();
@@ -484,11 +535,32 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size, const QSize &surfa
return;
if (rhi) {
- // ### no offscreen ("renderTargetId") support yet
- context->beginNextRhiFrame(renderer,
- swapchain->currentFrameRenderTarget(),
- rpDescForSwapchain,
- swapchain->currentFrameCommandBuffer(),
+ ensureCustomRenderTarget();
+ QRhiRenderTarget *rt;
+ QRhiRenderPassDescriptor *rp;
+ QRhiCommandBuffer *cb;
+ if (redirect.rt.renderTarget) {
+ rt = redirect.rt.renderTarget;
+ rp = rt->renderPassDescriptor();
+ if (!rp) {
+ qWarning("Custom render target is set but no renderpass descriptor has been provided.");
+ return;
+ }
+ cb = redirect.commandBuffer;
+ if (!cb) {
+ qWarning("Custom render target is set but no command buffer has been provided.");
+ return;
+ }
+ } else {
+ if (!swapchain) {
+ qWarning("QQuickWindow: No render target (neither swapchain nor custom target was provided)");
+ return;
+ }
+ rt = swapchain->currentFrameRenderTarget();
+ rp = rpDescForSwapchain;
+ cb = swapchain->currentFrameCommandBuffer();
+ }
+ context->beginNextRhiFrame(renderer, rt, rp, cb,
emitBeforeRenderPassRecording,
emitAfterRenderPassRecording,
q);
@@ -503,18 +575,28 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size, const QSize &surfa
emit q->beforeRendering();
runAndClearJobs(&beforeRenderingJobs);
if (!customRenderStage || !customRenderStage->render()) {
+ QSGAbstractRenderer::MatrixTransformFlags matrixFlags;
+ const bool flipY = rhi ? !rhi->isYUpInNDC() : false;
+ if (flipY)
+ matrixFlags |= QSGAbstractRenderer::MatrixTransformFlipY;
int fboId = 0;
const qreal devicePixelRatio = q->effectiveDevicePixelRatio();
- if (renderTargetId) {
- QRect rect(QPoint(0, 0), renderTargetSize);
- fboId = renderTargetId;
+ const bool hasCustomRenderTarget = customRenderTargetGl.renderTargetId || redirect.rt.renderTarget;
+ if (hasCustomRenderTarget) {
+ QRect rect;
+ if (redirect.rt.renderTarget) {
+ rect = QRect(QPoint(0, 0), redirect.rt.renderTarget->pixelSize());
+ } else {
+ fboId = customRenderTargetGl.renderTargetId;
+ rect = QRect(QPoint(0, 0), customRenderTargetGl.renderTargetSize);
+ }
renderer->setDeviceRect(rect);
renderer->setViewportRect(rect);
if (QQuickRenderControl::renderWindowFor(q)) {
- renderer->setProjectionMatrixToRect(QRect(QPoint(0, 0), size));
+ renderer->setProjectionMatrixToRect(QRect(QPoint(0, 0), size), matrixFlags);
renderer->setDevicePixelRatio(devicePixelRatio);
} else {
- renderer->setProjectionMatrixToRect(QRect(QPoint(0, 0), rect.size()));
+ renderer->setProjectionMatrixToRect(QRect(QPoint(0, 0), rect.size()), matrixFlags);
renderer->setDevicePixelRatio(1);
}
} else {
@@ -530,10 +612,6 @@ void QQuickWindowPrivate::renderSceneGraph(const QSize &size, const QSize &surfa
QRect rect(QPoint(0, 0), pixelSize);
renderer->setDeviceRect(rect);
renderer->setViewportRect(rect);
- const bool flipY = rhi ? !rhi->isYUpInNDC() : false;
- QSGAbstractRenderer::MatrixTransformFlags matrixFlags;
- if (flipY)
- matrixFlags |= QSGAbstractRenderer::MatrixTransformFlipY;
renderer->setProjectionMatrixToRect(QRectF(QPoint(0, 0), logicalSize), matrixFlags);
renderer->setDevicePixelRatio(devicePixelRatio);
}
@@ -589,8 +667,6 @@ QQuickWindowPrivate::QQuickWindowPrivate()
, allowChildEventFiltering(true)
, allowDoubleClick(true)
, lastFocusReason(Qt::OtherFocusReason)
- , renderTarget(nullptr)
- , renderTargetId(0)
, vaoHelper(nullptr)
, incubationController(nullptr)
, hasActiveSwapchain(false)
@@ -604,6 +680,7 @@ QQuickWindowPrivate::QQuickWindowPrivate()
QQuickWindowPrivate::~QQuickWindowPrivate()
{
+ redirect.rt.reset(rhi);
delete customRenderStage;
if (QQmlInspectorService *service = QQmlDebugConnector::service<QQmlInspectorService>())
service->removeWindow(q_func());
@@ -652,7 +729,7 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control)
q->setSurfaceType(windowManager ? windowManager->windowSurfaceType() : QSurface::OpenGLSurface);
q->setFormat(sg->defaultSurfaceFormat());
#if QT_CONFIG(vulkan)
- if (q->surfaceType() == QSurface::VulkanSurface)
+ if (!renderControl && q->surfaceType() == QSurface::VulkanSurface)
q->setVulkanInstance(QSGRhiSupport::vulkanInstance());
#endif
@@ -4028,13 +4105,13 @@ void QQuickWindow::setRenderTarget(QOpenGLFramebufferObject *fbo)
return;
}
- d->renderTarget = fbo;
+ d->customRenderTargetGl.renderTarget = fbo;
if (fbo) {
- d->renderTargetId = fbo->handle();
- d->renderTargetSize = fbo->size();
+ d->customRenderTargetGl.renderTargetId = fbo->handle();
+ d->customRenderTargetGl.renderTargetSize = fbo->size();
} else {
- d->renderTargetId = 0;
- d->renderTargetSize = QSize();
+ d->customRenderTargetGl.renderTargetId = 0;
+ d->customRenderTargetGl.renderTargetSize = QSize();
}
}
#endif
@@ -4069,11 +4146,11 @@ void QQuickWindow::setRenderTarget(uint fboId, const QSize &size)
return;
}
- d->renderTargetId = fboId;
- d->renderTargetSize = size;
+ d->customRenderTargetGl.renderTargetId = fboId;
+ d->customRenderTargetGl.renderTargetSize = size;
// Unset any previously set instance...
- d->renderTarget = nullptr;
+ d->customRenderTargetGl.renderTarget = nullptr;
}
@@ -4083,7 +4160,7 @@ void QQuickWindow::setRenderTarget(uint fboId, const QSize &size)
uint QQuickWindow::renderTargetId() const
{
Q_D(const QQuickWindow);
- return d->renderTargetId;
+ return d->customRenderTargetGl.renderTargetId;
}
/*!
@@ -4092,11 +4169,9 @@ uint QQuickWindow::renderTargetId() const
QSize QQuickWindow::renderTargetSize() const
{
Q_D(const QQuickWindow);
- return d->renderTargetSize;
+ return d->customRenderTargetGl.renderTargetSize;
}
-
-
#if QT_CONFIG(opengl)
/*!
Returns the render target for this window.
@@ -4113,11 +4188,84 @@ QSize QQuickWindow::renderTargetSize() const
QOpenGLFramebufferObject *QQuickWindow::renderTarget() const
{
Q_D(const QQuickWindow);
- return d->renderTarget;
+ return d->customRenderTargetGl.renderTarget;
}
#endif
/*!
+ Sets the render target for this window to be \a target.
+
+ A QQuickRenderTarget serves as an opaque handle for a renderable native
+ object, most commonly a 2D texture, and associated metadata, such as the
+ size in pixels.
+
+ A default constructed QQuickRenderTarget means no redirection. A valid
+ \a target, created via one of the static QQuickRenderTarget factory functions,
+ on the other hand, enables redirection of the rendering of the Qt Quick
+ scene: it will no longer target the color buffers for the surface
+ associated with the window, but rather the textures or other graphics
+ objects specified in \a target.
+
+ For example, assuming the scenegraph is using Vulkan to render, one can
+ redirect its output into a \c VkImage. For graphics APIs like Vulkan, the
+ image layout must be provided as well. QQuickRenderTarget instances are
+ implicitly shared and are copyable and can be passed by value. They do not
+ own the associated native objects (such as, the VkImage in the example),
+ however.
+
+ \badcode
+ QQuickRenderTarget rt = QQuickRenderTarget::fromNativeTexture({ &vulkanImage, VK_IMAGE_LAYOUT_PREINITIALIZED }, pixelSize);
+ quickWindow->setRenderTarget(rt);
+ \endcode
+
+ This function is very often used in combination with QQuickRenderControl
+ and an invisible QQuickWindow, in order to render Qt Quick content into a
+ texture, without creating an on-screen native window for this QQuickWindow.
+
+ When the desired target, or associated data, such as the size, changes,
+ call this function with a new QQuickRenderTarget. Constructing
+ QQuickRenderTarget instances and calling this function is cheap, but be
+ aware that setting a new \a target with a different native object or other
+ data may lead to potentially expensive initialization steps when the
+ scenegraph is about to render the next frame. Therefore change the target
+ only when necessary.
+
+ \note This function should not be used when using the \c software backend.
+ Instead, use grabWindow() to render the content into a QImage.
+
+ \note The window does not take ownership of any native objects referenced
+ in \a target.
+
+ \note It is the caller's responsibility to ensure the native objects
+ referred to in \a target are valid for the scenegraph renderer too. For
+ instance, with Vulkan, Metal, and Direct3D this implies that the texture or
+ image is created on the same graphics device that is used by the scenegraph
+ internally. This is often achieved by using this function in combination
+ with setGraphicsDevice().
+
+ \note With graphics APIs where relevant, the application must pay attention
+ to image layout transitions performed by the scenegraph. For example, once
+ a VkImage is associated with the scenegraph by calling this function, its
+ layout will transition to \c VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL when
+ rendering a frame.
+
+ \warning This function can only be called from the thread doing the
+ rendering.
+
+ \since 6.0
+
+ \sa QQuickRenderControl, setGraphicsDevice(), setSceneGraphBackend()
+ */
+void QQuickWindow::setRenderTarget(const QQuickRenderTarget &target)
+{
+ Q_D(QQuickWindow);
+ if (target != d->customRenderTarget) {
+ d->customRenderTarget = target;
+ d->redirect.renderTargetDirty = true;
+ }
+}
+
+/*!
Grabs the contents of the window and returns it as an image.
It is possible to call the grabWindow() function when the window is not
@@ -4125,6 +4273,14 @@ QOpenGLFramebufferObject *QQuickWindow::renderTarget() const
and has a valid size and that no other QQuickWindow instances are rendering
in the same process.
+ \note When using this window in combination with QQuickRenderControl, the
+ result of this function is an empty image, unless the \c software backend
+ is in use. This is because when redirecting the output to an
+ application-managed graphics resource (such as, a texture) by using
+ QQuickRenderControl and setRenderTarget(), the application is better suited
+ for managing and executing an eventual read back operation, since it is in
+ full control of the resource to begin with.
+
\warning Calling this function will cause performance problems.
\warning This function can only be called from the GUI thread.
@@ -4141,12 +4297,8 @@ QImage QQuickWindow::grabWindow()
if (!isVisible() && !d->renderControl) {
if (d->rhi) {
- // ### we may need a full offscreen round when non-exposed...
-
- if (d->renderControl)
- return d->renderControl->grab();
- else if (d->windowManager)
- return d->windowManager->grab(this);
+ if (d->windowManager)
+ return d->windowManager->grab(this); // ### we may need a full offscreen round when non-exposed?
return QImage();
}
@@ -4184,7 +4336,7 @@ QImage QQuickWindow::grabWindow()
}
if (d->renderControl)
- return d->renderControl->grab();
+ return QQuickRenderControlPrivate::get(d->renderControl)->grab();
else if (d->windowManager)
return d->windowManager->grab(this);
return QImage();
@@ -5648,7 +5800,11 @@ QSGRendererInterface *QQuickWindow::rendererInterface() const
loaded plugins.
\note The call to the function must happen before constructing the first
- QQuickWindow in the application. It cannot be changed afterwards.
+ QQuickWindow in the application. The graphics API cannot be changed
+ afterwards. When used in combination with QQuickRenderControl, this rule is
+ relaxed: it is possible to change the graphics API, but only when all
+ existing QQuickRenderControl and QQuickWindow instances have been
+ destroyed.
If the selected backend is invalid or an error occurs, the default backend
(OpenGL or software, depending on the Qt configuration) is used.
@@ -5709,6 +5865,65 @@ QString QQuickWindow::sceneGraphBackend()
}
/*!
+ Sets the graphics device objects for this window. The scenegraph will use
+ existing device, physical device, and other objects specified by \a device
+ instead of creating new ones.
+
+ This function is very often used in combination with QQuickRenderControl
+ and setRenderTarget(), in order to redirect Qt Quick rendering into a
+ texture.
+
+ A default constructed QQuickGraphicsDevice does not change the default
+ behavior in any way. Once a \a device created via one of the
+ QQuickGraphicsDevice factory functions, such as,
+ QQuickGraphicsDevice::fromDeviceObjects(), is passed in, and the scenegraph
+ uses a matching graphics API (with the example of fromDeviceObjects(), that
+ would be Vulkan), the scenegraph will use the existing device objects (such
+ as, the \c VkPhysicalDevice, \c VkDevice, and graphics queue family index,
+ in case of Vulkan) encapsulated by the QQuickGraphicsDevice. This allows
+ using the same device, and so sharing resources, such as buffers and
+ textures, between Qt Quick and native rendering engines.
+
+ \warning This function can only be called before initializing the
+ scenegraph and will have no effect if called afterwards. In practice this
+ typically means calling it right before QQuickRenderControl::initialize().
+
+ As an example, this time with Direct3D, the typical usage is expected to be
+ the following:
+
+ \badcode
+ // native graphics resources set up by a custom D3D rendering engine
+ ID3D11Device *device;
+ ID3D11DeviceContext *context;
+ ID3D11Texture2D *texture;
+ ...
+ // now to redirect Qt Quick content into 'texture' we could do the following:
+ QQuickRenderControl *renderControl = new QQuickRenderControl;
+ QQuickWindow *window = new QQuickWindow(renderControl); // this window will never be shown on-screen
+ ...
+ window->setGraphicsDevice(QQuickGraphicsDevice::fromDeviceAndContext(device, context));
+ renderControl->initialize();
+ window->setRenderTarget(QQuickRenderTarget::fromNativeTexture({ &texture, 0 }, textureSize);
+ ...
+ \endcode
+
+ The key aspect of using this function is to ensure that resources or
+ handles to resources, such as \c texture in the above example, are visible
+ to and usable by both the external rendering engine and the scenegraph
+ renderer. This requires using the same graphics device (or with OpenGL,
+ OpenGL context).
+
+ \since 6.0
+
+ \sa QQuickRenderControl, setRenderTarget(), setSceneGraphBackend()
+ */
+void QQuickWindow::setGraphicsDevice(const QQuickGraphicsDevice &device)
+{
+ Q_D(QQuickWindow);
+ d->customDeviceObjects = device;
+}
+
+/*!
Creates a simple rectangle node. When the scenegraph is not initialized, the return value is null.
This is cross-backend alternative to constructing a QSGSimpleRectNode directly.
diff --git a/src/quick/items/qquickwindow.h b/src/quick/items/qquickwindow.h
index 1331d036e1..a2278a8df0 100644
--- a/src/quick/items/qquickwindow.h
+++ b/src/quick/items/qquickwindow.h
@@ -66,7 +66,8 @@ class QQuickRenderControl;
class QSGRectangleNode;
class QSGImageNode;
class QSGNinePatchNode;
-class QRhi;
+class QQuickRenderTarget;
+class QQuickGraphicsDevice;
class Q_QUICK_EXPORT QQuickWindow : public QWindow
{
@@ -131,6 +132,8 @@ public:
#endif
QImage grabWindow();
+
+ // ### Qt 6 remove all these 5 functions. Replaced by setRenderTarget(QQuickRenderTarget*).
#if QT_CONFIG(opengl)
void setRenderTarget(QOpenGLFramebufferObject *fbo);
QOpenGLFramebufferObject *renderTarget() const;
@@ -138,8 +141,11 @@ public:
void setRenderTarget(uint fboId, const QSize &size);
uint renderTargetId() const;
QSize renderTargetSize() const;
+
+ void setRenderTarget(const QQuickRenderTarget &target);
+
#if QT_CONFIG(opengl)
- void resetOpenGLState();
+ void resetOpenGLState(); // ### Qt 6 remove
#endif
struct GraphicsStateInfo {
int currentFrameSlot;
@@ -178,13 +184,14 @@ public:
static bool hasDefaultAlphaBuffer();
static void setDefaultAlphaBuffer(bool useAlpha);
- void setPersistentOpenGLContext(bool persistent);
+ void setPersistentOpenGLContext(bool persistent); // ### Qt 6 is this relevant / usable anymore?
bool isPersistentOpenGLContext() const;
- void setPersistentSceneGraph(bool persistent);
+ void setPersistentSceneGraph(bool persistent); // ### Qt 6 is this relevant / usable anymore?
bool isPersistentSceneGraph() const;
- QOpenGLContext *openglContext() const;
+ QOpenGLContext *openglContext() const; // ### Qt 6 consider if this is kept or not
+
bool isSceneGraphInitialized() const;
void scheduleRenderJob(QRunnable *job, RenderStage schedule);
@@ -197,6 +204,8 @@ public:
static void setSceneGraphBackend(const QString &backend);
static QString sceneGraphBackend();
+ void setGraphicsDevice(const QQuickGraphicsDevice &device);
+
QSGRectangleNode *createRectangleNode() const;
QSGImageNode *createImageNode() const;
QSGNinePatchNode *createNinePatchNode() const;
@@ -206,7 +215,7 @@ public:
Q_SIGNALS:
void frameSwapped();
- Q_REVISION(2, 2) void openglContextCreated(QOpenGLContext *context);
+ Q_REVISION(2, 2) void openglContextCreated(QOpenGLContext *context); // ### Qt 6 remove
void sceneGraphInitialized();
void sceneGraphInvalidated();
void beforeSynchronizing();
diff --git a/src/quick/items/qquickwindow_p.h b/src/quick/items/qquickwindow_p.h
index a77ce30a89..ba8691cba3 100644
--- a/src/quick/items/qquickwindow_p.h
+++ b/src/quick/items/qquickwindow_p.h
@@ -57,6 +57,8 @@
#include <QtQuick/private/qsgcontext_p.h>
#include <QtQuick/private/qquickpaletteproviderprivatebase_p.h>
+#include <QtQuick/private/qquickrendertarget_p.h>
+#include <QtQuick/private/qquickgraphicsdevice_p.h>
#include <QtCore/qthread.h>
#include <QtCore/qmutex.h>
@@ -84,6 +86,7 @@ class QRhi;
class QRhiSwapChain;
class QRhiRenderBuffer;
class QRhiRenderPassDescriptor;
+class QRhiTexture;
//Make it easy to identify and customize the root item if needed
class Q_QUICK_PRIVATE_EXPORT QQuickRootItem : public QQuickItem
@@ -104,6 +107,17 @@ public:
virtual bool swap() = 0;
};
+class QQuickWindowRenderTarget
+{
+public:
+ void reset(QRhi *rhi);
+ QRhiRenderTarget *renderTarget = nullptr;
+ QRhiRenderPassDescriptor *rpDesc = nullptr;
+ QRhiTexture *texture = nullptr;
+ QRhiRenderBuffer *depthStencil = nullptr;
+ bool owns = false;
+};
+
class Q_QUICK_PRIVATE_EXPORT QQuickWindowPrivate
: public QWindowPrivate
, public QQuickPaletteProviderPrivateBase<QQuickWindow, QQuickWindowPrivate>
@@ -218,6 +232,9 @@ public:
void dirtyItem(QQuickItem *);
void cleanup(QSGNode *);
+ void ensureCustomRenderTarget();
+ void setCustomCommandBuffer(QRhiCommandBuffer *cb);
+
void polishItems();
void forcePolish();
void syncSceneGraph();
@@ -277,11 +294,26 @@ public:
Qt::FocusReason lastFocusReason;
- QOpenGLFramebufferObject *renderTarget;
- uint renderTargetId;
- QSize renderTargetSize;
+ // Storage for setRenderTarget(QQuickRenderTarget).
+ // Gets baked into redirect.renderTarget by ensureCustomRenderTarget() when rendering the next frame.
+ QQuickRenderTarget customRenderTarget;
+
+ struct Redirect {
+ QRhiCommandBuffer *commandBuffer = nullptr;
+ QQuickWindowRenderTarget rt;
+ bool renderTargetDirty = false;
+ } redirect;
+
+ QQuickGraphicsDevice customDeviceObjects;
+
+ // ### Qt 6 remove
+ struct {
+ QOpenGLFramebufferObject *renderTarget = nullptr;
+ uint renderTargetId = 0;
+ QSize renderTargetSize;
+ } customRenderTargetGl;
- QOpenGLVertexArrayObjectHelper *vaoHelper;
+ QOpenGLVertexArrayObjectHelper *vaoHelper; // ### Qt 6 remove
mutable QQuickWindowIncubationController *incubationController;