1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2017 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 | |
30 | #include <QtTest/QTest> |
31 | #include <Qt3DRender/qshaderprogram.h> |
32 | #include <Qt3DRender/qshaderprogrambuilder.h> |
33 | #include <Qt3DRender/private/qshaderprogrambuilder_p.h> |
34 | #include <QObject> |
35 | #include <QSignalSpy> |
36 | #include <Qt3DCore/qpropertyupdatedchange.h> |
37 | #include <Qt3DCore/private/qnodecreatedchangegenerator_p.h> |
38 | #include <Qt3DCore/qnodecreatedchange.h> |
39 | #include "testpostmanarbiter.h" |
40 | |
41 | class tst_QShaderProgramBuilder : public Qt3DRender::QShaderProgramBuilder |
42 | { |
43 | Q_OBJECT |
44 | public: |
45 | tst_QShaderProgramBuilder() |
46 | : Qt3DRender::QShaderProgramBuilder() |
47 | { |
48 | qRegisterMetaType<Qt3DRender::QShaderProgram*>(typeName: "Qt3DRender::QShaderProgram*" ); |
49 | } |
50 | |
51 | private Q_SLOTS: |
52 | void checkDefaultConstruction() |
53 | { |
54 | // GIVEN |
55 | Qt3DRender::QShaderProgramBuilder builder; |
56 | |
57 | // THEN |
58 | QVERIFY(!builder.shaderProgram()); |
59 | QVERIFY(builder.enabledLayers().isEmpty()); |
60 | QCOMPARE(builder.vertexShaderGraph(), QUrl()); |
61 | QCOMPARE(builder.tessellationControlShaderGraph(), QUrl()); |
62 | QCOMPARE(builder.tessellationEvaluationShaderGraph(), QUrl()); |
63 | QCOMPARE(builder.geometryShaderGraph(), QUrl()); |
64 | QCOMPARE(builder.fragmentShaderGraph(), QUrl()); |
65 | QCOMPARE(builder.computeShaderGraph(), QUrl()); |
66 | QCOMPARE(builder.vertexShaderCode(), QByteArray()); |
67 | QCOMPARE(builder.fragmentShaderCode(), QByteArray()); |
68 | QCOMPARE(builder.computeShaderCode(), QByteArray()); |
69 | QCOMPARE(builder.geometryShaderCode(), QByteArray()); |
70 | QCOMPARE(builder.tessellationEvaluationShaderCode(), QByteArray()); |
71 | QCOMPARE(builder.tessellationControlShaderCode(), QByteArray()); |
72 | } |
73 | |
74 | void checkPropertyChanges() |
75 | { |
76 | // GIVEN |
77 | Qt3DRender::QShaderProgramBuilder builder; |
78 | |
79 | { |
80 | // WHEN |
81 | QSignalSpy spy(&builder, SIGNAL(shaderProgramChanged(Qt3DRender::QShaderProgram*))); |
82 | auto newValue = new Qt3DRender::QShaderProgram(&builder); |
83 | builder.setShaderProgram(newValue); |
84 | |
85 | // THEN |
86 | QVERIFY(spy.isValid()); |
87 | QCOMPARE(builder.shaderProgram(), newValue); |
88 | QCOMPARE(spy.count(), 1); |
89 | |
90 | // WHEN |
91 | spy.clear(); |
92 | builder.setShaderProgram(newValue); |
93 | |
94 | // THEN |
95 | QCOMPARE(builder.shaderProgram(), newValue); |
96 | QCOMPARE(spy.count(), 0); |
97 | } |
98 | { |
99 | // WHEN |
100 | QSignalSpy spy(&builder, SIGNAL(enabledLayersChanged(QStringList))); |
101 | const auto newValue = QStringList() << "foo" << "bar" ; |
102 | builder.setEnabledLayers(newValue); |
103 | |
104 | // THEN |
105 | QVERIFY(spy.isValid()); |
106 | QCOMPARE(builder.enabledLayers(), newValue); |
107 | QCOMPARE(spy.count(), 1); |
108 | |
109 | // WHEN |
110 | spy.clear(); |
111 | builder.setEnabledLayers(newValue); |
112 | |
113 | // THEN |
114 | QCOMPARE(builder.enabledLayers(), newValue); |
115 | QCOMPARE(spy.count(), 0); |
116 | } |
117 | { |
118 | // WHEN |
119 | QSignalSpy spy(&builder, SIGNAL(vertexShaderGraphChanged(QUrl))); |
120 | const auto newValue = QUrl::fromEncoded(url: "qrc:/vertex.json" ); |
121 | builder.setVertexShaderGraph(newValue); |
122 | |
123 | // THEN |
124 | QVERIFY(spy.isValid()); |
125 | QCOMPARE(builder.vertexShaderGraph(), newValue); |
126 | QCOMPARE(spy.count(), 1); |
127 | |
128 | // WHEN |
129 | spy.clear(); |
130 | builder.setVertexShaderGraph(newValue); |
131 | |
132 | // THEN |
133 | QCOMPARE(builder.vertexShaderGraph(), newValue); |
134 | QCOMPARE(spy.count(), 0); |
135 | } |
136 | { |
137 | // WHEN |
138 | QSignalSpy spy(&builder, SIGNAL(tessellationControlShaderGraphChanged(QUrl))); |
139 | const auto newValue = QUrl::fromEncoded(url: "qrc:/tesscontrol.json" ); |
140 | builder.setTessellationControlShaderGraph(newValue); |
141 | |
142 | // THEN |
143 | QVERIFY(spy.isValid()); |
144 | QCOMPARE(builder.tessellationControlShaderGraph(), newValue); |
145 | QCOMPARE(spy.count(), 1); |
146 | |
147 | // WHEN |
148 | spy.clear(); |
149 | builder.setTessellationControlShaderGraph(newValue); |
150 | |
151 | // THEN |
152 | QCOMPARE(builder.tessellationControlShaderGraph(), newValue); |
153 | QCOMPARE(spy.count(), 0); |
154 | } |
155 | { |
156 | // WHEN |
157 | QSignalSpy spy(&builder, SIGNAL(tessellationEvaluationShaderGraphChanged(QUrl))); |
158 | const auto newValue = QUrl::fromEncoded(url: "qrc:/tesseval.json" ); |
159 | builder.setTessellationEvaluationShaderGraph(newValue); |
160 | |
161 | // THEN |
162 | QVERIFY(spy.isValid()); |
163 | QCOMPARE(builder.tessellationEvaluationShaderGraph(), newValue); |
164 | QCOMPARE(spy.count(), 1); |
165 | |
166 | // WHEN |
167 | spy.clear(); |
168 | builder.setTessellationEvaluationShaderGraph(newValue); |
169 | |
170 | // THEN |
171 | QCOMPARE(builder.tessellationEvaluationShaderGraph(), newValue); |
172 | QCOMPARE(spy.count(), 0); |
173 | } |
174 | { |
175 | // WHEN |
176 | QSignalSpy spy(&builder, SIGNAL(geometryShaderGraphChanged(QUrl))); |
177 | const auto newValue = QUrl::fromEncoded(url: "qrc:/geometry.json" ); |
178 | builder.setGeometryShaderGraph(newValue); |
179 | |
180 | // THEN |
181 | QVERIFY(spy.isValid()); |
182 | QCOMPARE(builder.geometryShaderGraph(), newValue); |
183 | QCOMPARE(spy.count(), 1); |
184 | |
185 | // WHEN |
186 | spy.clear(); |
187 | builder.setGeometryShaderGraph(newValue); |
188 | |
189 | // THEN |
190 | QCOMPARE(builder.geometryShaderGraph(), newValue); |
191 | QCOMPARE(spy.count(), 0); |
192 | } |
193 | { |
194 | // WHEN |
195 | QSignalSpy spy(&builder, SIGNAL(fragmentShaderGraphChanged(QUrl))); |
196 | const auto newValue = QUrl::fromEncoded(url: "qrc:/fragment.json" ); |
197 | builder.setFragmentShaderGraph(newValue); |
198 | |
199 | // THEN |
200 | QVERIFY(spy.isValid()); |
201 | QCOMPARE(builder.fragmentShaderGraph(), newValue); |
202 | QCOMPARE(spy.count(), 1); |
203 | |
204 | // WHEN |
205 | spy.clear(); |
206 | builder.setFragmentShaderGraph(newValue); |
207 | |
208 | // THEN |
209 | QCOMPARE(builder.fragmentShaderGraph(), newValue); |
210 | QCOMPARE(spy.count(), 0); |
211 | } |
212 | { |
213 | // WHEN |
214 | QSignalSpy spy(&builder, SIGNAL(computeShaderGraphChanged(QUrl))); |
215 | const auto newValue = QUrl::fromEncoded(url: "qrc:/compute.json" ); |
216 | builder.setComputeShaderGraph(newValue); |
217 | |
218 | // THEN |
219 | QVERIFY(spy.isValid()); |
220 | QCOMPARE(builder.computeShaderGraph(), newValue); |
221 | QCOMPARE(spy.count(), 1); |
222 | |
223 | // WHEN |
224 | spy.clear(); |
225 | builder.setComputeShaderGraph(newValue); |
226 | |
227 | // THEN |
228 | QCOMPARE(builder.computeShaderGraph(), newValue); |
229 | QCOMPARE(spy.count(), 0); |
230 | } |
231 | } |
232 | |
233 | void checkShaderProgramBookkeeping() |
234 | { |
235 | // GIVEN |
236 | QScopedPointer<Qt3DRender::QShaderProgramBuilder> builder(new Qt3DRender::QShaderProgramBuilder); |
237 | { |
238 | // WHEN |
239 | Qt3DRender::QShaderProgram program; |
240 | builder->setShaderProgram(&program); |
241 | |
242 | // THEN |
243 | QCOMPARE(program.parent(), builder.data()); |
244 | QCOMPARE(builder->shaderProgram(), &program); |
245 | } |
246 | // THEN (Should not crash and effect be unset) |
247 | QVERIFY(!builder->shaderProgram()); |
248 | |
249 | { |
250 | // WHEN |
251 | Qt3DRender::QShaderProgramBuilder someOtherBuilder; |
252 | QScopedPointer<Qt3DRender::QShaderProgram> program(new Qt3DRender::QShaderProgram(&someOtherBuilder)); |
253 | builder->setShaderProgram(program.data()); |
254 | |
255 | // THEN |
256 | QCOMPARE(program->parent(), &someOtherBuilder); |
257 | QCOMPARE(builder->shaderProgram(), program.data()); |
258 | |
259 | // WHEN |
260 | builder.reset(); |
261 | program.reset(); |
262 | |
263 | // THEN Should not crash when the effect is destroyed (tests for failed removal of destruction helper) |
264 | } |
265 | } |
266 | |
267 | void checkCreationData() |
268 | { |
269 | // GIVEN |
270 | Qt3DRender::QShaderProgramBuilder builder; |
271 | |
272 | builder.setShaderProgram(new Qt3DRender::QShaderProgram(&builder)); |
273 | builder.setEnabledLayers({"foo" , "bar" }); |
274 | builder.setVertexShaderGraph(QUrl::fromEncoded(url: "qrc:/vertex.json" )); |
275 | builder.setTessellationControlShaderGraph(QUrl::fromEncoded(url: "qrc:/tesscontrol.json" )); |
276 | builder.setTessellationEvaluationShaderGraph(QUrl::fromEncoded(url: "qrc:/tesseval.json" )); |
277 | builder.setGeometryShaderGraph(QUrl::fromEncoded(url: "qrc:/geometry.json" )); |
278 | builder.setFragmentShaderGraph(QUrl::fromEncoded(url: "qrc:/fragment.json" )); |
279 | builder.setComputeShaderGraph(QUrl::fromEncoded(url: "qrc:/compute.json" )); |
280 | |
281 | // WHEN |
282 | QVector<Qt3DCore::QNodeCreatedChangeBasePtr> creationChanges; |
283 | |
284 | { |
285 | Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&builder); |
286 | creationChanges = creationChangeGenerator.creationChanges(); |
287 | } |
288 | |
289 | // THEN |
290 | { |
291 | QCOMPARE(creationChanges.size(), 2); // second one is for the shader program child |
292 | |
293 | const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QShaderProgramBuilderData>>(src: creationChanges.first()); |
294 | const Qt3DRender::QShaderProgramBuilderData cloneData = creationChangeData->data; |
295 | |
296 | QCOMPARE(builder.shaderProgram()->id(), cloneData.shaderProgramId); |
297 | QCOMPARE(builder.enabledLayers(), cloneData.enabledLayers); |
298 | QCOMPARE(builder.vertexShaderGraph(), cloneData.vertexShaderGraph); |
299 | QCOMPARE(builder.tessellationControlShaderGraph(), cloneData.tessellationControlShaderGraph); |
300 | QCOMPARE(builder.tessellationEvaluationShaderGraph(), cloneData.tessellationEvaluationShaderGraph); |
301 | QCOMPARE(builder.geometryShaderGraph(), cloneData.geometryShaderGraph); |
302 | QCOMPARE(builder.fragmentShaderGraph(), cloneData.fragmentShaderGraph); |
303 | QCOMPARE(builder.computeShaderGraph(), cloneData.computeShaderGraph); |
304 | QCOMPARE(builder.id(), creationChangeData->subjectId()); |
305 | QCOMPARE(builder.isEnabled(), true); |
306 | QCOMPARE(builder.isEnabled(), creationChangeData->isNodeEnabled()); |
307 | QCOMPARE(builder.metaObject(), creationChangeData->metaObject()); |
308 | } |
309 | |
310 | // WHEN |
311 | builder.setEnabled(false); |
312 | |
313 | { |
314 | Qt3DCore::QNodeCreatedChangeGenerator creationChangeGenerator(&builder); |
315 | creationChanges = creationChangeGenerator.creationChanges(); |
316 | } |
317 | |
318 | // THEN |
319 | { |
320 | QCOMPARE(creationChanges.size(), 2); // second one is for the shader program child |
321 | |
322 | const auto creationChangeData = qSharedPointerCast<Qt3DCore::QNodeCreatedChange<Qt3DRender::QShaderProgramBuilderData>>(src: creationChanges.first()); |
323 | const Qt3DRender::QShaderProgramBuilderData cloneData = creationChangeData->data; |
324 | |
325 | QCOMPARE(builder.shaderProgram()->id(), cloneData.shaderProgramId); |
326 | QCOMPARE(builder.enabledLayers(), cloneData.enabledLayers); |
327 | QCOMPARE(builder.vertexShaderGraph(), cloneData.vertexShaderGraph); |
328 | QCOMPARE(builder.tessellationControlShaderGraph(), cloneData.tessellationControlShaderGraph); |
329 | QCOMPARE(builder.tessellationEvaluationShaderGraph(), cloneData.tessellationEvaluationShaderGraph); |
330 | QCOMPARE(builder.geometryShaderGraph(), cloneData.geometryShaderGraph); |
331 | QCOMPARE(builder.fragmentShaderGraph(), cloneData.fragmentShaderGraph); |
332 | QCOMPARE(builder.computeShaderGraph(), cloneData.computeShaderGraph); |
333 | QCOMPARE(builder.id(), creationChangeData->subjectId()); |
334 | QCOMPARE(builder.isEnabled(), false); |
335 | QCOMPARE(builder.isEnabled(), creationChangeData->isNodeEnabled()); |
336 | QCOMPARE(builder.metaObject(), creationChangeData->metaObject()); |
337 | } |
338 | } |
339 | |
340 | void checkShaderProgramUpdate() |
341 | { |
342 | // GIVEN |
343 | TestArbiter arbiter; |
344 | Qt3DRender::QShaderProgramBuilder builder; |
345 | arbiter.setArbiterOnNode(&builder); |
346 | auto program = new Qt3DRender::QShaderProgram(&builder); |
347 | |
348 | { |
349 | // WHEN |
350 | builder.setShaderProgram(program); |
351 | QCoreApplication::processEvents(); |
352 | |
353 | // THEN |
354 | QCOMPARE(arbiter.events.size(), 0); |
355 | QCOMPARE(arbiter.dirtyNodes.size(), 1); |
356 | QCOMPARE(arbiter.dirtyNodes.front(), &builder); |
357 | |
358 | arbiter.dirtyNodes.clear(); |
359 | } |
360 | |
361 | { |
362 | // WHEN |
363 | builder.setShaderProgram(program); |
364 | QCoreApplication::processEvents(); |
365 | |
366 | // THEN |
367 | QCOMPARE(arbiter.events.size(), 0); |
368 | QCOMPARE(arbiter.dirtyNodes.size(), 0); |
369 | } |
370 | } |
371 | |
372 | void checkEnabledLayersUpdate() |
373 | { |
374 | // GIVEN |
375 | TestArbiter arbiter; |
376 | Qt3DRender::QShaderProgramBuilder builder; |
377 | arbiter.setArbiterOnNode(&builder); |
378 | const auto layers = QStringList() << "foo" << "bar" ; |
379 | |
380 | { |
381 | // WHEN |
382 | builder.setEnabledLayers(layers); |
383 | QCoreApplication::processEvents(); |
384 | |
385 | // THEN |
386 | QCOMPARE(arbiter.events.size(), 0); |
387 | QCOMPARE(arbiter.dirtyNodes.size(), 1); |
388 | QCOMPARE(arbiter.dirtyNodes.front(), &builder); |
389 | |
390 | arbiter.dirtyNodes.clear(); |
391 | } |
392 | |
393 | { |
394 | // WHEN |
395 | builder.setEnabledLayers(layers); |
396 | QCoreApplication::processEvents(); |
397 | |
398 | // THEN |
399 | QCOMPARE(arbiter.events.size(), 0); |
400 | QCOMPARE(arbiter.dirtyNodes.size(), 0); |
401 | } |
402 | } |
403 | |
404 | void checkVertexShaderGraphUpdate() |
405 | { |
406 | // GIVEN |
407 | TestArbiter arbiter; |
408 | Qt3DRender::QShaderProgramBuilder builder; |
409 | arbiter.setArbiterOnNode(&builder); |
410 | |
411 | { |
412 | // WHEN |
413 | builder.setVertexShaderGraph(QUrl::fromEncoded(url: "qrc:/vertex.json" )); |
414 | QCoreApplication::processEvents(); |
415 | |
416 | // THEN |
417 | QCOMPARE(arbiter.events.size(), 0); |
418 | QCOMPARE(arbiter.dirtyNodes.size(), 1); |
419 | QCOMPARE(arbiter.dirtyNodes.front(), &builder); |
420 | |
421 | arbiter.dirtyNodes.clear(); |
422 | } |
423 | |
424 | { |
425 | // WHEN |
426 | builder.setVertexShaderGraph(QUrl::fromEncoded(url: "qrc:/vertex.json" )); |
427 | QCoreApplication::processEvents(); |
428 | |
429 | // THEN |
430 | QCOMPARE(arbiter.events.size(), 0); |
431 | QCOMPARE(arbiter.dirtyNodes.size(), 0); |
432 | } |
433 | |
434 | } |
435 | |
436 | void checkTessellationControlShaderGraphUpdate() |
437 | { |
438 | // GIVEN |
439 | TestArbiter arbiter; |
440 | Qt3DRender::QShaderProgramBuilder builder; |
441 | arbiter.setArbiterOnNode(&builder); |
442 | |
443 | { |
444 | // WHEN |
445 | builder.setTessellationControlShaderGraph(QUrl::fromEncoded(url: "qrc:/tesscontrol.json" )); |
446 | QCoreApplication::processEvents(); |
447 | |
448 | // THEN |
449 | QCOMPARE(arbiter.events.size(), 0); |
450 | QCOMPARE(arbiter.dirtyNodes.size(), 1); |
451 | QCOMPARE(arbiter.dirtyNodes.front(), &builder); |
452 | |
453 | arbiter.dirtyNodes.clear(); |
454 | } |
455 | |
456 | { |
457 | // WHEN |
458 | builder.setTessellationControlShaderGraph(QUrl::fromEncoded(url: "qrc:/tesscontrol.json" )); |
459 | QCoreApplication::processEvents(); |
460 | |
461 | // THEN |
462 | QCOMPARE(arbiter.events.size(), 0); |
463 | QCOMPARE(arbiter.dirtyNodes.size(), 0); |
464 | } |
465 | |
466 | } |
467 | |
468 | void checkTessellationEvaluationShaderGraphUpdate() |
469 | { |
470 | // GIVEN |
471 | TestArbiter arbiter; |
472 | Qt3DRender::QShaderProgramBuilder builder; |
473 | arbiter.setArbiterOnNode(&builder); |
474 | |
475 | { |
476 | // WHEN |
477 | builder.setTessellationEvaluationShaderGraph(QUrl::fromEncoded(url: "qrc:/tesseval.json" )); |
478 | QCoreApplication::processEvents(); |
479 | |
480 | // THEN |
481 | QCOMPARE(arbiter.events.size(), 0); |
482 | QCOMPARE(arbiter.dirtyNodes.size(), 1); |
483 | QCOMPARE(arbiter.dirtyNodes.front(), &builder); |
484 | |
485 | arbiter.dirtyNodes.clear(); |
486 | } |
487 | |
488 | { |
489 | // WHEN |
490 | builder.setTessellationEvaluationShaderGraph(QUrl::fromEncoded(url: "qrc:/tesseval.json" )); |
491 | QCoreApplication::processEvents(); |
492 | |
493 | // THEN |
494 | QCOMPARE(arbiter.events.size(), 0); |
495 | QCOMPARE(arbiter.dirtyNodes.size(), 0); |
496 | } |
497 | |
498 | } |
499 | |
500 | void checkGeometryShaderGraphUpdate() |
501 | { |
502 | // GIVEN |
503 | TestArbiter arbiter; |
504 | Qt3DRender::QShaderProgramBuilder builder; |
505 | arbiter.setArbiterOnNode(&builder); |
506 | |
507 | { |
508 | // WHEN |
509 | builder.setGeometryShaderGraph(QUrl::fromEncoded(url: "qrc:/geometry.json" )); |
510 | QCoreApplication::processEvents(); |
511 | |
512 | // THEN |
513 | QCOMPARE(arbiter.events.size(), 0); |
514 | QCOMPARE(arbiter.dirtyNodes.size(), 1); |
515 | QCOMPARE(arbiter.dirtyNodes.front(), &builder); |
516 | |
517 | arbiter.dirtyNodes.clear(); |
518 | } |
519 | |
520 | { |
521 | // WHEN |
522 | builder.setGeometryShaderGraph(QUrl::fromEncoded(url: "qrc:/geometry.json" )); |
523 | QCoreApplication::processEvents(); |
524 | |
525 | // THEN |
526 | QCOMPARE(arbiter.events.size(), 0); |
527 | QCOMPARE(arbiter.dirtyNodes.size(), 0); |
528 | } |
529 | |
530 | } |
531 | |
532 | void checkFragmentShaderGraphUpdate() |
533 | { |
534 | // GIVEN |
535 | TestArbiter arbiter; |
536 | Qt3DRender::QShaderProgramBuilder builder; |
537 | arbiter.setArbiterOnNode(&builder); |
538 | |
539 | { |
540 | // WHEN |
541 | builder.setFragmentShaderGraph(QUrl::fromEncoded(url: "qrc:/fragment.json" )); |
542 | QCoreApplication::processEvents(); |
543 | |
544 | // THEN |
545 | QCOMPARE(arbiter.events.size(), 0); |
546 | QCOMPARE(arbiter.dirtyNodes.size(), 1); |
547 | QCOMPARE(arbiter.dirtyNodes.front(), &builder); |
548 | |
549 | arbiter.dirtyNodes.clear(); |
550 | } |
551 | |
552 | { |
553 | // WHEN |
554 | builder.setFragmentShaderGraph(QUrl::fromEncoded(url: "qrc:/fragment.json" )); |
555 | QCoreApplication::processEvents(); |
556 | |
557 | // THEN |
558 | QCOMPARE(arbiter.events.size(), 0); |
559 | QCOMPARE(arbiter.dirtyNodes.size(), 0); |
560 | } |
561 | |
562 | } |
563 | |
564 | void checkComputeShaderGraphUpdate() |
565 | { |
566 | // GIVEN |
567 | TestArbiter arbiter; |
568 | Qt3DRender::QShaderProgramBuilder builder; |
569 | arbiter.setArbiterOnNode(&builder); |
570 | |
571 | { |
572 | // WHEN |
573 | builder.setComputeShaderGraph(QUrl::fromEncoded(url: "qrc:/compute.json" )); |
574 | QCoreApplication::processEvents(); |
575 | |
576 | // THEN |
577 | QCOMPARE(arbiter.events.size(), 0); |
578 | QCOMPARE(arbiter.dirtyNodes.size(), 1); |
579 | QCOMPARE(arbiter.dirtyNodes.front(), &builder); |
580 | |
581 | arbiter.dirtyNodes.clear(); |
582 | } |
583 | |
584 | { |
585 | // WHEN |
586 | builder.setComputeShaderGraph(QUrl::fromEncoded(url: "qrc:/compute.json" )); |
587 | QCoreApplication::processEvents(); |
588 | |
589 | // THEN |
590 | QCOMPARE(arbiter.events.size(), 0); |
591 | QCOMPARE(arbiter.dirtyNodes.size(), 0); |
592 | } |
593 | } |
594 | |
595 | void checkGeneratedCodePropertyUpdates() |
596 | { |
597 | Qt3DRender::QShaderProgramBuilderPrivate *dBuilder = static_cast<decltype(dBuilder)>(Qt3DCore::QNodePrivate::get(q: this)); |
598 | { |
599 | // WHEN |
600 | QSignalSpy spy(this, SIGNAL(vertexShaderCodeChanged(QByteArray))); |
601 | dBuilder->setShaderCode(QByteArrayLiteral("vertex" ), type: Qt3DRender::QShaderProgram::Vertex); |
602 | |
603 | // THEN |
604 | QVERIFY(spy.isValid()); |
605 | QCOMPARE(spy.count(), 1); |
606 | QCOMPARE(vertexShaderCode(), QByteArrayLiteral("vertex" )); |
607 | } |
608 | { |
609 | // WHEN |
610 | QSignalSpy spy(this, SIGNAL(fragmentShaderCodeChanged(QByteArray))); |
611 | dBuilder->setShaderCode(QByteArrayLiteral("fragment" ), type: Qt3DRender::QShaderProgram::Fragment); |
612 | |
613 | // THEN |
614 | QVERIFY(spy.isValid()); |
615 | QCOMPARE(spy.count(), 1); |
616 | QCOMPARE(fragmentShaderCode(), QByteArrayLiteral("fragment" )); |
617 | } |
618 | { |
619 | // WHEN |
620 | QSignalSpy spy(this, SIGNAL(geometryShaderCodeChanged(QByteArray))); |
621 | dBuilder->setShaderCode(QByteArrayLiteral("geometry" ), type: Qt3DRender::QShaderProgram::Geometry); |
622 | |
623 | // THEN |
624 | QVERIFY(spy.isValid()); |
625 | QCOMPARE(spy.count(), 1); |
626 | QCOMPARE(geometryShaderCode(), QByteArrayLiteral("geometry" )); |
627 | } |
628 | { |
629 | // WHEN |
630 | QSignalSpy spy(this, SIGNAL(computeShaderCodeChanged(QByteArray))); |
631 | dBuilder->setShaderCode(QByteArrayLiteral("compute" ), type: Qt3DRender::QShaderProgram::Compute); |
632 | |
633 | |
634 | // THEN |
635 | QVERIFY(spy.isValid()); |
636 | QCOMPARE(spy.count(), 1); |
637 | QCOMPARE(computeShaderCode(), QByteArrayLiteral("compute" )); |
638 | } |
639 | { |
640 | // WHEN |
641 | QSignalSpy spy(this, SIGNAL(tessellationControlShaderCodeChanged(QByteArray))); |
642 | dBuilder->setShaderCode(QByteArrayLiteral("control" ), type: Qt3DRender::QShaderProgram::TessellationControl); |
643 | |
644 | // THEN |
645 | QVERIFY(spy.isValid()); |
646 | QCOMPARE(spy.count(), 1); |
647 | QCOMPARE(tessellationControlShaderCode(), QByteArrayLiteral("control" )); |
648 | } |
649 | { |
650 | // WHEN |
651 | QSignalSpy spy(this, SIGNAL(tessellationEvaluationShaderCodeChanged(QByteArray))); |
652 | dBuilder->setShaderCode(QByteArrayLiteral("eval" ), type: Qt3DRender::QShaderProgram::TessellationEvaluation); |
653 | |
654 | // THEN |
655 | QVERIFY(spy.isValid()); |
656 | QCOMPARE(spy.count(), 1); |
657 | QCOMPARE(tessellationEvaluationShaderCode(), QByteArrayLiteral("eval" )); |
658 | } |
659 | } |
660 | |
661 | }; |
662 | |
663 | QTEST_MAIN(tst_QShaderProgramBuilder) |
664 | |
665 | #include "tst_qshaderprogrambuilder.moc" |
666 | |