1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2020 Klaralvdalens Datakonsult AB (KDAB). |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt3D module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | #include <QtTest/QtTest> |
30 | #include <QMutex> |
31 | #include <QWaitCondition> |
32 | #include <QThread> |
33 | #include <Qt3DRender/qrenderaspect.h> |
34 | #include <Qt3DRender/private/offscreensurfacehelper_p.h> |
35 | #include <Qt3DRender/private/rendersettings_p.h> |
36 | #include <Qt3DRender/private/viewportnode_p.h> |
37 | #include <Qt3DRender/private/job_common_p.h> |
38 | #include <Qt3DRender/private/entity_p.h> |
39 | |
40 | #include "testaspect.h" |
41 | #include "testrenderer.h" |
42 | |
43 | class TestRendererAspect : public Qt3DRender::TestAspect { |
44 | public: |
45 | TestRendererAspect(Qt3DCore::QEntity *root) : Qt3DRender::TestAspect(root) { |
46 | auto d = Qt3DCore::QAbstractAspectPrivate::get(aspect: this); |
47 | d->m_rootId = root->id(); |
48 | } |
49 | |
50 | void replaceWithTestRenderer() { |
51 | auto daspect = Qt3DRender::QRenderAspectPrivate::get(q: this); |
52 | |
53 | auto sceneRoot = daspect->m_renderer->sceneRoot(); |
54 | daspect->m_renderer->shutdown(); |
55 | delete daspect->m_renderer; |
56 | daspect->m_renderer = new TestRenderer(); |
57 | daspect->m_renderer->setNodeManagers(daspect->m_nodeManagers); |
58 | daspect->m_renderer->setOffscreenSurfaceHelper(daspect->m_offscreenHelper); |
59 | sceneRoot->setRenderer(daspect->m_renderer); |
60 | daspect->m_renderer->setSceneRoot(sceneRoot); |
61 | |
62 | // Give it a setting instance |
63 | Qt3DRender::Render::RenderSettings settings; |
64 | // owned by FG manager |
65 | Qt3DRender::Render::ViewportNode *fgRoot = new Qt3DRender::Render::ViewportNode(); |
66 | const Qt3DCore::QNodeId fgRootId = Qt3DCore::QNodeId::createId(); |
67 | |
68 | daspect->m_nodeManagers->frameGraphManager()->appendNode(id: fgRootId, node: fgRoot); |
69 | settings.setActiveFrameGraphId(fgRootId); |
70 | |
71 | daspect->m_renderer->setSettings(&settings); |
72 | } |
73 | }; |
74 | |
75 | class tst_Aspect : public QObject |
76 | { |
77 | Q_OBJECT |
78 | public : |
79 | tst_Aspect() = default; |
80 | ~tst_Aspect() = default; |
81 | |
82 | private Q_SLOTS: |
83 | |
84 | void checkJobs() |
85 | { |
86 | // GIVEN |
87 | Qt3DCore::QEntity *rootEntity = new Qt3DCore::QEntity(); |
88 | QScopedPointer<TestRendererAspect> aspect(new TestRendererAspect(rootEntity)); |
89 | auto daspect = Qt3DRender::QRenderAspectPrivate::get(q: aspect.data()); |
90 | daspect->m_renderAfterJobs = true; |
91 | aspect->onEngineStartup(); |
92 | |
93 | // replace with empty renderer |
94 | aspect->replaceWithTestRenderer(); |
95 | |
96 | // WHEN |
97 | daspect->m_renderer->markDirty(changes: Qt3DRender::Render::AbstractRenderer::AllDirty, node: nullptr); |
98 | |
99 | auto jobs = daspect->jobsToExecute(time: 1.); |
100 | // qDebug() << jobs.size(); |
101 | // for (auto job: jobs) |
102 | // qDebug() << Qt3DCore::QAspectJobPrivate::get(job.data())->m_jobName; |
103 | |
104 | // THEN -> AllDirty |
105 | QCOMPARE(jobs.size(), |
106 | 1 + // UpdateTreeEnabled |
107 | 1 + // UpdateTransform |
108 | 1 + // UpdateWorldBoundingVolume |
109 | 1 + // CalcBoundingVolume |
110 | 1 + // ExpandBoundingVolume |
111 | 1 + // SyncLoadingJobs |
112 | 1 + // UpdateSkinningPalette |
113 | 1 + // UpdateLevelOfDetail |
114 | 1 + // UpdateLayerEntity |
115 | 1 + // PickBoundingVolume |
116 | 1 + // RayCasting |
117 | 0 // No skeleton, no scene loading, no geometry, no buffers |
118 | ); |
119 | |
120 | // WHEN |
121 | daspect->m_renderer->clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty); |
122 | jobs = daspect->jobsToExecute(time: 1.); |
123 | |
124 | // THEN -> Nothing dirty |
125 | QCOMPARE(jobs.size(), |
126 | 1 + // SyncLoadingJobs |
127 | 1 + // UpdateSkinningPalette |
128 | 1 + // UpdateLevelOfDetail |
129 | 1 + // PickBoundingVolume |
130 | 1 + // RayCasting |
131 | 0 // No skeleton, no scene loading, no geometry, no buffers |
132 | ); |
133 | |
134 | // WHEN |
135 | daspect->m_renderer->clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty); |
136 | daspect->m_renderer->markDirty(changes: Qt3DRender::Render::AbstractRenderer::EntityEnabledDirty, node: nullptr); |
137 | jobs = daspect->jobsToExecute(time: 1.); |
138 | |
139 | // THEN -> enabled dirty |
140 | QCOMPARE(jobs.size(), |
141 | 1 + // UpdateTreeEnabled |
142 | 1 + // UpdateTransform |
143 | 1 + // UpdateWorldBoundingVolume |
144 | 1 + // CalcBoundingVolume |
145 | 1 + // ExpandBoundingVolume |
146 | 1 + // SyncLoadingJobs |
147 | 1 + // UpdateSkinningPalette |
148 | 1 + // UpdateLevelOfDetail |
149 | 1 + // PickBoundingVolume |
150 | 1 + // RayCasting |
151 | 0 // No skeleton, no scene loading, no geometry, no buffers |
152 | ); |
153 | |
154 | // WHEN |
155 | daspect->m_renderer->clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty); |
156 | daspect->m_renderer->markDirty(changes: Qt3DRender::Render::AbstractRenderer::TransformDirty, node: nullptr); |
157 | jobs = daspect->jobsToExecute(time: 1.); |
158 | |
159 | // THEN -> transform dirty |
160 | QCOMPARE(jobs.size(), |
161 | 1 + // UpdateTransform |
162 | 1 + // UpdateWorldBoundingVolume |
163 | 1 + // ExpandBoundingVolume |
164 | 1 + // SyncLoadingJobs |
165 | 1 + // UpdateSkinningPalette |
166 | 1 + // UpdateLevelOfDetail |
167 | 1 + // PickBoundingVolume |
168 | 1 + // RayCasting |
169 | 0 // No skeleton, no scene loading, no geometry, no buffers |
170 | ); |
171 | |
172 | // WHEN |
173 | daspect->m_renderer->clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty); |
174 | daspect->m_renderer->markDirty(changes: Qt3DRender::Render::AbstractRenderer::GeometryDirty, node: nullptr); |
175 | jobs = daspect->jobsToExecute(time: 1.); |
176 | |
177 | // THEN -> geometry dirty |
178 | QCOMPARE(jobs.size(), |
179 | 1 + // CalcBoundingVolume |
180 | 1 + // ExpandBoundingVolume |
181 | 1 + // SyncLoadingJobs |
182 | 1 + // UpdateSkinningPalette |
183 | 1 + // UpdateLevelOfDetail |
184 | 1 + // PickBoundingVolume |
185 | 1 + // RayCasting |
186 | 0 // No skeleton, no scene loading, no geometry, no buffers |
187 | ); |
188 | } |
189 | }; |
190 | |
191 | QTEST_MAIN(tst_Aspect) |
192 | |
193 | #include "tst_aspect.moc" |
194 | |