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
qquick3dscenemanager.cpp
Go to the documentation of this file.
1// Copyright (C) 2019 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
5#include "qquick3dobject_p.h"
7#include "qquick3dmodel_p.h"
8
9#include <QtQuick/QQuickWindow>
10
11#include <QtQuick3DRuntimeRender/private/qssgrenderlayer_p.h>
12#include <ssg/qssgrendercontextcore.h>
13#include <QtQuick3DRuntimeRender/private/qssgrendermodel_p.h>
14#include <QtQuick3DRuntimeRender/private/qssgrenderer_p.h>
15#include <QtQuick3DRuntimeRender/private/qssgrenderimage_p.h>
16
17#include <QtQuick3DUtils/private/qssgassert_p.h>
18
20
22
23static constexpr char qtQQ3DWAPropName[] { "_qtquick3dWindowAttachment" };
24
29
30// Should be deleted by QQuick3DWindowAttachment to ensure it's done
31// on the render thread.
38
40{
41 if (window == m_window)
42 return;
43
44 if (window != m_window) {
45 if (wattached) {
46 // Unregister from old windows attached object
48 wattached = nullptr;
49 }
51 if (m_window) {
53 if (wattached)
55 }
56
58 }
59}
60
65
71
76
78{
80
81 if (auto front = m_nodeMap[item]) {
82 auto *po = QQuick3DObjectPrivate::get(front);
83 sharedResourceRemoved |= po->sharedResource;
84 po->spatialNode = nullptr;
85
86 // The front-end object is no longer reachable (destroyed) so make sure we don't return it
87 // when doing a node look-up.
88 m_nodeMap[item] = nullptr;
89 }
90}
91
96
101
103{
104
105}
106
108{
109 const QList<QQuick3DObject *> dirtyList = dirtyBoundingBoxList;
110 for (auto object : dirtyList) {
112 if (itemPriv->sceneManager == nullptr)
113 continue;
114 auto model = static_cast<QSSGRenderModel *>(itemPriv->spatialNode);
115 if (model) {
116 QSSGBounds3 bounds = mgr.getModelBounds(model);
117 static_cast<QQuick3DModel *>(object)->setBounds(bounds.minimum, bounds.maximum);
118 }
120 }
121}
122
124{
125 auto it = std::begin(dirtyResources);
126 const auto end = std::end(dirtyResources);
127 bool ret = false;
128 for (; it != end; ++it)
129 ret |= updateResources(it);
130
131 return ret;
132}
133
135{
136 auto it = std::begin(dirtyNodes);
137 const auto end = std::end(dirtyNodes);
138 for (; it != end; ++it)
139 updateNodes(it);
140}
141
143{
144 auto it = std::begin(dirtyExtensions);
145 const auto end = std::end(dirtyExtensions);
146 for (; it != end; ++it)
147 updateExtensions(it);
148}
149
151{
152 const auto updateDirtyResourceNode = [this](QQuick3DObject *resource) {
154 po->dirtyAttributes = 0; // Not used, but we should still reset it.
155 QSSGRenderGraphObject *node = po->spatialNode;
156 po->spatialNode = resource->updateSpatialNode(node);
157 if (po->spatialNode)
158 m_nodeMap.insert(po->spatialNode, resource);
159 return po->sharedResource;
160 };
161
162 bool ret = false;
165 for (; it != end; ++it)
166 ret |= updateDirtyResourceNode(*it);
167
168 // Expectation is that we won't get here often, for other updates the
169 // backend nodes should have been realized and we won't get here, so
170 // just release space used by the set.
172
173 return ret;
174}
175
177{
178 QQuick3DObjectPrivate *itemPriv = QQuick3DObjectPrivate::get(resourceObject);
179 quint32 dirty = itemPriv->dirtyAttributes;
180 Q_UNUSED(dirty);
181 itemPriv->dirtyAttributes = 0;
182 QSSGRenderGraphObject *oldNode = itemPriv->spatialNode;
183 itemPriv->spatialNode = resourceObject->updateSpatialNode(itemPriv->spatialNode);
184 if (itemPriv->spatialNode) {
185 m_nodeMap.insert(itemPriv->spatialNode, resourceObject);
186 if (itemPriv->spatialNode->type == QSSGRenderGraphObject::Type::ResourceLoader) {
187 resourceLoaders.insert(itemPriv->spatialNode);
188 } else if (itemPriv->spatialNode->type == QQuick3DObjectPrivate::Type::Image2D && itemPriv->spatialNode != oldNode) {
190 }
191 }
192
193 if (QSSGRenderGraphObject::isTexture(itemPriv->type) && qobject_cast<QQuick3DTexture *>(resourceObject)->extensionDirty())
194 dirtySecondPassResources.insert(resourceObject);
195
196 // resource nodes dont go in the tree, so we dont need to parent them
197}
198
200{
201 QQuick3DObjectPrivate *itemPriv = QQuick3DObjectPrivate::get(spatialNode);
202 quint32 dirty = itemPriv->dirtyAttributes;
203 itemPriv->dirtyAttributes = 0;
204 QSSGRenderGraphObject *oldNode = itemPriv->spatialNode;
205 itemPriv->spatialNode = spatialNode->updateSpatialNode(oldNode);
206 // NOTE: We always update the node map, as we can end-up with the a node map where the mapping
207 // has been 'disconnected', e.g., the front-end object removed from the scene only to be later
208 // re-used.
209 if (itemPriv->spatialNode) {
210 m_nodeMap.insert(itemPriv->spatialNode, spatialNode);
211 if (itemPriv->type == QQuick3DObjectPrivate::Type::Item2D && itemPriv->spatialNode != oldNode)
213 }
214
215 QSSGRenderNode *graphNode = static_cast<QSSGRenderNode *>(itemPriv->spatialNode);
216
217 if (graphNode && graphNode->parent && dirty & QQuick3DObjectPrivate::ParentChanged) {
218 QQuick3DNode *nodeParent = qobject_cast<QQuick3DNode *>(spatialNode->parentItem());
219 if (nodeParent) {
220 QSSGRenderNode *parentGraphNode = static_cast<QSSGRenderNode *>(
221 QQuick3DObjectPrivate::get(nodeParent)->spatialNode);
222 if (parentGraphNode) {
223 graphNode->parent->removeChild(*graphNode);
224 parentGraphNode->addChild(*graphNode);
225 }
226 }
227 }
228
229 if (graphNode && graphNode->parent == nullptr) {
230 QQuick3DNode *nodeParent = qobject_cast<QQuick3DNode *>(spatialNode->parentItem());
231 if (nodeParent) {
232 QSSGRenderNode *parentGraphNode = static_cast<QSSGRenderNode *>(QQuick3DObjectPrivate::get(nodeParent)->spatialNode);
233 if (!parentGraphNode) {
234 // The parent spatial node hasn't been created yet
235 auto parentNode = QQuick3DObjectPrivate::get(nodeParent);
236 parentNode->spatialNode = nodeParent->updateSpatialNode(parentNode->spatialNode);
237 if (parentNode->spatialNode)
238 m_nodeMap.insert(parentNode->spatialNode, nodeParent);
239 parentGraphNode = static_cast<QSSGRenderNode *>(parentNode->spatialNode);
240 }
241 if (parentGraphNode)
242 parentGraphNode->addChild(*graphNode);
243 } else {
244 QQuick3DViewport *viewParent = qobject_cast<QQuick3DViewport *>(spatialNode->parent());
245 if (viewParent) {
246 auto sceneRoot = QQuick3DObjectPrivate::get(viewParent->scene());
247 if (!sceneRoot->spatialNode) // must have a scene root spatial node first
248 sceneRoot->spatialNode = viewParent->scene()->updateSpatialNode(sceneRoot->spatialNode);
249 if (sceneRoot->spatialNode) {
250 m_nodeMap.insert(sceneRoot->spatialNode, viewParent->scene());
251 static_cast<QSSGRenderNode *>(sceneRoot->spatialNode)->addChild(*graphNode);
252 }
253 }
254 }
255 }
256}
257
259{
260 return m_nodeMap[const_cast<QSSGRenderGraphObject *>(node)];
261}
262
264{
265
266 QQuick3DWindowAttachment *wa = nullptr;
267 if (auto aProperty = window.property(qtQQ3DWAPropName); aProperty.isValid())
268 wa = aProperty.value<QQuick3DWindowAttachment *>();
269
270 if (!wa) {
271 // WindowAttachment will not be created under 'window'.
272 // It should be deleted after all the cleanups related with 'window',
273 // otherwise some resourses deleted after it, will not be cleaned correctly.
276 }
277
278 return wa;
279}
280
282{
284 sharedResourceRemoved = false;
285 for (auto node : std::as_const(cleanupNodeList)) {
286 // Remove "spatial" nodes from scenegraph
287 if (QSSGRenderGraphObject::isNodeType(node->type)) {
288 QSSGRenderNode *spatialNode = static_cast<QSSGRenderNode *>(node);
289 spatialNode->removeFromGraph();
290 }
291
292 if (node->type == QQuick3DObjectPrivate::Type::Item2D) {
294 } else if (node->type == QQuick3DObjectPrivate::Type::Image2D) {
295 auto image = static_cast<QSSGRenderImage *>(node);
296 if (image && image->m_qsgTexture != nullptr ) {
298 }
299 }
300
301 // Remove all nodes from the node map because they will no
302 // longer be usable from this point from the frontend
303 m_nodeMap.remove(node);
304
305 // Some nodes will trigger resource cleanups that need to
306 // happen at a specified time (when graphics backend is active)
307 // So build another queue for graphics assets marked for removal
308 if (node->hasGraphicsResources()) {
310 if (node->type == QSSGRenderGraphObject::Type::ResourceLoader)
312 } else {
313 delete node;
314 }
315 }
316
317 // Nodes are now "cleaned up" so clear the cleanup list
319
320 return ret;
321}
322
323bool QQuick3DSceneManager::updateResources(QQuick3DObject **listHead)
324{
325 // Detach the current list head first, and consume all reachable entries.
326 // New entries may be added to the new list while traversing, which will be
327 // visited on the next updateDirtyNodes() call.
328 bool ret = false;
329 QQuick3DObject *updateList = *listHead;
330 *listHead = nullptr;
331 if (updateList)
332 QQuick3DObjectPrivate::get(updateList)->prevDirtyItem = &updateList;
333
334 QQuick3DObject *item = updateList;
335 while (item) {
336 // Different processing for resource nodes vs hierarchical nodes etc.
338 // handle hierarchical nodes
341 ret |= po->sharedResource;
342 po->removeFromDirtyList();
343 item = updateList;
344 }
345
346 return ret;
347}
348
349void QQuick3DSceneManager::updateNodes(QQuick3DObject **listHead)
350{
351 // Detach the current list head first, and consume all reachable entries.
352 // New entries may be added to the new list while traversing, which will be
353 // visited on the next updateDirtyNodes() call.
354 QQuick3DObject *updateList = *listHead;
355 *listHead = nullptr;
356 if (updateList)
357 QQuick3DObjectPrivate::get(updateList)->prevDirtyItem = &updateList;
358
359 QQuick3DObject *item = updateList;
360 while (item) {
361 // Different processing for resource nodes vs hierarchical nodes (anything that's _not_ a resource)
363 // handle hierarchical nodes
365 QQuick3DObjectPrivate::get(item)->removeFromDirtyList();
366 item = updateList;
367 }
368}
369
370void QQuick3DSceneManager::updateExtensions(QQuick3DObject **listHead)
371{
372 const auto updateDirtyExtensionNode = [this](QQuick3DObject *extension) {
374 po->dirtyAttributes = 0; // Not used, but we should still reset it.
375 QSSGRenderGraphObject *node = po->spatialNode;
376 po->spatialNode = extension->updateSpatialNode(node);
377 if (po->spatialNode)
378 m_nodeMap.insert(po->spatialNode, extension);
379 };
380
381 // Detach the current list head first, and consume all reachable entries.
382 // New entries may be added to the new list while traversing, which will be
383 // visited on the next updateDirtyNodes() call.
384 QQuick3DObject *updateList = *listHead;
385 *listHead = nullptr;
386 if (updateList)
387 QQuick3DObjectPrivate::get(updateList)->prevDirtyItem = &updateList;
388
389 QQuick3DObject *item = updateList;
390 while (item) {
391 // Different processing for resource nodes vs hierarchical nodes (anything that's _not_ a resource)
393 // handle hierarchical nodes
394 updateDirtyExtensionNode(item);
395 QQuick3DObjectPrivate::get(item)->removeFromDirtyList();
396 item = updateList;
397 }
398}
399
401{
402 for (auto it = std::begin(dirtyResources), end = std::end(dirtyResources); it != end; ++it) {
404 while (next) {
405 next->preSync();
406 next = QQuick3DObjectPrivate::get(next)->nextDirtyItem;
407 }
408 }
409
410 for (auto it = std::begin(dirtyNodes), end = std::end(dirtyNodes); it != end; ++it) {
412 while (next) {
413 next->preSync();
414 next = QQuick3DObjectPrivate::get(next)->nextDirtyItem;
415 }
416 }
417
418 for (auto it = std::begin(dirtyExtensions), end = std::end(dirtyExtensions); it != end; ++it) {
420 while (next) {
421 next->preSync();
422 next = QQuick3DObjectPrivate::get(next)->nextDirtyItem;
423 }
424 }
425}
426
430
432 : m_window(window)
433{
434 if (window) {
435 // Act when the application calls window->releaseResources() and the
436 // render loop emits the corresponding signal in order to forward the
437 // event to us as well. (do not confuse with other release-resources
438 // type of functions, this is about dropping pipeline and other resource
439 // caches than can be automatically recreated if needed on the next frame)
441 QSGRenderContext *rc = wd->context;
442 if (QSSG_GUARD_X(rc, "QQuickWindow has no QSGRenderContext, this should not happen")) {
443 // QSGRenderContext signals are emitted on the render thread, if there is one; use DirectConnection
444 connect(rc, &QSGRenderContext::releaseCachedResourcesRequested, this, &QQuick3DWindowAttachment::onReleaseCachedResources, Qt::DirectConnection);
445 connect(rc, &QSGRenderContext::invalidated, this, &QQuick3DWindowAttachment::onInvalidated, Qt::DirectConnection);
446 }
447
448 // We put this in the back of the queue to allow any clean-up of resources to happen first.
450 // afterAnimating is emitted on the main thread.
451 connect(window, &QQuickWindow::afterAnimating, this, &QQuick3DWindowAttachment::preSync);
452 // afterFrameEnd is emitted on render thread.
454 }
455}
456
458{
459 for (auto manager: sceneManagerCleanupQueue) {
460 sceneManagers.removeOne(manager);
461 delete manager;
462 }
463 // remaining sceneManagers should also be removed
464 qDeleteAll(sceneManagers);
465 QSSG_CHECK(QSSG_DEBUG_COND(resourceCleanupQueue.isEmpty()));
466 QSSG_CHECK(QSSG_DEBUG_COND(pendingResourceCleanupQueue.isEmpty()));
467
468 if (m_window)
470
471 QSSG_CHECK_X(!m_rci || m_rci.use_count() == 1, "RCI has unexpected reference count!");
472}
473
475{
476 for (auto &sceneManager : std::as_const(sceneManagers))
477 sceneManager->preSync();
478}
479
480// Called from the render thread
482{
483 // Pass the scene managers list of resources marked for
484 // removal to the render context for deletion
485 // The render context will take ownership of the nodes
486 // and clear the list
487
488 // In special cases there is no rci because synchronize() is never called.
489 // This can happen when running with the software backend of Qt Quick.
490 // Handle this gracefully.
491 if (!m_rci)
492 return;
493
494 // Check if there's orphaned resources that needs to be
495 // cleaned out first.
496 if (resourceCleanupQueue.size() != 0)
497 m_rci->renderer()->cleanupResources(resourceCleanupQueue);
498}
499
500// Called on the render thread, if there is one
501void QQuick3DWindowAttachment::onReleaseCachedResources()
502{
503 if (m_rci)
504 m_rci->releaseCachedResources();
506}
507
508void QQuick3DWindowAttachment::onInvalidated()
509{
510 // Find all objects that have graphics resources and queue them
511 // for cleanup.
512 // 1. We'll need to manually go through the nodes of each scene manager and mark
513 // objects with graphics resources for deletion.
514 // The scene graph is invalidated so we need to release graphics resources now, on the render thread.
515 for (auto &sceneManager : std::as_const(sceneManagers)) {
516 const auto objects = sceneManager->m_nodeMap.keys();
517 for (QSSGRenderGraphObject *obj : objects) {
518 if (obj->hasGraphicsResources())
519 sceneManager->cleanup(obj);
520 }
521 }
522
523 // Start: follow the normal clean-up procedure
524 for (auto &sceneManager : std::as_const(sceneManagers))
525 sceneManager->cleanupNodes();
526
527 for (const auto &pr : std::as_const(pendingResourceCleanupQueue))
528 resourceCleanupQueue.insert(pr);
529 pendingResourceCleanupQueue.clear();
530
531 // NOTE!: It's essential that we release the cached resources before we
532 // call cleanupResources(), to avoid the expensive bookkeeping code involved
533 // for models. This is achieved by dropping the data to avoid expensive look-ups; it's going away anyways.
534 // (In the future, if/when cleanupDrawCallData() is improved, then this step might not be necessary).
535 onReleaseCachedResources();
536
538 // end
539
540 // If the SG RenderContex is invalidated and we're the only one holding onto the SSG
541 // RenderContextInterface then just release it. If the application is not going down
542 // a new RCI will be created/set during the next sync.
543 if (m_rci.use_count() == 1) {
544 m_rci.reset();
546 }
547}
548
549bool QQuick3DWindowAttachment::synchronize(QSet<QSSGRenderGraphObject *> &resourceLoaders)
550{
551 // Terminate old scene managers
552 for (auto manager: sceneManagerCleanupQueue) {
553 sceneManagers.removeOne(manager);
554 delete manager;
555 }
556 // Terminate old scene managers
557 sceneManagerCleanupQueue = {};
558
559 bool sharedUpdateNeeded = false;
560
561 // Cleanup
562 for (auto &sceneManager : std::as_const(sceneManagers))
563 sharedUpdateNeeded |= sceneManager->cleanupNodes();
564
565 // Resources
566 for (auto &sceneManager : std::as_const(sceneManagers))
567 sharedUpdateNeeded |= sceneManager->updateDirtyResourceNodes();
568 // Spatial Nodes
569 for (auto &sceneManager : std::as_const(sceneManagers))
570 sceneManager->updateDirtySpatialNodes();
571 for (auto &sceneManager : std::as_const(sceneManagers))
572 sceneManager->updateDiryExtensions();
573 for (auto &sceneManager : std::as_const(sceneManagers))
574 sharedUpdateNeeded |= sceneManager->updateDirtyResourceSecondPass();
575 // Bounding Boxes
576 for (auto &sceneManager : std::as_const(sceneManagers))
577 sceneManager->updateBoundingBoxes(*m_rci->bufferManager());
578 // Resource Loaders
579 for (auto &sceneManager : std::as_const(sceneManagers))
580 resourceLoaders.unite(sceneManager->resourceLoaders);
581
582 if (sharedUpdateNeeded) {
583 // We know there are shared resources in the scene, so notify the "world".
584 // Ideally we should be more targeted, but for now this will do the job.
585 for (auto &sceneManager : std::as_const(sceneManagers))
586 sceneManager->requestUpdate();
587 }
588
589 // Prepare pending (adopted) resources for clean-up (will happen as a result of afterFrameEnd()).
590 for (const auto &pr : std::as_const(pendingResourceCleanupQueue))
591 resourceCleanupQueue.insert(pr);
592 pendingResourceCleanupQueue.clear();
593
594 return sharedUpdateNeeded;
595}
596
598{
599 for (const auto &sm : std::as_const(sceneManagers))
600 sm->requestUpdate();
601}
602
604{
605 // NOTE: We'll re-iterate this list either on the next sync or if there's no sceneManagers left.
606 // See: sync and dtor.
607 for (QQuick3DSceneManager *manager : std::as_const(sceneManagerCleanupQueue))
608 sceneManagers.removeOne(manager);
609
610 if (sceneManagers.isEmpty())
611 delete this;
612}
613
615
616void QQuick3DWindowAttachment::setRci(const std::shared_ptr<QSSGRenderContextInterface> &rciptr)
617{
618 QSSG_CHECK_X(m_rci == nullptr || m_rci.use_count() == 1, "Old render context was not released!");
619 m_rci = rciptr;
621}
622
628
633
635{
636 Q_ASSERT(obj->hasGraphicsResources());
637 pendingResourceCleanupQueue.push_back(obj);
638}
639
641{
642 if (!sceneManagerCleanupQueue.contains(manager))
643 sceneManagerCleanupQueue.push_back(manager);
644}
645
bool remove(const Key &key)
Removes the item that has the key from the hash.
Definition qhash.h:958
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1303
bool isEmpty() const noexcept
Definition qlist.h:401
bool removeOne(const AT &t)
Definition qlist.h:598
void push_back(parameter_type t)
Definition qlist.h:675
void clear()
Definition qlist.h:434
\inmodule QtCore
Definition qobject.h:103
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
QVariant property(const char *name) const
Returns the value of the object's name property.
Definition qobject.cpp:4323
bool setProperty(const char *name, const QVariant &value)
Sets the value of the object's name property to value.
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:2435
QSSGRenderGraphObject * updateSpatialNode(QSSGRenderGraphObject *node) override
static QQuick3DObjectPrivate * get(QQuick3DObject *item)
\qmltype Object3D \inqmlmodule QtQuick3D \instantiates QQuick3DObject \inherits QtObject
QQuick3DObject * parent
\qmlproperty Object3D QtQuick3D::Object3D::parent This property holds the parent of the Object3D in a...
void setWindow(QQuickWindow *window)
void updateDirtyResource(QQuick3DObject *resourceObject)
QHash< QSSGRenderGraphObject *, QQuick3DObject * > m_nodeMap
QSet< QSSGRenderGraphObject * > resourceLoaders
QQuick3DSceneManager(QObject *parent=nullptr)
QPointer< QQuick3DWindowAttachment > wattached
QSet< QSSGRenderGraphObject * > cleanupNodeList
QList< QQuick3DObject * > dirtyBoundingBoxList
QQuick3DObject * dirtyNodes[size_t(NodePriority::Count)]
static QQuick3DWindowAttachment * getOrSetWindowAttachment(QQuickWindow &window)
QQuick3DObject * lookUpNode(const QSSGRenderGraphObject *node) const
QQuick3DObject * dirtyExtensions[size_t(ExtensionPriority::Count)]
void dirtyItem(QQuick3DObject *item)
QQuick3DObject * dirtyResources[size_t(ResourcePriority::Count)]
QSet< QQuick3DObject * > dirtySecondPassResources
void updateBoundingBoxes(QSSGBufferManager &mgr)
void updateDirtySpatialNode(QQuick3DNode *spatialNode)
void cleanup(QSSGRenderGraphObject *item)
void unregisterSceneManager(QQuick3DSceneManager &manager)
Q_INVOKABLE bool synchronize(QSet< QSSGRenderGraphObject * > &resourceLoaders)
void registerSceneManager(QQuick3DSceneManager &manager)
QQuickWindow * window() const
void queueForCleanup(QSSGRenderGraphObject *obj)
QQuick3DWindowAttachment(QQuickWindow *window)
QQuick3DWindowAttachment.
void setRci(const std::shared_ptr< QSSGRenderContextInterface > &rciptr)
static QQuickWindowPrivate * get(QQuickWindow *c)
QSGRenderContext * context
\qmltype Window \instantiates QQuickWindow \inqmlmodule QtQuick
void releaseCachedResourcesRequested()
Class representing 3D range or axis aligned bounding box.
QVector3D minimum
QVector3D maximum
static constexpr bool isNodeType(Type type) noexcept
static constexpr bool isExtension(Type type) noexcept
static constexpr bool isTexture(Type type) noexcept
qsizetype size() const
Definition qset.h:50
bool remove(const T &value)
Definition qset.h:63
bool isEmpty() const
Definition qset.h:52
const_iterator constBegin() const noexcept
Definition qset.h:139
const_iterator constEnd() const noexcept
Definition qset.h:143
void clear()
Definition qset.h:61
iterator insert(const T &value)
Definition qset.h:155
\inmodule QtCore
Definition qvariant.h:65
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:536
void extension()
[6]
Definition dialogs.cpp:230
qDeleteAll(list.begin(), list.end())
cache insert(employee->id(), employee)
QSet< QString >::iterator it
short next
Definition keywords.cpp:445
Combined button and popup list for selecting options.
@ DirectConnection
Definition image.cpp:4
return ret
GLuint GLuint end
GLuint object
[3]
GLenum type
GLhandleARB obj
[2]
static QT_BEGIN_NAMESPACE constexpr char qtQQ3DWAPropName[]
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define QSSG_DEBUG_COND(cond)
#define QSSG_GUARD_X(cond, msg)
#define QSSG_CHECK_X(cond, msg)
#define QSSG_CHECK(cond)
#define Q_EMIT
#define emit
#define Q_UNUSED(x)
unsigned int quint32
Definition qtypes.h:50
QSqlQueryModel * model
[16]
QGraphicsItem * item
aWidget window() -> setWindowTitle("New Window Title")
[2]
QNetworkAccessManager manager
bool contains(const AT &t) const noexcept
Definition qlist.h:45
void addChild(QSSGRenderNode &inChild)
QSSGRenderNode * parent
void removeChild(QSSGRenderNode &inChild)