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
58QT_BEGIN_NAMESPACE
59
60namespace Qt3DRender {
61
62class TestAspect : public QRenderAspect
63{
64public:
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
115private:
116 QScopedPointer<Qt3DCore::QAspectJobManager> m_jobManager;
117};
118
119} // namespace Qt3DRender
120
121QT_END_NAMESPACE
122
123namespace {
124
125Qt3DCore::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
175Qt3DCore::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
201class tst_RenderViewBuilder : public QObject
202{
203 Q_OBJECT
204
205private 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
675QTEST_MAIN(tst_RenderViewBuilder)
676
677#include "tst_renderviewbuilder.moc"
678

source code of qt3d/tests/auto/render/opengl/renderviewbuilder/tst_renderviewbuilder.cpp