1/****************************************************************************
2**
3** Copyright (C) 2016 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// TODO Remove in Qt6
30#include <QtCore/qcompilerdetection.h>
31QT_WARNING_DISABLE_DEPRECATED
32
33#include <QtTest/QTest>
34#include <qbackendnodetester.h>
35#include <qtextureimagedatagenerator.h>
36#include <Qt3DRender/qtexture.h>
37#include <Qt3DRender/qtextureimage.h>
38#include <Qt3DRender/qtexturedata.h>
39
40#include <renderer_p.h>
41#include <glresourcemanagers_p.h>
42#include <gltexture_p.h>
43#include <Qt3DRender/private/texture_p.h>
44#include <Qt3DRender/private/textureimage_p.h>
45#include <Qt3DRender/private/nodemanagers_p.h>
46#include <Qt3DRender/private/managers_p.h>
47#include <Qt3DRender/private/qtexture_p.h>
48
49#include <testrenderer.h>
50
51/**
52 * @brief Dummy QTextureImageDataGenerator
53 */
54class TestImageDataGenerator : public Qt3DRender::QTextureImageDataGenerator
55{
56 int m_id;
57public:
58 TestImageDataGenerator(int id) : m_id(id) {}
59
60 Qt3DRender::QTextureImageDataPtr operator ()() override {
61 return Qt3DRender::QTextureImageDataPtr::create();
62 }
63
64 bool operator ==(const Qt3DRender::QTextureImageDataGenerator &other) const override {
65 const TestImageDataGenerator *otherFunctor = Qt3DRender::functor_cast<TestImageDataGenerator>(other: &other);
66 return (otherFunctor != nullptr && otherFunctor->m_id == m_id);
67 }
68
69 QT3D_FUNCTOR(TestImageDataGenerator)
70};
71
72/**
73 * @brief Dummy QTextureGenerator
74 */
75class TestTextureGenerator : public Qt3DRender::QTextureGenerator
76{
77 int m_id;
78public:
79 TestTextureGenerator(int id) : m_id(id) {}
80
81 Qt3DRender::QTextureDataPtr operator ()() override {
82 return Qt3DRender::QTextureDataPtr::create();
83 }
84
85 bool operator ==(const Qt3DRender::QTextureGenerator &other) const override {
86 const TestTextureGenerator *otherFunctor = Qt3DRender::functor_cast<TestTextureGenerator>(other: &other);
87 return (otherFunctor != nullptr && otherFunctor->m_id == m_id);
88 }
89
90 QT3D_FUNCTOR(TestTextureGenerator)
91};
92
93typedef QSharedPointer<TestTextureGenerator> TestTextureGeneratorPtr;
94
95class TestTexturePrivate : public Qt3DRender::QAbstractTexturePrivate
96{
97public:
98 int genId;
99};
100
101/**
102 * @brief Test QTexture. Assign texture data functor if genId > 0.
103 */
104class TestTexture : public Qt3DRender::QAbstractTexture
105{
106public:
107 TestTexture(int genId, Qt3DCore::QNode *p = nullptr)
108 : QAbstractTexture(*new TestTexturePrivate(), p)
109 {
110 d_func()->genId = genId;
111 if (genId > 0)
112 d_func()->setDataFunctor(TestTextureGeneratorPtr::create(arguments&: genId));
113 }
114private:
115 Q_DECLARE_PRIVATE(TestTexture)
116};
117
118class TestSharedGLTexturePrivate : public Qt3DRender::QAbstractTexturePrivate
119{
120};
121
122class TestSharedGLTexture : public Qt3DRender::QAbstractTexture
123{
124public:
125 TestSharedGLTexture(int textureId, Qt3DCore::QNode *p = nullptr)
126 : QAbstractTexture(*new TestSharedGLTexturePrivate(), p)
127 {
128 d_func()->m_sharedTextureId = textureId;
129 }
130
131private:
132 Q_DECLARE_PRIVATE(TestSharedGLTexture)
133};
134
135
136/**
137 * @brief Test QTextureImage
138 */
139class TestTextureImage : public Qt3DRender::QAbstractTextureImage
140{
141public:
142 TestTextureImage(int genId, Qt3DCore::QNode *p = nullptr)
143 : QAbstractTextureImage(p)
144 , m_genId(genId)
145 {
146 }
147
148 void updateGenerator()
149 {
150 Qt3DRender::QAbstractTextureImage::notifyDataGeneratorChanged();
151 }
152
153 Qt3DRender::QTextureImageDataGeneratorPtr dataGenerator() const
154 {
155 return Qt3DRender::QTextureImageDataGeneratorPtr(new TestImageDataGenerator(m_genId));
156 }
157protected:
158 int m_genId;
159};
160
161class EmptyTextureImage : public Qt3DRender::QAbstractTextureImage
162{
163public:
164 EmptyTextureImage(Qt3DCore::QNode *p = nullptr)
165 : QAbstractTextureImage(p)
166 {
167 }
168
169 Qt3DRender::QTextureImageDataGeneratorPtr dataGenerator() const
170 {
171 return {};
172 }
173};
174
175class tst_RenderTextures : public Qt3DCore::QBackendNodeTester
176{
177 Q_OBJECT
178
179 Qt3DRender::QAbstractTexture *createQTexture(int genId,
180 const QVector<int> &imgGenIds,
181 bool genMipMaps)
182 {
183 TestTexture *tex = new TestTexture(genId);
184
185 for (int imgGen : imgGenIds)
186 tex->addTextureImage(textureImage: new TestTextureImage(imgGen));
187 tex->setGenerateMipMaps(genMipMaps);
188
189 return tex;
190 }
191
192 Qt3DRender::QAbstractTexture *createQTextureWithTextureId(int textureId)
193 {
194 return new TestSharedGLTexture(textureId);
195 }
196
197 Qt3DRender::Render::Texture *createBackendTexture(Qt3DRender::QAbstractTexture *frontend,
198 Qt3DRender::Render::TextureManager *texMgr,
199 Qt3DRender::Render::TextureImageManager *texImgMgr,
200 Qt3DRender::Render::AbstractRenderer *renderer)
201 {
202 Qt3DRender::Render::Texture *backend = texMgr->getOrCreateResource(id: frontend->id());
203 backend->setRenderer(renderer);
204 simulateInitializationSync(frontend, backend);
205
206 // create texture images
207 for (const auto texImgFrontend : frontend->textureImages()) {
208 // make sure TextureImageManager has backend node for this QTextureImage
209 if (!texImgMgr->contains(id: texImgFrontend->id())) {
210 Qt3DRender::Render::TextureImage *texImgBackend = texImgMgr->getOrCreateResource(id: texImgFrontend->id());
211 texImgBackend->setRenderer(renderer);
212 simulateInitializationSync(frontend: texImgFrontend, backend: texImgBackend);
213 }
214 }
215
216 return backend;
217 }
218
219private Q_SLOTS:
220
221 void shouldCreateSameGLTextures()
222 {
223 QSKIP("Texture Sharing is now disabled");
224 QScopedPointer<Qt3DRender::Render::NodeManagers> mgrs(new Qt3DRender::Render::NodeManagers());
225 Qt3DRender::Render::OpenGL::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous);
226 renderer.setNodeManagers(mgrs.data());
227
228 // GIVEN
229 Qt3DRender::QAbstractTexture *tex1a = createQTexture(genId: -1, imgGenIds: {1,2}, genMipMaps: true);
230 Qt3DRender::QAbstractTexture *tex1b = createQTexture(genId: -1, imgGenIds: {1,2}, genMipMaps: true);
231
232 // WHEN
233 Qt3DRender::Render::Texture *bt1a = createBackendTexture(frontend: tex1a,
234 texMgr: mgrs->textureManager(),
235 texImgMgr: mgrs->textureImageManager(),
236 renderer: &renderer);
237 Qt3DRender::Render::Texture *bt1b = createBackendTexture(frontend: tex1b,
238 texMgr: mgrs->textureManager(),
239 texImgMgr: mgrs->textureImageManager(),
240 renderer: &renderer);
241 renderer.updateTexture(texture: bt1a);
242 renderer.updateTexture(texture: bt1b);
243
244 // THEN
245 QCOMPARE(renderer.glResourceManagers()->glTextureManager()->lookupResource(bt1a->peerId()),
246 renderer.glResourceManagers()->glTextureManager()->lookupResource(bt1b->peerId()));
247 renderer.shutdown();
248 }
249
250 void shouldCreateDifferentGLTexturess()
251 {
252 QScopedPointer<Qt3DRender::Render::NodeManagers> mgrs(new Qt3DRender::Render::NodeManagers());
253 Qt3DRender::Render::OpenGL::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous);
254 renderer.setNodeManagers(mgrs.data());
255
256 // GIVEN
257 QVector<Qt3DRender::QAbstractTexture*> textures;
258 textures << createQTexture(genId: -1, imgGenIds: {1,2}, genMipMaps: true);
259 textures << createQTexture(genId: -1, imgGenIds: {1,2}, genMipMaps: false);
260 textures << createQTexture(genId: 1, imgGenIds: {1,2}, genMipMaps: true);
261 textures << createQTexture(genId: 1, imgGenIds: {1,2}, genMipMaps: false);
262 textures << createQTexture(genId: 1, imgGenIds: {1,2,3}, genMipMaps: true);
263 textures << createQTexture(genId: 1, imgGenIds: {1,2,3}, genMipMaps: false);
264
265 // WHEN
266 QVector<Qt3DRender::Render::Texture*> backend;
267 for (auto *t : textures) {
268 Qt3DRender::Render::Texture *backendTexture = createBackendTexture(frontend: t,
269 texMgr: mgrs->textureManager(),
270 texImgMgr: mgrs->textureImageManager(),
271 renderer: &renderer);
272 backend.push_back(t: backendTexture);
273 renderer.updateTexture(texture: backendTexture);
274 }
275
276 // THEN
277
278 // no 2 textures must be the same
279 for (int i = 0; i < backend.size(); i++)
280 for (int k = i+1; k < backend.size(); k++)
281 QVERIFY(renderer.glResourceManagers()->glTextureManager()->lookupResource(backend[i]->peerId()) !=
282 renderer.glResourceManagers()->glTextureManager()->lookupResource(backend[k]->peerId()));
283
284 QVector<Qt3DRender::Render::OpenGL::GLTexture *> glTextures;
285 for (Qt3DRender::Render::Texture *t : backend)
286 glTextures.push_back(t: renderer.glResourceManagers()->glTextureManager()->lookupResource(id: t->peerId()));
287
288 // some texture generators must be the same
289 QVERIFY(glTextures[0]->textureGenerator().data() == nullptr);
290 QVERIFY(glTextures[1]->textureGenerator().data() == nullptr);
291 QCOMPARE(*(glTextures[2]->textureGenerator()), *(glTextures[3]->textureGenerator()));
292
293 // some images must be the same
294 QCOMPARE(glTextures[0]->images(), glTextures[1]->images());
295 QCOMPARE(glTextures[0]->images(), glTextures[2]->images());
296 QCOMPARE(glTextures[0]->images(), glTextures[3]->images());
297 QCOMPARE(glTextures[4]->images(), glTextures[5]->images());
298
299 QCOMPARE(glTextures[0]->properties(), glTextures[2]->properties());
300 QCOMPARE(glTextures[1]->properties(), glTextures[3]->properties());
301 QVERIFY(glTextures[0]->properties() != glTextures[1]->properties());
302
303 renderer.shutdown();
304 }
305
306 void shouldCreateDifferentGLTexturesWhenUsingSharedTextureIds()
307 {
308 QScopedPointer<Qt3DRender::Render::NodeManagers> mgrs(new Qt3DRender::Render::NodeManagers());
309 Qt3DRender::Render::OpenGL::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous);
310 renderer.setNodeManagers(mgrs.data());
311
312 Qt3DRender::Render::OpenGL::GLResourceManagers *glMgrs = renderer.glResourceManagers();
313
314 // both texture having the same sharedTextureId
315 {
316 // GIVEN
317 Qt3DRender::QAbstractTexture *tex1a = createQTextureWithTextureId(textureId: 1);
318 Qt3DRender::QAbstractTexture *tex1b = createQTextureWithTextureId(textureId: 1);
319
320 // WHEN
321 Qt3DRender::Render::Texture *bt1 = createBackendTexture(frontend: tex1a,
322 texMgr: mgrs->textureManager(),
323 texImgMgr: mgrs->textureImageManager(),
324 renderer: &renderer);
325 Qt3DRender::Render::Texture *bt2 = createBackendTexture(frontend: tex1b,
326 texMgr: mgrs->textureManager(),
327 texImgMgr: mgrs->textureImageManager(),
328 renderer: &renderer);
329 // THEN
330 QCOMPARE(bt1->sharedTextureId(), 1);
331 QCOMPARE(bt2->sharedTextureId(), 1);
332
333 // WHEN
334 renderer.updateTexture(texture: bt1);
335 renderer.updateTexture(texture: bt2);
336
337 // THEN
338 Qt3DRender::Render::OpenGL::GLTexture *glt1 = glMgrs->glTextureManager()->lookupResource(id: bt1->peerId());
339 Qt3DRender::Render::OpenGL::GLTexture *glt2 = glMgrs->glTextureManager()->lookupResource(id: bt2->peerId());
340 QVERIFY(glt1 != glt2);
341 QCOMPARE(glt1->sharedTextureId(), bt1->sharedTextureId());
342 QCOMPARE(glt2->sharedTextureId(), bt2->sharedTextureId());
343 }
344
345 // textures having a different sharedTextureId
346 {
347 // GIVEN
348 Qt3DRender::QAbstractTexture *tex1a = createQTextureWithTextureId(textureId: 1);
349 Qt3DRender::QAbstractTexture *tex1b = createQTextureWithTextureId(textureId: 2);
350
351 // WHEN
352 Qt3DRender::Render::Texture *bt1 = createBackendTexture(frontend: tex1a,
353 texMgr: mgrs->textureManager(),
354 texImgMgr: mgrs->textureImageManager(),
355 renderer: &renderer);
356 Qt3DRender::Render::Texture *bt2 = createBackendTexture(frontend: tex1b,
357 texMgr: mgrs->textureManager(),
358 texImgMgr: mgrs->textureImageManager(),
359 renderer: &renderer);
360 // THEN
361 QCOMPARE(bt1->sharedTextureId(), 1);
362 QCOMPARE(bt2->sharedTextureId(), 2);
363
364 // WHEN
365 renderer.updateTexture(texture: bt1);
366 renderer.updateTexture(texture: bt2);
367
368 // THEN
369 Qt3DRender::Render::OpenGL::GLTexture *glt1 = glMgrs->glTextureManager()->lookupResource(id: bt1->peerId());
370 Qt3DRender::Render::OpenGL::GLTexture *glt2 = glMgrs->glTextureManager()->lookupResource(id: bt2->peerId());
371 QVERIFY(glt1 != glt2);
372 QCOMPARE(glt1->sharedTextureId(), bt1->sharedTextureId());
373 QCOMPARE(glt2->sharedTextureId(), bt2->sharedTextureId());
374 }
375
376 renderer.shutdown();
377 }
378
379 void generatorsShouldCreateSameData()
380 {
381 QScopedPointer<Qt3DRender::Render::NodeManagers> mgrs(new Qt3DRender::Render::NodeManagers());
382 Qt3DRender::Render::OpenGL::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous);
383 renderer.setNodeManagers(mgrs.data());
384
385 // GIVEN
386 QVector<Qt3DRender::QAbstractTexture*> textures;
387 textures << createQTexture(genId: 1, imgGenIds: {1}, genMipMaps: true);
388 textures << createQTexture(genId: 2, imgGenIds: {1,2}, genMipMaps: true);
389 textures << createQTexture(genId: 1, imgGenIds: {1,2}, genMipMaps: true);
390
391 // WHEN
392 QVector<Qt3DRender::Render::Texture*> backend;
393 for (auto *t : textures) {
394 Qt3DRender::Render::Texture *backendTexture = createBackendTexture(frontend: t,
395 texMgr: mgrs->textureManager(),
396 texImgMgr: mgrs->textureImageManager(),
397 renderer: &renderer);
398 backend.push_back(t: backendTexture);
399 renderer.updateTexture(texture: backendTexture);
400 }
401
402 Qt3DRender::QTextureImageDataGeneratorPtr idg1a = renderer.glResourceManagers()->glTextureManager()->lookupResource(id: backend[0]->peerId())->images()[0].generator;
403 Qt3DRender::QTextureImageDataGeneratorPtr idg1b = renderer.glResourceManagers()->glTextureManager()->lookupResource(id: backend[1]->peerId())->images()[0].generator;
404 Qt3DRender::QTextureImageDataGeneratorPtr idg2 = renderer.glResourceManagers()->glTextureManager()->lookupResource(id: backend[1]->peerId())->images()[1].generator;
405 Qt3DRender::QTextureGeneratorPtr tg1a = renderer.glResourceManagers()->glTextureManager()->lookupResource(id: backend[0]->peerId())->textureGenerator();
406 Qt3DRender::QTextureGeneratorPtr tg1b = renderer.glResourceManagers()->glTextureManager()->lookupResource(id: backend[2]->peerId())->textureGenerator();
407 Qt3DRender::QTextureGeneratorPtr tg2 = renderer.glResourceManagers()->glTextureManager()->lookupResource(id: backend[1]->peerId())->textureGenerator();
408
409 // THEN
410 QVERIFY(idg1a);
411 QVERIFY(idg1b);
412 QVERIFY(idg2);
413 QVERIFY(tg1a);
414 QVERIFY(tg1b);
415 QVERIFY(tg2);
416
417 QCOMPARE(*idg1a, *idg1b);
418 QVERIFY(!(*idg1a == *idg2));
419 QCOMPARE(*tg1a, *tg1b);
420 QVERIFY(!(*tg1a == *tg2));
421
422 renderer.shutdown();
423 }
424
425 void checkTextureImageInitialState()
426 {
427 // GIVEN
428 Qt3DRender::Render::TextureImage img;
429
430 // THEN
431 QCOMPARE(img.layer(), 0);
432 QCOMPARE(img.mipLevel(), 0);
433 QCOMPARE(img.isDirty(), false);
434 QCOMPARE(img.face(), Qt3DRender::QAbstractTexture::CubeMapPositiveX);
435 QVERIFY(img.dataGenerator().isNull());
436 }
437
438 void checkTextureImageCleanupState()
439 {
440 // GIVEN
441 Qt3DRender::Render::OpenGL::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous);
442 TestTextureImage img(1);
443 img.setLayer(2);
444 img.setMipLevel(3);
445
446 // WHEN
447 Qt3DRender::Render::TextureImage texImgBackend;
448 texImgBackend.setRenderer(&renderer);
449 simulateInitializationSync(frontend: &img, backend: &texImgBackend);
450 texImgBackend.cleanup();
451
452 // THEN
453 QCOMPARE(texImgBackend.isDirty(), false);
454 QCOMPARE(texImgBackend.layer(), 0);
455 QCOMPARE(texImgBackend.mipLevel(), 0);
456 QCOMPARE(texImgBackend.face(), Qt3DRender::QAbstractTexture::CubeMapPositiveX);
457 QVERIFY(texImgBackend.dataGenerator().isNull());
458
459 renderer.shutdown();
460 }
461
462 void checkTextureImageInitializeFromPeer()
463 {
464 // GIVEN
465 Qt3DRender::Render::OpenGL::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous);
466 TestTextureImage img(1);
467
468 {
469 // WHEN
470 img.setLayer(2);
471 img.setMipLevel(3);
472
473 Qt3DRender::Render::TextureImage texImgBackend;
474 texImgBackend.setRenderer(&renderer);
475 simulateInitializationSync(frontend: &img, backend: &texImgBackend);
476
477 // THEN
478 QCOMPARE(texImgBackend.isEnabled(), true);
479 QCOMPARE(texImgBackend.isDirty(), true);
480 QCOMPARE(texImgBackend.peerId(), img.id());
481 QCOMPARE(texImgBackend.layer(), 2);
482 QCOMPARE(texImgBackend.mipLevel(), 3);
483 QCOMPARE(texImgBackend.face(), Qt3DRender::QAbstractTexture::CubeMapPositiveX);
484 QVERIFY(!texImgBackend.dataGenerator().isNull());
485 }
486
487 {
488 // WHEN
489 img.setEnabled(false);
490
491 Qt3DRender::Render::TextureImage texImgBackend;
492 texImgBackend.setRenderer(&renderer);
493 simulateInitializationSync(frontend: &img, backend: &texImgBackend);
494
495 // THEN
496 QCOMPARE(texImgBackend.isEnabled(), false);
497 QCOMPARE(texImgBackend.peerId(), img.id());
498 }
499
500 renderer.shutdown();
501 }
502
503 void checkTextureImageSceneChangeEvents()
504 {
505 // GIVEN
506 Qt3DRender::Render::TextureImage backendImage;
507 TestTextureImage textureImage(1);
508 TestRenderer renderer;
509 backendImage.setRenderer(&renderer);
510 simulateInitializationSync(frontend: &textureImage, backend: &backendImage);
511
512 {
513 // WHEN
514 const bool newValue = false;
515 textureImage.setEnabled(newValue);
516 backendImage.syncFromFrontEnd(frontEnd: &textureImage, firstTime: false);
517
518 // THEN
519 QCOMPARE(backendImage.isEnabled(), newValue);
520 QVERIFY(backendImage.isDirty());
521 QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::AllDirty);
522 renderer.clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty);
523 backendImage.unsetDirty();
524 }
525
526 {
527 // WHEN
528 const int newValue = 7;
529 textureImage.setLayer(newValue);
530 backendImage.syncFromFrontEnd(frontEnd: &textureImage, firstTime: false);
531
532 // THEN
533 QCOMPARE(backendImage.layer(), newValue);
534 QVERIFY(backendImage.isDirty());
535 QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::AllDirty);
536 renderer.clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty);
537 backendImage.unsetDirty();
538 }
539
540 {
541 // WHEN
542 const int newValue = 3;
543 textureImage.setMipLevel(newValue);
544 backendImage.syncFromFrontEnd(frontEnd: &textureImage, firstTime: false);
545
546
547 // THEN
548 QCOMPARE(backendImage.mipLevel(), newValue);
549 QVERIFY(backendImage.isDirty());
550 QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::AllDirty);
551 renderer.clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty);
552 backendImage.unsetDirty();
553 }
554
555 {
556 // WHEN
557 const Qt3DRender::QAbstractTexture::CubeMapFace newValue = Qt3DRender::QAbstractTexture::CubeMapNegativeX;
558 textureImage.setFace(newValue);
559 backendImage.syncFromFrontEnd(frontEnd: &textureImage, firstTime: false);
560
561 // THEN
562 QCOMPARE(backendImage.face(), newValue);
563 QVERIFY(backendImage.isDirty());
564 QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::AllDirty);
565 renderer.clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty);
566 backendImage.unsetDirty();
567 }
568
569 {
570 // WHEN
571 textureImage.updateGenerator();
572 backendImage.syncFromFrontEnd(frontEnd: &textureImage, firstTime: false);
573
574 // THEN
575 QVERIFY(backendImage.isDirty());
576 QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::AllDirty);
577 renderer.clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty);
578 backendImage.unsetDirty();
579
580 // WHEN
581 textureImage.updateGenerator();
582 backendImage.syncFromFrontEnd(frontEnd: &textureImage, firstTime: false);
583
584 // THEN
585 QVERIFY(backendImage.isDirty());
586 QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::AllDirty);
587 renderer.clearDirtyBits(changes: Qt3DRender::Render::AbstractRenderer::AllDirty);
588 backendImage.unsetDirty();
589 }
590
591 renderer.shutdown();
592 }
593
594 void checkTextureImageProperlyReleaseGenerator()
595 {
596 QScopedPointer<Qt3DRender::Render::NodeManagers> mgrs(new Qt3DRender::Render::NodeManagers());
597 Qt3DRender::Render::OpenGL::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous);
598 Qt3DRender::Render::TextureManager *texMgr = mgrs->textureManager();
599 Qt3DRender::Render::TextureImageManager *texImgMgr = mgrs->textureImageManager();
600 renderer.setNodeManagers(mgrs.data());
601
602 // GIVEN
603 Qt3DRender::QAbstractTexture* frontendTexture = createQTexture(genId: 1, imgGenIds: {1}, genMipMaps: true);
604
605 Qt3DRender::Render::Texture *backendTexture = texMgr->getOrCreateResource(id: frontendTexture->id());
606 backendTexture->setRenderer(&renderer);
607 simulateInitializationSync(frontend: frontendTexture, backend: backendTexture);
608
609 // THEN
610 QCOMPARE(backendTexture->textureImageIds().size(), 1);
611 QCOMPARE(frontendTexture->textureImages().size(), 1);
612
613 // WHEN
614 TestTextureImage *texImgFrontend = static_cast<TestTextureImage *>(frontendTexture->textureImages().first());
615 const Qt3DRender::QTextureImageDataGeneratorPtr frontendGenerator = texImgFrontend->dataGenerator();
616
617 // THEN
618 QVERIFY(!frontendGenerator.isNull());
619
620 // WHEN
621 Qt3DRender::Render::TextureImage *texImgBackend = texImgMgr->getOrCreateResource(id: texImgFrontend->id());
622 texImgBackend->setRenderer(&renderer);
623 simulateInitializationSync(frontend: texImgFrontend, backend: texImgBackend);
624
625 // THEN
626 qDebug() << frontendGenerator << texImgBackend->dataGenerator();
627 const Qt3DRender::QTextureImageDataGeneratorPtr backendGenerator = texImgFrontend->dataGenerator();
628 QVERIFY(frontendGenerator != backendGenerator);
629 QVERIFY(*frontendGenerator == *backendGenerator);
630
631 renderer.shutdown();
632 }
633
634 void checkTextureIsMarkedForDeletion()
635 {
636 QScopedPointer<Qt3DRender::Render::NodeManagers> mgrs(new Qt3DRender::Render::NodeManagers());
637 Qt3DRender::Render::OpenGL::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous);
638 Qt3DRender::Render::TextureManager *texMgr = mgrs->textureManager();
639 renderer.setNodeManagers(mgrs.data());
640
641 Qt3DRender::Render::TextureFunctor textureBackendNodeMapper(&renderer,
642 texMgr);
643
644 // GIVEN
645 Qt3DRender::QAbstractTexture* frontendTexture = createQTexture(genId: 1, imgGenIds: {1}, genMipMaps: true);
646
647 Qt3DRender::Render::Texture *backendTexture = static_cast<Qt3DRender::Render::Texture *>(textureBackendNodeMapper.create(change: creationChange(frontend: frontendTexture)));
648 backendTexture->setRenderer(&renderer);
649 simulateInitializationSync(frontend: frontendTexture, backend: backendTexture);
650
651 // THEN
652 QVERIFY(backendTexture != nullptr);
653 QCOMPARE(texMgr->textureIdsToCleanup().size(), 0);
654
655 QCOMPARE(texMgr->lookupResource(frontendTexture->id()), backendTexture);
656
657 // WHEN
658 textureBackendNodeMapper.destroy(id: frontendTexture->id());
659
660 // THEN
661 QCOMPARE(texMgr->textureIdsToCleanup().size(), 1);
662 QCOMPARE(texMgr->textureIdsToCleanup().first(), frontendTexture->id());
663 QVERIFY(texMgr->lookupResource(frontendTexture->id()) == nullptr);
664
665 renderer.shutdown();
666 }
667
668 void checkTextureDestructionReconstructionWithinSameLoop()
669 {
670 QScopedPointer<Qt3DRender::Render::NodeManagers> mgrs(new Qt3DRender::Render::NodeManagers());
671 Qt3DRender::Render::OpenGL::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous);
672 Qt3DRender::Render::TextureManager *texMgr = mgrs->textureManager();
673 renderer.setNodeManagers(mgrs.data());
674
675 Qt3DRender::Render::TextureFunctor textureBackendNodeMapper(&renderer,
676 texMgr);
677
678 // GIVEN
679 Qt3DRender::QAbstractTexture* frontendTexture = createQTexture(genId: 1, imgGenIds: {1}, genMipMaps: true);
680
681 Qt3DRender::Render::Texture *backendTexture = static_cast<Qt3DRender::Render::Texture *>(textureBackendNodeMapper.create(change: creationChange(frontend: frontendTexture)));
682 backendTexture->setRenderer(&renderer);
683 simulateInitializationSync(frontend: frontendTexture, backend: backendTexture);
684
685 // WHEN
686 textureBackendNodeMapper.destroy(id: frontendTexture->id());
687
688 // THEN
689 QCOMPARE(texMgr->textureIdsToCleanup().size(), 1);
690 QCOMPARE(texMgr->textureIdsToCleanup().first(), frontendTexture->id());
691 QVERIFY(texMgr->lookupResource(frontendTexture->id()) == nullptr);
692
693 // WHEN
694 backendTexture = static_cast<Qt3DRender::Render::Texture *>(textureBackendNodeMapper.create(change: creationChange(frontend: frontendTexture)));
695 backendTexture->setRenderer(&renderer);
696 simulateInitializationSync(frontend: frontendTexture, backend: backendTexture);
697
698 // THEN
699 QVERIFY(backendTexture != nullptr);
700 QCOMPARE(texMgr->textureIdsToCleanup().size(), 0);
701 QCOMPARE(texMgr->lookupResource(frontendTexture->id()), backendTexture);
702
703 renderer.shutdown();
704 }
705
706 void checkTextureImageDirtinessPropagatesToTextures()
707 {
708 // GIVEN
709 QScopedPointer<Qt3DRender::Render::NodeManagers> mgrs(new Qt3DRender::Render::NodeManagers());
710 Qt3DRender::Render::OpenGL::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous);
711 Qt3DRender::Render::TextureManager *texMgr = mgrs->textureManager();
712 Qt3DRender::Render::TextureImageManager *texImgMgr = mgrs->textureImageManager();
713 renderer.setNodeManagers(mgrs.data());
714
715 Qt3DRender::QTexture2D *texture1 = new Qt3DRender::QTexture2D();
716 TestTextureImage *image1 = new TestTextureImage(1);
717
718 Qt3DRender::QTexture2D *texture2 = new Qt3DRender::QTexture2D();
719 TestTextureImage *image2 = new TestTextureImage(2);
720
721 Qt3DRender::QTexture2D *texture3 = new Qt3DRender::QTexture2D();
722
723 texture1->addTextureImage(textureImage: image1);
724 texture2->addTextureImage(textureImage: image2);
725 texture3->addTextureImage(textureImage: image1);
726 texture3->addTextureImage(textureImage: image2);
727
728 Qt3DRender::Render::Texture *backendTexture1 = texMgr->getOrCreateResource(id: texture1->id());
729 Qt3DRender::Render::Texture *backendTexture2 = texMgr->getOrCreateResource(id: texture2->id());
730 Qt3DRender::Render::Texture *backendTexture3 = texMgr->getOrCreateResource(id: texture3->id());
731 Qt3DRender::Render::TextureImage *backendImage1 = texImgMgr->getOrCreateResource(id: image1->id());
732 Qt3DRender::Render::TextureImage *backendImage2 = texImgMgr->getOrCreateResource(id: image2->id());
733
734 backendTexture1->setRenderer(&renderer);
735 backendTexture2->setRenderer(&renderer);
736 backendTexture3->setRenderer(&renderer);
737 backendImage1->setRenderer(&renderer);
738 backendImage2->setRenderer(&renderer);
739
740 simulateInitializationSync(frontend: texture1, backend: backendTexture1);
741 simulateInitializationSync(frontend: texture2, backend: backendTexture2);
742 simulateInitializationSync(frontend: texture3, backend: backendTexture3);
743 simulateInitializationSync(frontend: image1, backend: backendImage1);
744 simulateInitializationSync(frontend: image2, backend: backendImage2);
745
746 // THEN
747 QCOMPARE(backendTexture1->textureImageIds().size(), 1);
748 QCOMPARE(backendTexture1->textureImageIds().first(), image1->id());
749 QCOMPARE(backendTexture2->textureImageIds().size(), 1);
750 QCOMPARE(backendTexture2->textureImageIds().first(), image2->id());
751 QCOMPARE(backendTexture3->textureImageIds().size(), 2);
752 QCOMPARE(backendTexture3->textureImageIds().first(), image1->id());
753 QCOMPARE(backendTexture3->textureImageIds().last(), image2->id());
754
755 // WHEN
756 backendTexture1->unsetDirty();
757 backendTexture2->unsetDirty();
758 backendTexture3->unsetDirty();
759 backendImage1->unsetDirty();
760 backendImage2->unsetDirty();
761
762 // THEN
763 QVERIFY(backendTexture1->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty);
764 QVERIFY(backendTexture2->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty);
765 QVERIFY(backendTexture3->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty);
766
767 // WHEN
768 renderer.textureGathererJob()->run();
769
770 // THEN
771 QVERIFY(backendTexture1->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty);
772 QVERIFY(backendTexture2->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty);
773 QVERIFY(backendTexture3->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty);
774
775 // WHEN
776 // Make Image1 dirty
777 image1->updateGenerator();
778 backendImage1->syncFromFrontEnd(frontEnd: image1, firstTime: false);
779
780 // THEN
781 QVERIFY(backendImage1->isDirty());
782 QVERIFY(backendTexture1->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty);
783 QVERIFY(backendTexture2->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty);
784 QVERIFY(backendTexture3->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty);
785
786 // WHEN
787 renderer.textureGathererJob()->run();
788
789 // THEN
790 QVERIFY(backendTexture1->dirtyFlags() & Qt3DRender::Render::Texture::DirtyImageGenerators);
791 QVERIFY(backendTexture2->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty);
792 QVERIFY(backendTexture3->dirtyFlags() & Qt3DRender::Render::Texture::DirtyImageGenerators);
793
794 backendImage1->unsetDirty();
795 backendTexture1->unsetDirty();
796 backendTexture3->unsetDirty();
797
798 // WHEN
799 image2->updateGenerator();
800 backendImage2->syncFromFrontEnd(frontEnd: image2, firstTime: false);
801
802 // THEN
803 QVERIFY(backendImage2->isDirty());
804 QVERIFY(backendTexture1->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty);
805 QVERIFY(backendTexture2->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty);
806 QVERIFY(backendTexture3->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty);
807
808 // WHEN
809 renderer.textureGathererJob()->run();
810
811 QVERIFY(backendTexture1->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty);
812 QVERIFY(backendTexture2->dirtyFlags() & Qt3DRender::Render::Texture::DirtyImageGenerators);
813 QVERIFY(backendTexture3->dirtyFlags() & Qt3DRender::Render::Texture::DirtyImageGenerators);
814
815 renderer.shutdown();
816 }
817};
818
819QTEST_MAIN(tst_RenderTextures)
820
821#include "tst_textures.moc"
822

source code of qt3d/tests/auto/render/opengl/textures/tst_textures.cpp