Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qquick3ditem2d.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include <QtQuick3D/qquick3dobject.h>
5#include <QtQuick3D/private/qquick3ditem2d_p.h>
6
7#include <QtQuick/private/qquickitem_p.h>
8#include <QtQuick/private/qsgrenderer_p.h>
9#include <QtQuick/private/qquickwindow_p.h>
10
11#include <QtQuick3DRuntimeRender/private/qssgrenderitem2d_p.h>
12#include "qquick3dnode_p_p.h"
13
15
16/*
17internal
18*/
19
22{
23 m_contentItem = new QQuickItem();
24 m_contentItem->setObjectName(QLatin1String("parent of ") + item->objectName()); // for debugging
25 // No size is set for m_contentItem. This is intentional, otherwise item2d anchoring breaks.
28
31}
32
34{
35 delete m_contentItem;
36
37 // This is sketchy. Similarly to the problems QQuick3DTexture has with its
38 // QSGTexture, the same problems arise here with the QSGRenderer. The
39 // associated scenegraph resource must be destroyed on the render thread,
40 // if there is one. If the scenegraph gets invalidated, that's easy due to
41 // signals/slots, but there's no such signal if an object with Item2Ds in
42 // it gets dynamically destroyed.
43 // Here on the gui thread in this dtor there's no way to properly manage
44 // the QSG resource's releasing anymore. Rather, as QSGRenderer is a
45 // QObject, do a deleteLater(), which typically works, but is not a 100%
46 // guarantee that the object will get destroyed on the render thread
47 // eventually, since in theory it could happen that the render thread is
48 // not even running at this point anymore (if the window is closing / the
49 // app is shutting down) - although in practice that won't be an issue
50 // since that case is taken care of the sceneGraphInvalidated signal.
51 // So while unlikely, a leak may still occur under certain circumstances.
52 if (m_renderer)
53 m_renderer->deleteLater();
54}
55
57{
58 item->setParent(m_contentItem);
59 item->setParentItem(m_contentItem);
61 connect(item, &QQuickItem::enabledChanged, this, &QQuick3DItem2D::updatePicking);
62 connect(item, &QQuickItem::visibleChanged, this, &QQuick3DItem2D::updatePicking);
63 m_sourceItems.append(item);
64 update();
65}
67{
68 m_sourceItems.removeOne(item);
69 if (item)
71 if (m_sourceItems.isEmpty())
73 else
74 update();
75}
76
78{
79 return m_contentItem;
80}
81
83{
85}
86
87void QQuick3DItem2D::invalidated()
88{
89 // clean up the renderer
90 if (m_renderer) {
91 delete m_renderer;
92 m_renderer = nullptr;
93 }
94}
95
96void QQuick3DItem2D::updatePicking()
97{
98 m_pickingDirty = true;
99 update();
100}
101
103{
104 auto *sourceItemPrivate = QQuickItemPrivate::get(m_contentItem);
105 QQuickWindow *window = m_contentItem->window();
106
107 if (!window) {
109 window = manager->window();
110 }
111
112 if (!node) {
113 markAllDirty();
114 node = new QSSGRenderItem2D();
115 }
116
118
119 auto itemNode = static_cast<QSSGRenderItem2D *>(node);
121
122 m_rootNode = sourceItemPrivate->rootNode();
123 if (!m_rootNode) {
124 return nullptr;
125 }
126
127 if (!m_renderer) {
129 connect(window, &QQuickWindow::sceneGraphInvalidated, this, &QQuick3DItem2D::invalidated, Qt::DirectConnection);
131
132 // item2D rendernode has its own render pass descriptor and it should
133 // be removed before deleting rhi context.
134 // Otherwise, rhi will complain about the unreleased resource.
135 connect(
136 m_renderer,
138 this,
139 [this]() {
140 auto itemNode = static_cast<QSSGRenderItem2D *>(QQuick3DObjectPrivate::get(this)->spatialNode);
141 if (itemNode) {
142 if (itemNode->m_rp) {
143 itemNode->m_rp->deleteLater();
144 itemNode->m_rp = nullptr;
145 }
146 }
147 },
149 }
150
151 {
152 // Block the sceneGraphChanged() signal. Calling nodeChanged() will emit the sceneGraphChanged()
153 // signal, which is connected to the update() slot to mark the object dirty, which could cause
154 // and constant update even if the 2D content doesn't change.
155 QSignalBlocker blocker(m_renderer);
156 m_renderer->setRootNode(m_rootNode);
157 m_rootNode->markDirty(QSGNode::DirtyForceUpdate); // Force matrix, clip and opacity update.
158 m_renderer->nodeChanged(m_rootNode, QSGNode::DirtyForceUpdate); // Force render list update.
159 }
160
161 if (m_pickingDirty) {
162 m_pickingDirty = false;
163 bool isPickable = false;
164 for (auto item : m_sourceItems) {
165 // Enable picking for Item2D if any of its child is visible and enabled.
166 if (item->isVisible() && item->isEnabled()) {
167 isPickable = true;
168 break;
169 }
170 }
171 itemNode->setState(QSSGRenderNode::LocalState::Pickable, isPickable);
172 }
173
174 itemNode->m_renderer = m_renderer;
175
176 return node;
177}
178
180{
182}
183
185{
187 auto *sourcePrivate = QQuickItemPrivate::get(m_contentItem);
188 auto *window = manager->window();
189 if (m_window != window) {
190 update(); // Just schedule an upate immediately.
191 if (m_window) {
192 disconnect(m_window, SIGNAL(destroyed(QObject*)), this, SLOT(derefWindow(QObject*)));
193 sourcePrivate->derefWindow();
194 }
195 m_window = window;
196 sourcePrivate->refWindow(window);
197 connect(window, SIGNAL(destroyed(QObject*)), this, SLOT(derefWindow(QObject*)));
198 sourcePrivate->refFromEffectItem(true);
199 }
200}
201
203{
204 auto *itemPriv = QQuickItemPrivate::get(item);
205
206 if (win == itemPriv->window) {
207 itemPriv->window = nullptr;
208 itemPriv->windowRefCount = 0;
209
210 itemPriv->prevDirtyItem = nullptr;
211 itemPriv->nextDirtyItem = nullptr;
212 }
213
214 for (auto *child: itemPriv->childItems)
216}
217
218void QQuick3DItem2D::derefWindow(QObject *win)
219{
220 detachWindow(m_contentItem, win);
221}
222
bool isEnabled() const
Returns true if the item is enabled; otherwise, false is returned.
void setParentItem(QGraphicsItem *parent)
Sets this item's parent item to newParent.
bool isVisible() const
Returns true if the item is visible; otherwise, false is returned.
static void setObjectOwnership(QObject *, ObjectOwnership)
Sets the ownership of object.
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:153
\inmodule QtCore
Definition qobject.h:90
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
Q_WEAK_OVERLOAD void setObjectName(const QString &name)
Sets the object's name to name.
Definition qobject.h:114
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
void deleteLater()
\threadsafe
Definition qobject.cpp:2352
QQuickItem * contentItem() const
void itemDestroyed(QQuickItem *item) override
void markAllDirty() override
void removeChildItem(QQuickItem *item)
void allChildrenRemoved()
void addChildItem(QQuickItem *item)
~QQuick3DItem2D() override
QQuick3DItem2D(QQuickItem *item, QQuick3DNode *parent=nullptr)
void preSync() override
QSSGRenderGraphObject * updateSpatialNode(QSSGRenderGraphObject *node) override
void markAllDirty() override
QSSGRenderGraphObject * updateSpatialNode(QSSGRenderGraphObject *node) override
QPointer< QQuick3DSceneManager > sceneManager
static QQuick3DObjectPrivate * get(QQuick3DObject *item)
QSSGRenderGraphObject * spatialNode
void removeItemChangeListener(QQuickItemChangeListener *, ChangeTypes types)
void addItemChangeListener(QQuickItemChangeListener *listener, ChangeTypes types)
QQuickDeliveryAgent * ensureSubsceneDeliveryAgent()
static QQuickItemPrivate * get(QQuickItem *item)
The QQuickItem class provides the most basic of all visual items in \l {Qt Quick}.
Definition qquickitem.h:64
void visibleChanged()
QQuickWindow * window() const
Returns the window in which this item is rendered.
void childrenChanged()
void enabledChanged()
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
void sceneGraphInvalidated()
\qmlsignal QtQuick::Window::sceneGraphInitialized()
void deleteLater()
When called without a frame being recorded, this function is equivalent to deleting the object.
Definition qrhi.cpp:3419
void sceneGraphChanged()
This signal is emitted on the first modification of a node in the tree after the last scene render.
void setRootNode(QSGRootNode *node)
Sets the node as the root of the QSGNode scene that you want to render.
@ DirtyForceUpdate
Definition qsgnode.h:78
void markDirty(DirtyState bits)
Notifies all connected renderers that the node has dirty bits.
Definition qsgnode.cpp:622
virtual QSGRenderer * createRenderer(QSGRendererInterface::RenderMode renderMode=QSGRendererInterface::RenderMode2D)=0
void nodeChanged(QSGNode *node, QSGNode::DirtyState state) override
Updates internal data structures and emits the sceneGraphChanged() signal.
Exception-safe wrapper around QObject::blockSignals().
Definition qobject.h:443
QWidget * window() const
Returns the window for this widget, i.e.
Definition qwidget.cpp:4320
Combined button and popup list for selecting options.
@ DirectConnection
static void * context
#define SLOT(a)
Definition qobjectdefs.h:51
#define SIGNAL(a)
Definition qobjectdefs.h:52
static void detachWindow(QQuickItem *item, QObject *win)
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define emit
QWidget * win
Definition settings.cpp:6
myObject disconnect()
[26]
QGraphicsItem * item
QLayoutItem * child
[0]
aWidget window() -> setWindowTitle("New Window Title")
[2]
QNetworkAccessManager manager
QRhiRenderPassDescriptor * m_rp
Definition moc.h:24
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent