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> |
31 | QT_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 | */ |
54 | class TestImageDataGenerator : public Qt3DRender::QTextureImageDataGenerator |
55 | { |
56 | int m_id; |
57 | public: |
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 | */ |
75 | class TestTextureGenerator : public Qt3DRender::QTextureGenerator |
76 | { |
77 | int m_id; |
78 | public: |
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 | |
93 | typedef QSharedPointer<TestTextureGenerator> TestTextureGeneratorPtr; |
94 | |
95 | class TestTexturePrivate : public Qt3DRender::QAbstractTexturePrivate |
96 | { |
97 | public: |
98 | int genId; |
99 | }; |
100 | |
101 | /** |
102 | * @brief Test QTexture. Assign texture data functor if genId > 0. |
103 | */ |
104 | class TestTexture : public Qt3DRender::QAbstractTexture |
105 | { |
106 | public: |
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 | } |
114 | private: |
115 | Q_DECLARE_PRIVATE(TestTexture) |
116 | }; |
117 | |
118 | class TestSharedGLTexturePrivate : public Qt3DRender::QAbstractTexturePrivate |
119 | { |
120 | }; |
121 | |
122 | class TestSharedGLTexture : public Qt3DRender::QAbstractTexture |
123 | { |
124 | public: |
125 | TestSharedGLTexture(int textureId, Qt3DCore::QNode *p = nullptr) |
126 | : QAbstractTexture(*new TestSharedGLTexturePrivate(), p) |
127 | { |
128 | d_func()->m_sharedTextureId = textureId; |
129 | } |
130 | |
131 | private: |
132 | Q_DECLARE_PRIVATE(TestSharedGLTexture) |
133 | }; |
134 | |
135 | |
136 | /** |
137 | * @brief Test QTextureImage |
138 | */ |
139 | class TestTextureImage : public Qt3DRender::QAbstractTextureImage |
140 | { |
141 | public: |
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 | } |
157 | protected: |
158 | int m_genId; |
159 | }; |
160 | |
161 | class EmptyTextureImage : public Qt3DRender::QAbstractTextureImage |
162 | { |
163 | public: |
164 | EmptyTextureImage(Qt3DCore::QNode *p = nullptr) |
165 | : QAbstractTextureImage(p) |
166 | { |
167 | } |
168 | |
169 | Qt3DRender::QTextureImageDataGeneratorPtr dataGenerator() const |
170 | { |
171 | return {}; |
172 | } |
173 | }; |
174 | |
175 | class 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 | |
219 | private 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 () |
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 | |
819 | QTEST_MAIN(tst_RenderTextures) |
820 | |
821 | #include "tst_textures.moc" |
822 | |