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
30#include <QtTest/QTest>
31#include <Qt3DRender/qtechnique.h>
32#include <Qt3DRender/qfilterkey.h>
33#include <Qt3DRender/qparameter.h>
34#include <Qt3DRender/qrenderpass.h>
35#include <Qt3DRender/private/qtechnique_p.h>
36#include <Qt3DRender/private/technique_p.h>
37#include <Qt3DRender/private/nodemanagers_p.h>
38#include <Qt3DRender/private/managers_p.h>
39#include <Qt3DRender/private/filterkey_p.h>
40#include <Qt3DRender/private/techniquemanager_p.h>
41#include "qbackendnodetester.h"
42#include "testrenderer.h"
43
44class tst_Technique : public Qt3DCore::QBackendNodeTester
45{
46 Q_OBJECT
47
48private Q_SLOTS:
49
50 void checkInitialState()
51 {
52 // GIVEN
53 Qt3DRender::Render::Technique backendTechnique;
54
55 // THEN
56 QCOMPARE(backendTechnique.isEnabled(), false);
57 QVERIFY(backendTechnique.peerId().isNull());
58
59 QCOMPARE(backendTechnique.graphicsApiFilter()->m_minor, 0);
60 QCOMPARE(backendTechnique.graphicsApiFilter()->m_major, 0);
61 QCOMPARE(backendTechnique.graphicsApiFilter()->m_profile, Qt3DRender::QGraphicsApiFilter::NoProfile);
62 QCOMPARE(backendTechnique.graphicsApiFilter()->m_vendor, QString());
63 QCOMPARE(backendTechnique.graphicsApiFilter()->m_extensions, QStringList());
64
65 QCOMPARE(backendTechnique.parameters().size(), 0);
66 QCOMPARE(backendTechnique.filterKeys().size(), 0);
67 QCOMPARE(backendTechnique.renderPasses().size(), 0);
68 QCOMPARE(backendTechnique.isCompatibleWithRenderer(), false);
69 QVERIFY(backendTechnique.nodeManager() == nullptr);
70 }
71
72 void checkCleanupState()
73 {
74 // GIVEN
75 TestRenderer renderer;
76 Qt3DRender::Render::Technique backendTechnique;
77 Qt3DRender::Render::NodeManagers nodeManagers;
78
79 // WHEN
80 backendTechnique.setRenderer(&renderer);
81 backendTechnique.setEnabled(true);
82 backendTechnique.setNodeManager(&nodeManagers);
83 backendTechnique.setCompatibleWithRenderer(true);
84
85 {
86 Qt3DRender::QTechnique technique;
87 Qt3DRender::QRenderPass pass;
88 Qt3DRender::QParameter parameter;
89 Qt3DRender::QFilterKey filterKey;
90
91 technique.addRenderPass(pass: &pass);
92 technique.addParameter(p: &parameter);
93 technique.addFilterKey(filterKey: &filterKey);
94
95 simulateInitializationSync(frontend: &technique, backend: &backendTechnique);
96 }
97
98 backendTechnique.cleanup();
99
100 // THEN
101 QCOMPARE(backendTechnique.isEnabled(), false);
102 QCOMPARE(backendTechnique.parameters().size(), 0);
103 QCOMPARE(backendTechnique.filterKeys().size(), 0);
104 QCOMPARE(backendTechnique.renderPasses().size(), 0);
105 QCOMPARE(backendTechnique.isCompatibleWithRenderer(), false);
106 }
107
108 void checkInitializeFromPeer()
109 {
110 // GIVEN
111 TestRenderer renderer;
112 Qt3DRender::QTechnique technique;
113 Qt3DRender::QRenderPass pass;
114 Qt3DRender::QParameter parameter;
115 Qt3DRender::QFilterKey filterKey;
116
117 technique.addRenderPass(pass: &pass);
118 technique.addParameter(p: &parameter);
119 technique.addFilterKey(filterKey: &filterKey);
120
121 {
122 // WHEN
123 Qt3DRender::Render::Technique backendTechnique;
124 Qt3DRender::Render::NodeManagers nodeManagers;
125
126 backendTechnique.setRenderer(&renderer);
127 backendTechnique.setNodeManager(&nodeManagers);
128 simulateInitializationSync(frontend: &technique, backend: &backendTechnique);
129
130 // THEN
131 QCOMPARE(backendTechnique.isEnabled(), true);
132 QCOMPARE(backendTechnique.peerId(), technique.id());
133 Qt3DRender::GraphicsApiFilterData apiFilterData = Qt3DRender::QGraphicsApiFilterPrivate::get(q: technique.graphicsApiFilter())->m_data;
134 QCOMPARE(*backendTechnique.graphicsApiFilter(), apiFilterData);
135 QCOMPARE(backendTechnique.parameters().size(), 1);
136 QCOMPARE(backendTechnique.parameters().first(), parameter.id());
137 QCOMPARE(backendTechnique.filterKeys().size(), 1);
138 QCOMPARE(backendTechnique.filterKeys().first(), filterKey.id());
139 QCOMPARE(backendTechnique.renderPasses().size(), 1);
140 QCOMPARE(backendTechnique.renderPasses().first(), pass.id());
141 QCOMPARE(backendTechnique.isCompatibleWithRenderer(), false);
142 const QVector<Qt3DCore::QNodeId> dirtyTechniques = nodeManagers.techniqueManager()->takeDirtyTechniques();
143 QCOMPARE(dirtyTechniques.size(), 1);
144 QCOMPARE(dirtyTechniques.first(), backendTechnique.peerId());
145 QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TechniquesDirty);
146 }
147 renderer.clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty);
148 {
149 // WHEN
150 Qt3DRender::Render::Technique backendTechnique;
151 Qt3DRender::Render::NodeManagers nodeManagers;
152
153 backendTechnique.setNodeManager(&nodeManagers);
154 backendTechnique.setRenderer(&renderer);
155 technique.setEnabled(false);
156 simulateInitializationSync(frontend: &technique, backend: &backendTechnique);
157
158 // THEN
159 QCOMPARE(backendTechnique.peerId(), technique.id());
160 QCOMPARE(backendTechnique.isEnabled(), false);
161 QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TechniquesDirty);
162 }
163 }
164
165 void checkSetCompatibleWithRenderer()
166 {
167 // GIVEN
168 Qt3DRender::Render::Technique backendTechnique;
169
170 // THEN
171 QCOMPARE(backendTechnique.isCompatibleWithRenderer(), false);
172
173 // WHEN
174 backendTechnique.setCompatibleWithRenderer(true);
175
176 // THEN
177 QCOMPARE(backendTechnique.isCompatibleWithRenderer(), true);
178 }
179
180 void checkSceneChangeEvents()
181 {
182 // GIVEN
183 Qt3DRender::QTechnique technique;
184 Qt3DRender::Render::Technique backendTechnique;
185 Qt3DRender::Render::NodeManagers nodeManagers;
186
187 TestRenderer renderer;
188 backendTechnique.setRenderer(&renderer);
189 backendTechnique.setNodeManager(&nodeManagers);
190
191 {
192 // WHEN
193 const bool newValue = true;
194 technique.setEnabled(newValue);
195 backendTechnique.syncFromFrontEnd(frontEnd: &technique, firstTime: false);
196
197 // THEN
198 QCOMPARE(backendTechnique.isEnabled(), newValue);
199 QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TechniquesDirty);
200 renderer.clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty);
201 QCOMPARE(nodeManagers.techniqueManager()->takeDirtyTechniques().size(), 1);
202 }
203 {
204 // WHEN
205 backendTechnique.setCompatibleWithRenderer(true);
206 QCOMPARE(nodeManagers.techniqueManager()->takeDirtyTechniques().size(), 0);
207
208 technique.graphicsApiFilter()->setMajorVersion(4);
209 technique.graphicsApiFilter()->setMinorVersion(5);
210 technique.graphicsApiFilter()->setVendor(QStringLiteral("ATI"));
211
212 backendTechnique.syncFromFrontEnd(frontEnd: &technique, firstTime: false);
213
214 // THEN
215 QCOMPARE(backendTechnique.graphicsApiFilter()->m_major, technique.graphicsApiFilter()->majorVersion());
216 QCOMPARE(backendTechnique.graphicsApiFilter()->m_minor, technique.graphicsApiFilter()->minorVersion());
217 QCOMPARE(backendTechnique.graphicsApiFilter()->m_vendor, technique.graphicsApiFilter()->vendor());
218 QCOMPARE(backendTechnique.isCompatibleWithRenderer(), false);
219
220 const QVector<Qt3DCore::QNodeId> dirtyTechniques = nodeManagers.techniqueManager()->takeDirtyTechniques();
221 QCOMPARE(dirtyTechniques.size(), 1);
222 QCOMPARE(dirtyTechniques.first(), backendTechnique.peerId());
223
224 QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TechniquesDirty);
225 renderer.clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty);
226 }
227 {
228 Qt3DRender::QParameter parameter;
229
230 {
231 // WHEN
232 technique.addParameter(p: &parameter);
233 backendTechnique.syncFromFrontEnd(frontEnd: &technique, firstTime: false);
234
235 // THEN
236 QCOMPARE(backendTechnique.parameters().size(), 1);
237 QCOMPARE(backendTechnique.parameters().first(), parameter.id());
238 QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TechniquesDirty);
239 renderer.clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty);
240 }
241 {
242 // WHEN
243 technique.removeParameter(p: &parameter);
244 backendTechnique.syncFromFrontEnd(frontEnd: &technique, firstTime: false);
245
246 // THEN
247 QCOMPARE(backendTechnique.parameters().size(), 0);
248 QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TechniquesDirty);
249 renderer.clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty);
250 }
251 }
252 {
253 Qt3DRender::QFilterKey filterKey;
254
255 {
256 // WHEN
257 technique.addFilterKey(filterKey: &filterKey);
258 backendTechnique.syncFromFrontEnd(frontEnd: &technique, firstTime: false);
259
260 // THEN
261 QCOMPARE(backendTechnique.filterKeys().size(), 1);
262 QCOMPARE(backendTechnique.filterKeys().first(), filterKey.id());
263 QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TechniquesDirty);
264 renderer.clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty);
265 }
266 {
267 // WHEN
268 technique.removeFilterKey(filterKey: &filterKey);
269 backendTechnique.syncFromFrontEnd(frontEnd: &technique, firstTime: false);
270
271 // THEN
272 QCOMPARE(backendTechnique.filterKeys().size(), 0);
273 QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TechniquesDirty);
274 renderer.clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty);
275 }
276 }
277 {
278 Qt3DRender::QRenderPass pass;
279
280 {
281 // WHEN
282 technique.addRenderPass(pass: &pass);
283 backendTechnique.syncFromFrontEnd(frontEnd: &technique, firstTime: false);
284
285 // THEN
286 QCOMPARE(backendTechnique.renderPasses().size(), 1);
287 QCOMPARE(backendTechnique.renderPasses().first(), pass.id());
288 QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TechniquesDirty);
289 renderer.clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty);
290 }
291 {
292 // WHEN
293 technique.removeRenderPass(pass: &pass);
294 backendTechnique.syncFromFrontEnd(frontEnd: &technique, firstTime: false);
295
296 // THEN
297 QCOMPARE(backendTechnique.renderPasses().size(), 0);
298 QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::TechniquesDirty);
299 renderer.clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty);
300 }
301 }
302 }
303
304 void checkIsCompatibleWithFilters()
305 {
306 // GIVEN
307 TestRenderer renderer;
308 Qt3DRender::Render::Technique backendTechnique;
309 Qt3DRender::Render::NodeManagers nodeManagers;
310
311 backendTechnique.setNodeManager(&nodeManagers);
312
313 Qt3DRender::QFilterKey *filterKey1 = new Qt3DRender::QFilterKey();
314 Qt3DRender::QFilterKey *filterKey2 = new Qt3DRender::QFilterKey();
315 Qt3DRender::QFilterKey *filterKey3 = new Qt3DRender::QFilterKey();
316 Qt3DRender::QFilterKey *filterKey4 = new Qt3DRender::QFilterKey();
317 Qt3DRender::QFilterKey *filterKey5 = new Qt3DRender::QFilterKey();
318
319 filterKey1->setName(QStringLiteral("displacement"));
320 filterKey2->setName(QStringLiteral("diffRatio"));
321 filterKey3->setName(QStringLiteral("oil"));
322 filterKey4->setName(QStringLiteral("oil"));
323 filterKey5->setName(QStringLiteral("heads"));
324
325 filterKey1->setValue(QVariant(427.0f));
326 filterKey2->setValue(QVariant(4.11f));
327 filterKey3->setValue(QVariant(QStringLiteral("Valvoline-VR1")));
328 filterKey4->setValue(QVariant(QStringLiteral("Mobil-1")));
329 filterKey5->setName(QStringLiteral("AFR"));
330
331 // Create backend nodes
332 // WHEN
333 Qt3DRender::Render::FilterKey *backendFilterKey1 = nodeManagers.filterKeyManager()->getOrCreateResource(id: filterKey1->id());
334 Qt3DRender::Render::FilterKey *backendFilterKey2 = nodeManagers.filterKeyManager()->getOrCreateResource(id: filterKey2->id());
335 Qt3DRender::Render::FilterKey *backendFilterKey3 = nodeManagers.filterKeyManager()->getOrCreateResource(id: filterKey3->id());
336 Qt3DRender::Render::FilterKey *backendFilterKey4 = nodeManagers.filterKeyManager()->getOrCreateResource(id: filterKey4->id());
337 Qt3DRender::Render::FilterKey *backendFilterKey5 = nodeManagers.filterKeyManager()->getOrCreateResource(id: filterKey5->id());
338
339 backendFilterKey1->setRenderer(&renderer);
340 backendFilterKey2->setRenderer(&renderer);
341 backendFilterKey3->setRenderer(&renderer);
342 backendFilterKey4->setRenderer(&renderer);
343 backendFilterKey5->setRenderer(&renderer);
344
345 simulateInitializationSync(frontend: filterKey1, backend: backendFilterKey1);
346 simulateInitializationSync(frontend: filterKey2, backend: backendFilterKey2);
347 simulateInitializationSync(frontend: filterKey3, backend: backendFilterKey3);
348 simulateInitializationSync(frontend: filterKey4, backend: backendFilterKey4);
349 simulateInitializationSync(frontend: filterKey5, backend: backendFilterKey5);
350
351 // THEN
352 QCOMPARE(nodeManagers.filterKeyManager()->activeHandles().size(), 5);
353
354 {
355 // WHEN
356 backendTechnique.appendFilterKey(criterionId: filterKey1->id());
357 backendTechnique.appendFilterKey(criterionId: filterKey2->id());
358
359 // THEN
360 QCOMPARE(backendTechnique.filterKeys().size(), 2);
361
362 // WHEN
363 Qt3DCore::QNodeIdVector techniqueFilters;
364 techniqueFilters.push_back(t: filterKey1->id());
365 techniqueFilters.push_back(t: filterKey2->id());
366 techniqueFilters.push_back(t: filterKey3->id());
367 techniqueFilters.push_back(t: filterKey5->id());
368
369 // THEN -> incompatible technique doesn't have enough filters
370 QCOMPARE(backendTechnique.isCompatibleWithFilters(techniqueFilters), false);
371
372 // WHEN
373 backendTechnique.removeFilterKey(criterionId: filterKey1->id());
374 backendTechnique.removeFilterKey(criterionId: filterKey2->id());
375
376 // THEN
377 QCOMPARE(backendTechnique.filterKeys().size(), 0);
378 }
379
380 {
381 // WHEN
382 backendTechnique.appendFilterKey(criterionId: filterKey1->id());
383 backendTechnique.appendFilterKey(criterionId: filterKey2->id());
384 backendTechnique.appendFilterKey(criterionId: filterKey3->id());
385 backendTechnique.appendFilterKey(criterionId: filterKey5->id());
386
387 // THEN
388 QCOMPARE(backendTechnique.filterKeys().size(), 4);
389
390 // WHEN
391 Qt3DCore::QNodeIdVector techniqueFilters;
392 techniqueFilters.push_back(t: filterKey1->id());
393 techniqueFilters.push_back(t: filterKey2->id());
394 techniqueFilters.push_back(t: filterKey3->id());
395 techniqueFilters.push_back(t: filterKey5->id());
396
397 // THEN -> compatible same number
398 QCOMPARE(backendTechnique.isCompatibleWithFilters(techniqueFilters), true);
399
400 // WHEN
401 backendTechnique.removeFilterKey(criterionId: filterKey1->id());
402 backendTechnique.removeFilterKey(criterionId: filterKey2->id());
403 backendTechnique.removeFilterKey(criterionId: filterKey3->id());
404 backendTechnique.removeFilterKey(criterionId: filterKey5->id());
405
406 // THEN
407 QCOMPARE(backendTechnique.filterKeys().size(), 0);
408 }
409
410 {
411 // WHEN
412 backendTechnique.appendFilterKey(criterionId: filterKey1->id());
413 backendTechnique.appendFilterKey(criterionId: filterKey2->id());
414 backendTechnique.appendFilterKey(criterionId: filterKey3->id());
415 backendTechnique.appendFilterKey(criterionId: filterKey5->id());
416
417 // THEN
418 QCOMPARE(backendTechnique.filterKeys().size(), 4);
419
420 // WHEN
421 Qt3DCore::QNodeIdVector techniqueFilters;
422 techniqueFilters.push_back(t: filterKey1->id());
423 techniqueFilters.push_back(t: filterKey2->id());
424 techniqueFilters.push_back(t: filterKey4->id());
425 techniqueFilters.push_back(t: filterKey5->id());
426
427 // THEN -> compatible same number, one not matching
428 QCOMPARE(backendTechnique.isCompatibleWithFilters(techniqueFilters), false);
429
430 // WHEN
431 backendTechnique.removeFilterKey(criterionId: filterKey1->id());
432 backendTechnique.removeFilterKey(criterionId: filterKey2->id());
433 backendTechnique.removeFilterKey(criterionId: filterKey3->id());
434 backendTechnique.removeFilterKey(criterionId: filterKey5->id());
435
436 // THEN
437 QCOMPARE(backendTechnique.filterKeys().size(), 0);
438 }
439
440 {
441 // WHEN
442 backendTechnique.appendFilterKey(criterionId: filterKey1->id());
443 backendTechnique.appendFilterKey(criterionId: filterKey2->id());
444 backendTechnique.appendFilterKey(criterionId: filterKey3->id());
445 backendTechnique.appendFilterKey(criterionId: filterKey5->id());
446
447 // THEN
448 QCOMPARE(backendTechnique.filterKeys().size(), 4);
449
450 // WHEN
451 Qt3DCore::QNodeIdVector techniqueFilters;
452 techniqueFilters.push_back(t: filterKey1->id());
453 techniqueFilters.push_back(t: filterKey2->id());
454 techniqueFilters.push_back(t: filterKey3->id());
455
456 // THEN -> technique has more than necessary filters
457 QCOMPARE(backendTechnique.isCompatibleWithFilters(techniqueFilters), true);
458
459 // WHEN
460 backendTechnique.removeFilterKey(criterionId: filterKey1->id());
461 backendTechnique.removeFilterKey(criterionId: filterKey2->id());
462 backendTechnique.removeFilterKey(criterionId: filterKey3->id());
463 backendTechnique.removeFilterKey(criterionId: filterKey5->id());
464
465 // THEN
466 QCOMPARE(backendTechnique.filterKeys().size(), 0);
467 }
468
469 {
470 // WHEN
471 backendTechnique.appendFilterKey(criterionId: filterKey1->id());
472 backendTechnique.appendFilterKey(criterionId: filterKey2->id());
473 backendTechnique.appendFilterKey(criterionId: filterKey3->id());
474 backendTechnique.appendFilterKey(criterionId: filterKey5->id());
475
476 // THEN
477 QCOMPARE(backendTechnique.filterKeys().size(), 4);
478
479 // WHEN
480 Qt3DCore::QNodeIdVector techniqueFilters;
481 techniqueFilters.push_back(t: filterKey1->id());
482 techniqueFilters.push_back(t: filterKey2->id());
483 techniqueFilters.push_back(t: filterKey4->id());
484
485 // THEN -> technique has more than necessary filters
486 // but one is not matching
487 QCOMPARE(backendTechnique.isCompatibleWithFilters(techniqueFilters), false);
488
489 // WHEN
490 backendTechnique.removeFilterKey(criterionId: filterKey1->id());
491 backendTechnique.removeFilterKey(criterionId: filterKey2->id());
492 backendTechnique.removeFilterKey(criterionId: filterKey3->id());
493 backendTechnique.removeFilterKey(criterionId: filterKey5->id());
494
495 // THEN
496 QCOMPARE(backendTechnique.filterKeys().size(), 0);
497 }
498 }
499};
500
501QTEST_MAIN(tst_Technique)
502
503#include "tst_technique.moc"
504

source code of qt3d/tests/auto/render/technique/tst_technique.cpp