1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 Paul Lemire <paul.lemire350@gmail.com> |
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/QTest> |
30 | #include <Qt3DCore/private/qaspectjobmanager_p.h> |
31 | #include <Qt3DCore/private/qnodevisitor_p.h> |
32 | #include <Qt3DCore/private/qnode_p.h> |
33 | |
34 | #include <renderviewbuilder_p.h> |
35 | #include <Qt3DRender/private/qrenderaspect_p.h> |
36 | #include <Qt3DRender/qviewport.h> |
37 | #include <Qt3DRender/qclearbuffers.h> |
38 | #include <Qt3DRender/qdispatchcompute.h> |
39 | #include <Qt3DRender/qfrustumculling.h> |
40 | #include <Qt3DRender/qmaterial.h> |
41 | #include <Qt3DRender/qspotlight.h> |
42 | #include <Qt3DRender/qpointlight.h> |
43 | #include <Qt3DRender/qenvironmentlight.h> |
44 | #include <Qt3DRender/qgeometryrenderer.h> |
45 | #include <Qt3DRender/qcomputecommand.h> |
46 | #include <Qt3DRender/qlayerfilter.h> |
47 | #include <Qt3DRender/qrenderpassfilter.h> |
48 | #include <Qt3DRender/qtechniquefilter.h> |
49 | #include <Qt3DRender/qcameraselector.h> |
50 | #include <Qt3DRender/qcamera.h> |
51 | #include <Qt3DRender/qlayer.h> |
52 | #include <Qt3DRender/private/qrenderaspect_p.h> |
53 | #include <Qt3DRender/private/nodemanagers_p.h> |
54 | #include <Qt3DRender/private/managers_p.h> |
55 | #include <Qt3DRender/private/filterentitybycomponentjob_p.h> |
56 | #include <Qt3DRender/private/qrenderaspect_p.h> |
57 | |
58 | QT_BEGIN_NAMESPACE |
59 | |
60 | namespace Qt3DRender { |
61 | |
62 | class TestAspect : public QRenderAspect |
63 | { |
64 | public: |
65 | TestAspect(Qt3DCore::QNode *root) |
66 | : QRenderAspect(Qt3DRender::QRenderAspect::Synchronous) |
67 | , m_jobManager(new Qt3DCore::QAspectJobManager()) |
68 | { |
69 | Qt3DCore::QAbstractAspectPrivate::get(aspect: this)->m_jobManager = m_jobManager.data(); |
70 | QRenderAspect::onRegistered(); |
71 | |
72 | QVector<Qt3DCore::QNode *> nodes; |
73 | Qt3DCore::QNodeVisitor v; |
74 | v.traverse(rootNode_: root, fN: [&nodes](Qt3DCore::QNode *node) { |
75 | Qt3DCore::QNodePrivate *d = Qt3DCore::QNodePrivate::get(q: node); |
76 | d->m_typeInfo = const_cast<QMetaObject*>(Qt3DCore::QNodePrivate::findStaticMetaObject(metaObject: node->metaObject())); |
77 | d->m_hasBackendNode = true; |
78 | nodes << node; |
79 | }); |
80 | |
81 | for (const auto node: nodes) |
82 | d_func()->createBackendNode(change: { |
83 | .id: node->id(), |
84 | .metaObj: Qt3DCore::QNodePrivate::get(q: node)->m_typeInfo, |
85 | .type: Qt3DCore::NodeTreeChange::Added, |
86 | .node: node |
87 | }); |
88 | } |
89 | |
90 | ~TestAspect() |
91 | { |
92 | QRenderAspect::onUnregistered(); |
93 | } |
94 | |
95 | Qt3DRender::Render::NodeManagers *nodeManagers() const |
96 | { |
97 | return d_func()->m_renderer->nodeManagers(); |
98 | } |
99 | |
100 | Render::OpenGL::Renderer *renderer() const |
101 | { |
102 | return static_cast<Render::OpenGL::Renderer *>(d_func()->m_renderer); |
103 | } |
104 | |
105 | Render::OpenGL::MaterialParameterGathererJobPtr materialGathererJob() const |
106 | { |
107 | Render::OpenGL::MaterialParameterGathererJobPtr job = Render::OpenGL::MaterialParameterGathererJobPtr::create(); |
108 | job->setNodeManagers(nodeManagers()); |
109 | return job; |
110 | } |
111 | |
112 | void onRegistered() { QRenderAspect::onRegistered(); } |
113 | void onUnregistered() { QRenderAspect::onUnregistered(); } |
114 | |
115 | private: |
116 | QScopedPointer<Qt3DCore::QAspectJobManager> m_jobManager; |
117 | }; |
118 | |
119 | } // namespace Qt3DRender |
120 | |
121 | QT_END_NAMESPACE |
122 | |
123 | namespace { |
124 | |
125 | Qt3DCore::QEntity *buildSimpleScene(Qt3DRender::QFrameGraphNode *fg) |
126 | { |
127 | Qt3DCore::QEntity *root = new Qt3DCore::QEntity(); |
128 | |
129 | Qt3DRender::QRenderSettings* renderSettings = new Qt3DRender::QRenderSettings(); |
130 | renderSettings->setActiveFrameGraph(fg); |
131 | root->addComponent(comp: renderSettings); |
132 | |
133 | // Scene |
134 | { |
135 | Qt3DCore::QEntity *e = new Qt3DCore::QEntity(); |
136 | Qt3DRender::QMaterial *material = new Qt3DRender::QMaterial(); |
137 | Qt3DRender::QGeometryRenderer *geometryRenderer = new Qt3DRender::QGeometryRenderer(); |
138 | e->addComponent(comp: material); |
139 | e->addComponent(comp: geometryRenderer); |
140 | e->setParent(root); |
141 | } |
142 | { |
143 | Qt3DCore::QEntity *e = new Qt3DCore::QEntity(); |
144 | Qt3DRender::QMaterial *material = new Qt3DRender::QMaterial(); |
145 | Qt3DRender::QComputeCommand *computeCommand = new Qt3DRender::QComputeCommand(); |
146 | e->addComponent(comp: material); |
147 | e->addComponent(comp: computeCommand); |
148 | e->setParent(root); |
149 | } |
150 | |
151 | { |
152 | Qt3DCore::QEntity *e = new Qt3DCore::QEntity(); |
153 | Qt3DRender::QPointLight *light = new Qt3DRender::QPointLight(); |
154 | e->addComponent(comp: light); |
155 | e->setParent(root); |
156 | } |
157 | |
158 | { |
159 | Qt3DCore::QEntity *e = new Qt3DCore::QEntity(); |
160 | Qt3DRender::QSpotLight *light = new Qt3DRender::QSpotLight(); |
161 | e->addComponent(comp: light); |
162 | e->setParent(root); |
163 | } |
164 | |
165 | { |
166 | Qt3DCore::QEntity *e = new Qt3DCore::QEntity(); |
167 | Qt3DRender::QEnvironmentLight *light = new Qt3DRender::QEnvironmentLight(); |
168 | e->addComponent(comp: light); |
169 | e->setParent(root); |
170 | } |
171 | |
172 | return root; |
173 | } |
174 | |
175 | Qt3DCore::QEntity *buildEntityFilterTestScene(Qt3DRender::QFrameGraphNode *fg, Qt3DRender::QLayer *layer) |
176 | { |
177 | Qt3DCore::QEntity *root = new Qt3DCore::QEntity(); |
178 | |
179 | Qt3DRender::QRenderSettings* renderSettings = new Qt3DRender::QRenderSettings(); |
180 | renderSettings->setActiveFrameGraph(fg); |
181 | root->addComponent(comp: renderSettings); |
182 | |
183 | // Scene |
184 | for (int i = 0; i < 200; ++i) { |
185 | Qt3DCore::QEntity *e = new Qt3DCore::QEntity(); |
186 | Qt3DRender::QMaterial *material = new Qt3DRender::QMaterial(); |
187 | Qt3DRender::QGeometryRenderer *geometryRenderer = new Qt3DRender::QGeometryRenderer(); |
188 | e->addComponent(comp: material); |
189 | e->addComponent(comp: geometryRenderer); |
190 | if (i % 2 == 0) |
191 | e->addComponent(comp: layer); |
192 | e->setParent(root); |
193 | } |
194 | |
195 | return root; |
196 | } |
197 | |
198 | } // anonymous |
199 | |
200 | |
201 | class tst_RenderViewBuilder : public QObject |
202 | { |
203 | Q_OBJECT |
204 | |
205 | private Q_SLOTS: |
206 | |
207 | void checkInitialState() |
208 | { |
209 | // GIVEN |
210 | Qt3DRender::QViewport *viewport = new Qt3DRender::QViewport(); |
211 | Qt3DRender::QClearBuffers *clearBuffer = new Qt3DRender::QClearBuffers(viewport); |
212 | Qt3DRender::TestAspect testAspect(buildSimpleScene(fg: viewport)); |
213 | |
214 | // THEN |
215 | Qt3DRender::Render::FrameGraphNode *leafNode = testAspect.nodeManagers()->frameGraphManager()->lookupNode(id: clearBuffer->id()); |
216 | QVERIFY(leafNode != nullptr); |
217 | |
218 | { |
219 | // WHEN |
220 | Qt3DRender::Render::OpenGL::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); |
221 | |
222 | // THEN |
223 | QCOMPARE(renderViewBuilder.renderViewIndex(), 0); |
224 | QCOMPARE(renderViewBuilder.renderer(), testAspect.renderer()); |
225 | QCOMPARE(renderViewBuilder.layerCacheNeedsToBeRebuilt(), false); |
226 | QCOMPARE(renderViewBuilder.materialGathererCacheNeedsToBeRebuilt(), false); |
227 | QVERIFY(!renderViewBuilder.renderViewJob().isNull()); |
228 | QVERIFY(!renderViewBuilder.frustumCullingJob().isNull()); |
229 | QVERIFY(!renderViewBuilder.syncPreFrustumCullingJob().isNull()); |
230 | QVERIFY(!renderViewBuilder.setClearDrawBufferIndexJob().isNull()); |
231 | |
232 | QVERIFY(renderViewBuilder.filterEntityByLayerJob().isNull()); |
233 | QVERIFY(renderViewBuilder.syncFilterEntityByLayerJob().isNull()); |
234 | QVERIFY(renderViewBuilder.syncRenderViewPreCommandUpdateJob().isNull()); |
235 | QVERIFY(renderViewBuilder.syncRenderViewPostCommandUpdateJob().isNull()); |
236 | QVERIFY(renderViewBuilder.syncRenderViewPostInitializationJob().isNull()); |
237 | |
238 | QCOMPARE(renderViewBuilder.renderViewCommandUpdaterJobs().size(), 0); |
239 | QCOMPARE(renderViewBuilder.materialGathererJobs().size(), 0); |
240 | |
241 | // WHEN |
242 | renderViewBuilder.prepareJobs(); |
243 | |
244 | // THEN |
245 | QVERIFY(!renderViewBuilder.syncRenderViewPreCommandUpdateJob().isNull()); |
246 | QVERIFY(!renderViewBuilder.syncRenderViewPostCommandUpdateJob().isNull()); |
247 | QVERIFY(!renderViewBuilder.syncRenderViewPostInitializationJob().isNull()); |
248 | QVERIFY(renderViewBuilder.filterEntityByLayerJob().isNull()); |
249 | QVERIFY(renderViewBuilder.syncFilterEntityByLayerJob().isNull()); |
250 | |
251 | QCOMPARE(renderViewBuilder.renderViewCommandUpdaterJobs().size(), Qt3DRender::Render::OpenGL::RenderViewBuilder::defaultJobCount()); |
252 | QCOMPARE(renderViewBuilder.materialGathererJobs().size(), 0); |
253 | QCOMPARE(renderViewBuilder.buildJobHierachy().size(), 8 + 1 * Qt3DRender::Render::OpenGL::RenderViewBuilder::defaultJobCount()); |
254 | } |
255 | |
256 | { |
257 | // WHEN |
258 | Qt3DRender::Render::OpenGL::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); |
259 | renderViewBuilder.setOptimalJobCount(2); |
260 | renderViewBuilder.setLayerCacheNeedsToBeRebuilt(true); |
261 | renderViewBuilder.prepareJobs(); |
262 | |
263 | // THEN |
264 | QCOMPARE(renderViewBuilder.layerCacheNeedsToBeRebuilt(), true); |
265 | QVERIFY(!renderViewBuilder.filterEntityByLayerJob().isNull()); |
266 | QVERIFY(!renderViewBuilder.syncFilterEntityByLayerJob().isNull()); |
267 | |
268 | // mark jobs dirty and recheck |
269 | QCOMPARE(renderViewBuilder.buildJobHierachy().size(), 10 + renderViewBuilder.optimalJobCount()); |
270 | } |
271 | |
272 | { |
273 | // WHEN |
274 | Qt3DRender::Render::OpenGL::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); |
275 | renderViewBuilder.setOptimalJobCount(2); |
276 | renderViewBuilder.setMaterialGathererCacheNeedsToBeRebuilt(true); |
277 | renderViewBuilder.prepareJobs(); |
278 | |
279 | // THEN |
280 | QCOMPARE(renderViewBuilder.materialGathererCacheNeedsToBeRebuilt(), true); |
281 | // We have elementsPerJob = qMax(materialHandles.size() / m_optimalParallelJobCount, 1) |
282 | // Given we have 2 materials -> 1 element per job -> so we need 2 jobs |
283 | QCOMPARE(renderViewBuilder.materialGathererJobs().size(), 2); |
284 | QVERIFY(!renderViewBuilder.syncMaterialGathererJob().isNull()); |
285 | |
286 | // mark jobs dirty and recheck |
287 | QCOMPARE(renderViewBuilder.buildJobHierachy().size(), 13); |
288 | } |
289 | } |
290 | |
291 | void checkCheckJobDependencies() |
292 | { |
293 | // GIVEN |
294 | Qt3DRender::QViewport *viewport = new Qt3DRender::QViewport(); |
295 | Qt3DRender::QClearBuffers *clearBuffer = new Qt3DRender::QClearBuffers(viewport); |
296 | Qt3DRender::TestAspect testAspect(buildSimpleScene(fg: viewport)); |
297 | |
298 | auto expandBVJob = Qt3DRender::QRenderAspectPrivate::get(q: &testAspect)->m_expandBoundingVolumeJob; |
299 | auto wordTransformJob = Qt3DRender::QRenderAspectPrivate::get(q: &testAspect)->m_worldTransformJob; |
300 | auto updateTreeEnabledJob = Qt3DRender::QRenderAspectPrivate::get(q: &testAspect)->m_updateTreeEnabledJob; |
301 | auto updateEntityLayerJob = Qt3DRender::QRenderAspectPrivate::get(q: &testAspect)->m_updateEntityLayersJob; |
302 | |
303 | // THEN |
304 | Qt3DRender::Render::FrameGraphNode *leafNode = testAspect.nodeManagers()->frameGraphManager()->lookupNode(id: clearBuffer->id()); |
305 | QVERIFY(leafNode != nullptr); |
306 | |
307 | { |
308 | // WHEN |
309 | Qt3DRender::Render::OpenGL::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); |
310 | renderViewBuilder.prepareJobs(); |
311 | renderViewBuilder.buildJobHierachy(); |
312 | |
313 | // THEN |
314 | // Step 1 |
315 | QCOMPARE(renderViewBuilder.renderViewJob()->dependencies().size(), 1); // Depends upon skinning palette update |
316 | |
317 | // Step 2 |
318 | QCOMPARE(renderViewBuilder.syncRenderViewPostInitializationJob()->dependencies().size(), 1); |
319 | QCOMPARE(renderViewBuilder.syncRenderViewPostInitializationJob()->dependencies().constFirst().toStrongRef().data(), |
320 | renderViewBuilder.renderViewJob().data()); |
321 | |
322 | // Step 3 |
323 | QVERIFY(renderViewBuilder.filterEntityByLayerJob().isNull()); |
324 | QVERIFY(renderViewBuilder.syncFilterEntityByLayerJob().isNull()); |
325 | |
326 | QCOMPARE(renderViewBuilder.filterProximityJob()->dependencies().size(), 2); |
327 | QVERIFY(renderViewBuilder.filterProximityJob()->dependencies().contains(renderViewBuilder.syncRenderViewPostInitializationJob())); |
328 | QVERIFY(renderViewBuilder.filterProximityJob()->dependencies().contains(expandBVJob)); |
329 | |
330 | QCOMPARE(renderViewBuilder.setClearDrawBufferIndexJob()->dependencies().size(), 1); |
331 | QCOMPARE(renderViewBuilder.setClearDrawBufferIndexJob()->dependencies().constFirst().toStrongRef().data(), |
332 | renderViewBuilder.syncRenderViewPostInitializationJob().data()); |
333 | |
334 | QCOMPARE(renderViewBuilder.syncPreFrustumCullingJob()->dependencies().size(), 3); |
335 | QVERIFY(renderViewBuilder.syncPreFrustumCullingJob()->dependencies().contains(renderViewBuilder.syncRenderViewPostInitializationJob())); |
336 | QVERIFY(renderViewBuilder.syncPreFrustumCullingJob()->dependencies().contains(wordTransformJob)); |
337 | QVERIFY(renderViewBuilder.syncPreFrustumCullingJob()->dependencies().contains(testAspect.renderer()->updateShaderDataTransformJob())); |
338 | |
339 | // Step 4 |
340 | QCOMPARE(renderViewBuilder.frustumCullingJob()->dependencies().size(), 2); |
341 | QVERIFY(renderViewBuilder.frustumCullingJob()->dependencies().contains(renderViewBuilder.syncPreFrustumCullingJob())); |
342 | QVERIFY(renderViewBuilder.frustumCullingJob()->dependencies().contains(expandBVJob)); |
343 | |
344 | QCOMPARE(renderViewBuilder.syncRenderViewPreCommandUpdateJob()->dependencies().size(), renderViewBuilder.materialGathererJobs().size() + 7); |
345 | QVERIFY(renderViewBuilder.syncRenderViewPreCommandUpdateJob()->dependencies().contains(renderViewBuilder.syncRenderViewPostInitializationJob())); |
346 | QVERIFY(renderViewBuilder.syncRenderViewPreCommandUpdateJob()->dependencies().contains(renderViewBuilder.filterProximityJob())); |
347 | QVERIFY(renderViewBuilder.syncRenderViewPreCommandUpdateJob()->dependencies().contains(renderViewBuilder.frustumCullingJob())); |
348 | QVERIFY(renderViewBuilder.syncRenderViewPreCommandUpdateJob()->dependencies().contains(testAspect.renderer()->introspectShadersJob())); |
349 | QVERIFY(renderViewBuilder.syncRenderViewPreCommandUpdateJob()->dependencies().contains(testAspect.renderer()->bufferGathererJob())); |
350 | QVERIFY(renderViewBuilder.syncRenderViewPreCommandUpdateJob()->dependencies().contains(testAspect.renderer()->textureGathererJob())); |
351 | QVERIFY(renderViewBuilder.syncRenderViewPreCommandUpdateJob()->dependencies().contains(testAspect.renderer()->lightGathererJob())); |
352 | |
353 | // Step 5 |
354 | for (const auto &renderViewBuilderJob : renderViewBuilder.renderViewCommandUpdaterJobs()) { |
355 | QCOMPARE(renderViewBuilderJob->dependencies().size(), 1); |
356 | QCOMPARE(renderViewBuilderJob->dependencies().constFirst().toStrongRef().data(), |
357 | renderViewBuilder.syncRenderViewPreCommandUpdateJob().data()); |
358 | } |
359 | |
360 | // Step 6 |
361 | QCOMPARE(renderViewBuilder.syncRenderViewPostCommandUpdateJob()->dependencies().size(), renderViewBuilder.renderViewCommandUpdaterJobs().size()); |
362 | for (const auto &renderViewBuilderJob : renderViewBuilder.renderViewCommandUpdaterJobs()) { |
363 | QVERIFY(renderViewBuilder.syncRenderViewPostCommandUpdateJob()->dependencies().contains(renderViewBuilderJob)); |
364 | } |
365 | } |
366 | { |
367 | // WHEN |
368 | Qt3DRender::Render::OpenGL::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); |
369 | renderViewBuilder.setLayerCacheNeedsToBeRebuilt(true); |
370 | renderViewBuilder.setMaterialGathererCacheNeedsToBeRebuilt(true); |
371 | renderViewBuilder.prepareJobs(); |
372 | renderViewBuilder.buildJobHierachy(); |
373 | |
374 | // THEN |
375 | // Step 1 |
376 | QCOMPARE(renderViewBuilder.renderViewJob()->dependencies().size(), 1); // Depends upon skinning palette update |
377 | |
378 | // Step 2 |
379 | QCOMPARE(renderViewBuilder.syncRenderViewPostInitializationJob()->dependencies().size(), 1); |
380 | QCOMPARE(renderViewBuilder.syncRenderViewPostInitializationJob()->dependencies().constFirst().toStrongRef().data(), |
381 | renderViewBuilder.renderViewJob().data()); |
382 | |
383 | // Step 3 |
384 | QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->dependencies().size(), 3); |
385 | QVERIFY(renderViewBuilder.filterEntityByLayerJob()->dependencies().contains(updateEntityLayerJob)); |
386 | QVERIFY(renderViewBuilder.filterEntityByLayerJob()->dependencies().contains(renderViewBuilder.syncRenderViewPostInitializationJob())); |
387 | QVERIFY(renderViewBuilder.filterEntityByLayerJob()->dependencies().contains(updateTreeEnabledJob)); |
388 | |
389 | QCOMPARE(renderViewBuilder.syncFilterEntityByLayerJob()->dependencies().size(), 1); |
390 | QVERIFY(renderViewBuilder.syncFilterEntityByLayerJob()->dependencies().contains(renderViewBuilder.filterEntityByLayerJob())); |
391 | |
392 | QCOMPARE(renderViewBuilder.filterProximityJob()->dependencies().size(), 2); |
393 | QVERIFY(renderViewBuilder.filterProximityJob()->dependencies().contains(renderViewBuilder.syncRenderViewPostInitializationJob())); |
394 | QVERIFY(renderViewBuilder.filterProximityJob()->dependencies().contains(expandBVJob)); |
395 | |
396 | QCOMPARE(renderViewBuilder.setClearDrawBufferIndexJob()->dependencies().size(), 1); |
397 | QCOMPARE(renderViewBuilder.setClearDrawBufferIndexJob()->dependencies().constFirst().toStrongRef().data(), |
398 | renderViewBuilder.syncRenderViewPostInitializationJob().data()); |
399 | |
400 | QCOMPARE(renderViewBuilder.syncPreFrustumCullingJob()->dependencies().size(), 3); |
401 | QVERIFY(renderViewBuilder.syncPreFrustumCullingJob()->dependencies().contains(renderViewBuilder.syncRenderViewPostInitializationJob())); |
402 | QVERIFY(renderViewBuilder.syncPreFrustumCullingJob()->dependencies().contains(wordTransformJob)); |
403 | QVERIFY(renderViewBuilder.syncPreFrustumCullingJob()->dependencies().contains(testAspect.renderer()->updateShaderDataTransformJob())); |
404 | |
405 | for (const auto &materialGatherer : renderViewBuilder.materialGathererJobs()) { |
406 | QCOMPARE(materialGatherer->dependencies().size(), 3); |
407 | QVERIFY(materialGatherer->dependencies().contains(renderViewBuilder.syncRenderViewPostInitializationJob())); |
408 | QVERIFY(materialGatherer->dependencies().contains(testAspect.renderer()->introspectShadersJob())); |
409 | QVERIFY(materialGatherer->dependencies().contains(testAspect.renderer()->filterCompatibleTechniqueJob())); |
410 | } |
411 | |
412 | // Step 4 |
413 | QCOMPARE(renderViewBuilder.frustumCullingJob()->dependencies().size(), 2); |
414 | QVERIFY(renderViewBuilder.frustumCullingJob()->dependencies().contains(renderViewBuilder.syncPreFrustumCullingJob())); |
415 | QVERIFY(renderViewBuilder.frustumCullingJob()->dependencies().contains(expandBVJob)); |
416 | |
417 | QVERIFY(renderViewBuilder.syncRenderViewPreCommandUpdateJob()->dependencies().contains(renderViewBuilder.syncRenderViewPostInitializationJob())); |
418 | QVERIFY(renderViewBuilder.syncRenderViewPreCommandUpdateJob()->dependencies().contains(renderViewBuilder.syncFilterEntityByLayerJob())); |
419 | QVERIFY(renderViewBuilder.syncRenderViewPreCommandUpdateJob()->dependencies().contains(renderViewBuilder.frustumCullingJob())); |
420 | QVERIFY(renderViewBuilder.syncRenderViewPreCommandUpdateJob()->dependencies().contains(renderViewBuilder.filterProximityJob())); |
421 | QVERIFY(renderViewBuilder.syncRenderViewPreCommandUpdateJob()->dependencies().contains(testAspect.renderer()->introspectShadersJob())); |
422 | QVERIFY(renderViewBuilder.syncRenderViewPreCommandUpdateJob()->dependencies().contains(testAspect.renderer()->bufferGathererJob())); |
423 | QVERIFY(renderViewBuilder.syncRenderViewPreCommandUpdateJob()->dependencies().contains(testAspect.renderer()->textureGathererJob())); |
424 | |
425 | // Step 5 |
426 | for (const auto &renderViewBuilderJob : renderViewBuilder.renderViewCommandUpdaterJobs()) { |
427 | QCOMPARE(renderViewBuilderJob->dependencies().size(), 1); |
428 | QCOMPARE(renderViewBuilderJob->dependencies().constFirst().toStrongRef().data(), |
429 | renderViewBuilder.syncRenderViewPreCommandUpdateJob().data()); |
430 | } |
431 | |
432 | // Step 6 |
433 | QCOMPARE(renderViewBuilder.syncRenderViewPostCommandUpdateJob()->dependencies().size(), renderViewBuilder.renderViewCommandUpdaterJobs().size()); |
434 | for (const auto &renderViewBuilderJob : renderViewBuilder.renderViewCommandUpdaterJobs()) { |
435 | QVERIFY(renderViewBuilder.syncRenderViewPostCommandUpdateJob()->dependencies().contains(renderViewBuilderJob)); |
436 | } |
437 | } |
438 | } |
439 | |
440 | void checkRenderViewJobExecution() |
441 | { |
442 | // GIVEN |
443 | Qt3DRender::QViewport *viewport = new Qt3DRender::QViewport(); |
444 | Qt3DRender::QClearBuffers *clearBuffer = new Qt3DRender::QClearBuffers(viewport); |
445 | Qt3DRender::TestAspect testAspect(buildSimpleScene(fg: viewport)); |
446 | |
447 | // THEN |
448 | Qt3DRender::Render::FrameGraphNode *leafNode = testAspect.nodeManagers()->frameGraphManager()->lookupNode(id: clearBuffer->id()); |
449 | QVERIFY(leafNode != nullptr); |
450 | |
451 | // WHEN |
452 | Qt3DRender::Render::OpenGL::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); |
453 | renderViewBuilder.prepareJobs(); |
454 | renderViewBuilder.buildJobHierachy(); |
455 | renderViewBuilder.renderViewJob()->run(); |
456 | |
457 | // THEN |
458 | QVERIFY(renderViewBuilder.renderViewJob()->renderView() != nullptr); |
459 | } |
460 | |
461 | void checkLightGatherExecution() |
462 | { |
463 | // GIVEN |
464 | Qt3DRender::QViewport *viewport = new Qt3DRender::QViewport(); |
465 | Qt3DRender::QClearBuffers *clearBuffer = new Qt3DRender::QClearBuffers(viewport); |
466 | Qt3DRender::TestAspect testAspect(buildSimpleScene(fg: viewport)); |
467 | Qt3DRender::Render::OpenGL::Renderer *renderer = testAspect.renderer(); |
468 | |
469 | // THEN |
470 | Qt3DRender::Render::FrameGraphNode *leafNode = testAspect.nodeManagers()->frameGraphManager()->lookupNode(id: clearBuffer->id()); |
471 | QVERIFY(leafNode != nullptr); |
472 | |
473 | // WHEN |
474 | renderer->lightGathererJob()->run(); |
475 | |
476 | // THEN |
477 | QCOMPARE(renderer->lightGathererJob()->lights().size(), 2); |
478 | QVERIFY(renderer->lightGathererJob()->environmentLight() != nullptr); |
479 | } |
480 | |
481 | void checkRenderableEntitiesFilteringExecution() |
482 | { |
483 | // GIVEN |
484 | Qt3DRender::QViewport *viewport = new Qt3DRender::QViewport(); |
485 | Qt3DRender::QClearBuffers *clearBuffer = new Qt3DRender::QClearBuffers(viewport); |
486 | Qt3DRender::TestAspect testAspect(buildSimpleScene(fg: viewport)); |
487 | Qt3DRender::Render::OpenGL::Renderer *renderer = testAspect.renderer(); |
488 | |
489 | // THEN |
490 | Qt3DRender::Render::FrameGraphNode *leafNode = testAspect.nodeManagers()->frameGraphManager()->lookupNode(id: clearBuffer->id()); |
491 | QVERIFY(leafNode != nullptr); |
492 | |
493 | // WHEN |
494 | renderer->renderableEntityFilterJob()->run(); |
495 | |
496 | // THEN |
497 | QCOMPARE(renderer->renderableEntityFilterJob()->filteredEntities().size(), 1); |
498 | } |
499 | |
500 | void checkComputableEntitiesFilteringExecution() |
501 | { |
502 | // GIVEN |
503 | Qt3DRender::QViewport *viewport = new Qt3DRender::QViewport(); |
504 | Qt3DRender::QClearBuffers *clearBuffer = new Qt3DRender::QClearBuffers(viewport); |
505 | Qt3DRender::TestAspect testAspect(buildSimpleScene(fg: viewport)); |
506 | Qt3DRender::Render::OpenGL::Renderer *renderer = testAspect.renderer(); |
507 | |
508 | // THEN |
509 | Qt3DRender::Render::FrameGraphNode *leafNode = testAspect.nodeManagers()->frameGraphManager()->lookupNode(id: clearBuffer->id()); |
510 | QVERIFY(leafNode != nullptr); |
511 | |
512 | // WHEN |
513 | renderer->computableEntityFilterJob()->run(); |
514 | |
515 | // THEN |
516 | QCOMPARE(renderer->computableEntityFilterJob()->filteredEntities().size(), 1); |
517 | } |
518 | |
519 | void checkSyncRenderViewInitializationExecution() |
520 | { |
521 | // GIVEN |
522 | Qt3DRender::QViewport *viewport = new Qt3DRender::QViewport(); |
523 | Qt3DRender::QClearBuffers *clearBuffer = new Qt3DRender::QClearBuffers(viewport); |
524 | Qt3DRender::QLayerFilter *layerFilter = new Qt3DRender::QLayerFilter(clearBuffer); |
525 | Qt3DRender::QFrustumCulling *frustumCulling = new Qt3DRender::QFrustumCulling(layerFilter); |
526 | Qt3DRender::QTechniqueFilter *techniqueFilter = new Qt3DRender::QTechniqueFilter(frustumCulling); |
527 | Qt3DRender::QRenderPassFilter *renderPassFilter = new Qt3DRender::QRenderPassFilter(techniqueFilter); |
528 | Qt3DRender::QLayer *layer = new Qt3DRender::QLayer(); |
529 | |
530 | layerFilter->addLayer(layer); |
531 | Qt3DRender::TestAspect testAspect(buildSimpleScene(fg: viewport)); |
532 | |
533 | // THEN |
534 | Qt3DRender::Render::FrameGraphNode *leafNode = testAspect.nodeManagers()->frameGraphManager()->lookupNode(id: renderPassFilter->id()); |
535 | QVERIFY(leafNode != nullptr); |
536 | |
537 | { |
538 | // WHEN |
539 | Qt3DRender::Render::OpenGL::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); |
540 | renderViewBuilder.prepareJobs(); |
541 | renderViewBuilder.buildJobHierachy(); |
542 | |
543 | // THEN |
544 | QCOMPARE(renderViewBuilder.frustumCullingJob()->isActive(), false); |
545 | for (const auto &materialGatherer : renderViewBuilder.materialGathererJobs()) { |
546 | QVERIFY(materialGatherer->techniqueFilter() == nullptr); |
547 | QVERIFY(materialGatherer->renderPassFilter() == nullptr); |
548 | } |
549 | |
550 | // WHEN |
551 | renderViewBuilder.renderViewJob()->run(); |
552 | renderViewBuilder.syncRenderViewPostInitializationJob()->run(); |
553 | |
554 | // THEN |
555 | QCOMPARE(renderViewBuilder.frustumCullingJob()->isActive(), true); |
556 | for (const auto &materialGatherer : renderViewBuilder.materialGathererJobs()) { |
557 | QVERIFY(materialGatherer->techniqueFilter() != nullptr); |
558 | QVERIFY(materialGatherer->renderPassFilter() != nullptr); |
559 | } |
560 | } |
561 | { |
562 | // WHEN |
563 | Qt3DRender::Render::OpenGL::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); |
564 | renderViewBuilder.setLayerCacheNeedsToBeRebuilt(true); |
565 | renderViewBuilder.prepareJobs(); |
566 | renderViewBuilder.buildJobHierachy(); |
567 | |
568 | // THEN |
569 | QCOMPARE(renderViewBuilder.frustumCullingJob()->isActive(), false); |
570 | QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->hasLayerFilter(), false); |
571 | QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->layerFilters().size(), 0); |
572 | for (const auto &materialGatherer : renderViewBuilder.materialGathererJobs()) { |
573 | QVERIFY(materialGatherer->techniqueFilter() == nullptr); |
574 | QVERIFY(materialGatherer->renderPassFilter() == nullptr); |
575 | } |
576 | |
577 | // WHEN |
578 | renderViewBuilder.renderViewJob()->run(); |
579 | renderViewBuilder.syncRenderViewPostInitializationJob()->run(); |
580 | |
581 | // THEN |
582 | QCOMPARE(renderViewBuilder.frustumCullingJob()->isActive(), true); |
583 | QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->hasLayerFilter(), true); |
584 | QCOMPARE(renderViewBuilder.filterEntityByLayerJob()->layerFilters().size(), 1); |
585 | for (const auto &materialGatherer : renderViewBuilder.materialGathererJobs()) { |
586 | QVERIFY(materialGatherer->techniqueFilter() != nullptr); |
587 | QVERIFY(materialGatherer->renderPassFilter() != nullptr); |
588 | } |
589 | } |
590 | } |
591 | |
592 | void checkSyncFrustumCullingExecution() |
593 | { |
594 | // GIVEN |
595 | Qt3DRender::QViewport *viewport = new Qt3DRender::QViewport(); |
596 | Qt3DRender::QClearBuffers *clearBuffer = new Qt3DRender::QClearBuffers(viewport); |
597 | Qt3DRender::QFrustumCulling *frustumCulling = new Qt3DRender::QFrustumCulling(clearBuffer); |
598 | Qt3DRender::QCameraSelector *cameraSelector = new Qt3DRender::QCameraSelector(frustumCulling); |
599 | Qt3DRender::QCamera *camera = new Qt3DRender::QCamera(); |
600 | cameraSelector->setCamera(camera); |
601 | |
602 | Qt3DRender::TestAspect testAspect(buildSimpleScene(fg: viewport)); |
603 | |
604 | // THEN |
605 | Qt3DRender::Render::FrameGraphNode *leafNode = testAspect.nodeManagers()->frameGraphManager()->lookupNode(id: cameraSelector->id()); |
606 | QVERIFY(leafNode != nullptr); |
607 | |
608 | // WHEN |
609 | Qt3DRender::Render::OpenGL::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); |
610 | renderViewBuilder.prepareJobs(); |
611 | renderViewBuilder.buildJobHierachy(); |
612 | |
613 | // THEN |
614 | QCOMPARE(renderViewBuilder.frustumCullingJob()->viewProjection(), Matrix4x4()); |
615 | |
616 | // WHEN |
617 | renderViewBuilder.renderViewJob()->run(); |
618 | renderViewBuilder.syncPreFrustumCullingJob()->run(); |
619 | |
620 | // THEN |
621 | QCOMPARE(convertToQMatrix4x4(renderViewBuilder.frustumCullingJob()->viewProjection()), camera->projectionMatrix() * camera->viewMatrix()); |
622 | } |
623 | |
624 | void checkRemoveEntitiesNotInSubset() |
625 | { |
626 | // GIVEN |
627 | Qt3DRender::QViewport *viewport = new Qt3DRender::QViewport(); |
628 | Qt3DRender::QClearBuffers *clearBuffer = new Qt3DRender::QClearBuffers(viewport); |
629 | Qt3DRender::QLayerFilter *layerFilter = new Qt3DRender::QLayerFilter(clearBuffer); |
630 | Qt3DRender::QLayer *layer = new Qt3DRender::QLayer(); |
631 | layerFilter->addLayer(layer); |
632 | Qt3DRender::TestAspect testAspect(buildEntityFilterTestScene(fg: viewport, layer)); |
633 | Qt3DRender::Render::OpenGL::Renderer *renderer = testAspect.renderer(); |
634 | |
635 | // THEN |
636 | Qt3DRender::Render::FrameGraphNode *leafNode = testAspect.nodeManagers()->frameGraphManager()->lookupNode(id: layerFilter->id()); |
637 | QVERIFY(leafNode != nullptr); |
638 | |
639 | // WHEN |
640 | renderer->markDirty(changes: Qt3DRender::Render::AbstractRenderer::AllDirty, node: nullptr); |
641 | |
642 | Qt3DRender::Render::OpenGL::RenderViewBuilder renderViewBuilder(leafNode, 0, testAspect.renderer()); |
643 | |
644 | renderViewBuilder.setLayerCacheNeedsToBeRebuilt(true); |
645 | renderViewBuilder.prepareJobs(); |
646 | renderViewBuilder.buildJobHierachy(); |
647 | |
648 | renderer->renderableEntityFilterJob()->run(); |
649 | |
650 | renderViewBuilder.renderViewJob()->run(); |
651 | renderViewBuilder.syncRenderViewPostInitializationJob()->run(); |
652 | renderViewBuilder.filterEntityByLayerJob()->run(); |
653 | |
654 | QVector<Qt3DRender::Render::Entity *> renderableEntity = renderer->renderableEntityFilterJob()->filteredEntities(); |
655 | QVector<Qt3DRender::Render::Entity *> filteredEntity = renderViewBuilder.filterEntityByLayerJob()->filteredEntities(); |
656 | |
657 | // THEN |
658 | QCOMPARE(renderableEntity.size(), 200); |
659 | QCOMPARE(filteredEntity.size(), 100); |
660 | |
661 | std::sort(first: renderableEntity.begin(), last: renderableEntity.end()); |
662 | |
663 | // WHEN |
664 | renderableEntity = Qt3DRender::Render::OpenGL::RenderViewBuilder::entitiesInSubset(entities: renderableEntity, subset: filteredEntity); |
665 | |
666 | // THEN |
667 | QCOMPARE(renderableEntity.size(), 100); |
668 | for (const auto entity : renderableEntity) { |
669 | QVERIFY(filteredEntity.contains(entity)); |
670 | } |
671 | } |
672 | |
673 | }; |
674 | |
675 | QTEST_MAIN(tst_RenderViewBuilder) |
676 | |
677 | #include "tst_renderviewbuilder.moc" |
678 | |