Source code

Revision control

Copy as Markdown

// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include "testupdatespatialnode.h"
#include <ssg/qssgrenderextensions.h>
#include <ssg/qssgrenderhelpers.h>
#include <QThread>
#include <QTest>
#include <QtQuick3D/private/qquick3dobject_p.h>
#include <QtQuick3DRuntimeRender/private/qssgrendernode_p.h>
template <typename T>
static void tst_updateSpatialNode(QQuick3DObject *owner,
TestData &testData,
QSSGRenderGraphObject *&node)
{
QVERIFY(owner != nullptr);
// If updateSpatialNode is called there shall be a sceneManager set
const auto sceneManager = QQuick3DObjectPrivate::get(owner)->sceneManager;
Q_ASSERT(sceneManager);
const auto &nodeMap = sceneManager->m_nodeMap;
if (testData.callCount == 0) {
// 1. The first time we'll create a new node
// There should be no links to this object in the node map
const auto values = nodeMap.values();
QVERIFY(!values.contains(owner));
QVERIFY(node == nullptr);
node = new T;
} else if (testData.callCount == 1) {
// 2. The second time we'll delete it and return nullptr.
// This should cause any link to this object to be removed from the node map (On next sync).
QVERIFY(node != nullptr);
node = nullptr;
} else if (testData.callCount == 2) {
// 3. The third time we verify that the received node is nullptr (It was indeed uppdate)
// and then we'll create a new node.
QVERIFY(node == nullptr);
// There should be no links to this object in the node map
const auto values = nodeMap.values();
QVERIFY(!values.contains(owner));
node = new T;
testData.finalNode = node;
} else if (testData.callCount == 3) {
// The forth time we verify that the received node is the same as the new one.
QCOMPARE(node, testData.finalNode);
} else {
Q_UNREACHABLE();
}
testData.callCount++;
// as long as the count is less then the expected could we trigger an update
const bool done = testData.callCount >= testData.expectedCallCount;
if (!done)
QMetaObject::invokeMethod(owner, "update", Qt::QueuedConnection);
}
/// RESOURCE OBJECT
///
///
TestData testData_ResourceObject { 3 };
class MyCustomGraphObject : public QSSGRenderGraphObject
{
public:
MyCustomGraphObject() : QSSGRenderGraphObject(Type(BaseType::Resource)) {}
~MyCustomGraphObject() override
{
testData_ResourceObject.destroyedCount++;
}
};
MyCustomResource::MyCustomResource(QQuick3DObject *parent)
: QQuick3DObject(parent)
{
}
QSSGRenderGraphObject *MyCustomResource::updateSpatialNode(QSSGRenderGraphObject *node)
{
tst_updateSpatialNode<MyCustomGraphObject>(this, testData_ResourceObject, node);
return node;
}
/// NODE OBJECT
///
///
TestData testData_NodeObject { 3 };
class MyCustomRenderNode : public QSSGRenderNode
{
public:
MyCustomRenderNode() : QSSGRenderNode() {}
~MyCustomRenderNode() override
{
testData_NodeObject.destroyedCount++;
}
};
MyCustomNode::MyCustomNode(QQuick3DNode *parent)
: QQuick3DNode(parent)
{
}
QSSGRenderGraphObject *MyCustomNode::updateSpatialNode(QSSGRenderGraphObject *node)
{
tst_updateSpatialNode<MyCustomRenderNode>(this, testData_NodeObject, node);
return node;
}
/// EXTENSION OBJECT
///
///
TestData testData_ExtensionObject { 3 };
class MyCustomExtensionImpl : public QSSGRenderExtension
{
public:
MyCustomExtensionImpl() {}
~MyCustomExtensionImpl() override
{
testData_ExtensionObject.destroyedCount++;
}
bool prepareData(QSSGFrameData &data) override { Q_UNUSED(data); return true; }
void prepareRender(QSSGFrameData &data) override { Q_UNUSED(data); }
void render(QSSGFrameData &data) override { Q_UNUSED(data); }
void resetForFrame() override {}
RenderMode mode() const override { return RenderMode::Standalone; }
RenderStage stage() const override { return RenderStage::PreColor; }
};
MyCustomExtension::MyCustomExtension(QQuick3DObject *parent)
: QQuick3DRenderExtension(parent)
{
}
QSSGRenderGraphObject *MyCustomExtension::updateSpatialNode(QSSGRenderGraphObject *node)
{
tst_updateSpatialNode<MyCustomExtensionImpl>(this, testData_ExtensionObject, node);
return node;
}