diff options
Diffstat (limited to 'tests/auto/render/opengl/textures/tst_textures.cpp')
-rw-r--r-- | tests/auto/render/opengl/textures/tst_textures.cpp | 821 |
1 files changed, 821 insertions, 0 deletions
diff --git a/tests/auto/render/opengl/textures/tst_textures.cpp b/tests/auto/render/opengl/textures/tst_textures.cpp new file mode 100644 index 000000000..5343a6fde --- /dev/null +++ b/tests/auto/render/opengl/textures/tst_textures.cpp @@ -0,0 +1,821 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// TODO Remove in Qt6 +#include <QtCore/qcompilerdetection.h> +QT_WARNING_DISABLE_DEPRECATED + +#include <QtTest/QTest> +#include <qbackendnodetester.h> +#include <qtextureimagedatagenerator.h> +#include <Qt3DRender/qtexture.h> +#include <Qt3DRender/qtextureimage.h> +#include <Qt3DRender/qtexturedata.h> + +#include <renderer_p.h> +#include <glresourcemanagers_p.h> +#include <gltexture_p.h> +#include <Qt3DRender/private/texture_p.h> +#include <Qt3DRender/private/textureimage_p.h> +#include <Qt3DRender/private/nodemanagers_p.h> +#include <Qt3DRender/private/managers_p.h> +#include <Qt3DRender/private/qtexture_p.h> + +#include <testrenderer.h> + +/** + * @brief Dummy QTextureImageDataGenerator + */ +class TestImageDataGenerator : public Qt3DRender::QTextureImageDataGenerator +{ + int m_id; +public: + TestImageDataGenerator(int id) : m_id(id) {} + + Qt3DRender::QTextureImageDataPtr operator ()() override { + return Qt3DRender::QTextureImageDataPtr::create(); + } + + bool operator ==(const Qt3DRender::QTextureImageDataGenerator &other) const override { + const TestImageDataGenerator *otherFunctor = Qt3DRender::functor_cast<TestImageDataGenerator>(&other); + return (otherFunctor != nullptr && otherFunctor->m_id == m_id); + } + + QT3D_FUNCTOR(TestImageDataGenerator) +}; + +/** + * @brief Dummy QTextureGenerator + */ +class TestTextureGenerator : public Qt3DRender::QTextureGenerator +{ + int m_id; +public: + TestTextureGenerator(int id) : m_id(id) {} + + Qt3DRender::QTextureDataPtr operator ()() override { + return Qt3DRender::QTextureDataPtr::create(); + } + + bool operator ==(const Qt3DRender::QTextureGenerator &other) const override { + const TestTextureGenerator *otherFunctor = Qt3DRender::functor_cast<TestTextureGenerator>(&other); + return (otherFunctor != nullptr && otherFunctor->m_id == m_id); + } + + QT3D_FUNCTOR(TestTextureGenerator) +}; + +typedef QSharedPointer<TestTextureGenerator> TestTextureGeneratorPtr; + +class TestTexturePrivate : public Qt3DRender::QAbstractTexturePrivate +{ +public: + int genId; +}; + +/** + * @brief Test QTexture. Assign texture data functor if genId > 0. + */ +class TestTexture : public Qt3DRender::QAbstractTexture +{ +public: + TestTexture(int genId, Qt3DCore::QNode *p = nullptr) + : QAbstractTexture(*new TestTexturePrivate(), p) + { + d_func()->genId = genId; + if (genId > 0) + d_func()->setDataFunctor(TestTextureGeneratorPtr::create(genId)); + } +private: + Q_DECLARE_PRIVATE(TestTexture) +}; + +class TestSharedGLTexturePrivate : public Qt3DRender::QAbstractTexturePrivate +{ +}; + +class TestSharedGLTexture : public Qt3DRender::QAbstractTexture +{ +public: + TestSharedGLTexture(int textureId, Qt3DCore::QNode *p = nullptr) + : QAbstractTexture(*new TestSharedGLTexturePrivate(), p) + { + d_func()->m_sharedTextureId = textureId; + } + +private: + Q_DECLARE_PRIVATE(TestSharedGLTexture) +}; + + +/** + * @brief Test QTextureImage + */ +class TestTextureImage : public Qt3DRender::QAbstractTextureImage +{ +public: + TestTextureImage(int genId, Qt3DCore::QNode *p = nullptr) + : QAbstractTextureImage(p) + , m_genId(genId) + { + } + + void updateGenerator() + { + Qt3DRender::QAbstractTextureImage::notifyDataGeneratorChanged(); + } + + Qt3DRender::QTextureImageDataGeneratorPtr dataGenerator() const + { + return Qt3DRender::QTextureImageDataGeneratorPtr(new TestImageDataGenerator(m_genId)); + } +protected: + int m_genId; +}; + +class EmptyTextureImage : public Qt3DRender::QAbstractTextureImage +{ +public: + EmptyTextureImage(Qt3DCore::QNode *p = nullptr) + : QAbstractTextureImage(p) + { + } + + Qt3DRender::QTextureImageDataGeneratorPtr dataGenerator() const + { + return {}; + } +}; + +class tst_RenderTextures : public Qt3DCore::QBackendNodeTester +{ + Q_OBJECT + + Qt3DRender::QAbstractTexture *createQTexture(int genId, + const QVector<int> &imgGenIds, + bool genMipMaps) + { + TestTexture *tex = new TestTexture(genId); + + for (int imgGen : imgGenIds) + tex->addTextureImage(new TestTextureImage(imgGen)); + tex->setGenerateMipMaps(genMipMaps); + + return tex; + } + + Qt3DRender::QAbstractTexture *createQTextureWithTextureId(int textureId) + { + return new TestSharedGLTexture(textureId); + } + + Qt3DRender::Render::Texture *createBackendTexture(Qt3DRender::QAbstractTexture *frontend, + Qt3DRender::Render::TextureManager *texMgr, + Qt3DRender::Render::TextureImageManager *texImgMgr, + Qt3DRender::Render::AbstractRenderer *renderer) + { + Qt3DRender::Render::Texture *backend = texMgr->getOrCreateResource(frontend->id()); + backend->setRenderer(renderer); + simulateInitializationSync(frontend, backend); + + // create texture images + for (const auto texImgFrontend : frontend->textureImages()) { + // make sure TextureImageManager has backend node for this QTextureImage + if (!texImgMgr->contains(texImgFrontend->id())) { + Qt3DRender::Render::TextureImage *texImgBackend = texImgMgr->getOrCreateResource(texImgFrontend->id()); + texImgBackend->setRenderer(renderer); + simulateInitializationSync(texImgFrontend, texImgBackend); + } + } + + return backend; + } + +private Q_SLOTS: + + void shouldCreateSameGLTextures() + { + QSKIP("Texture Sharing is now disabled"); + QScopedPointer<Qt3DRender::Render::NodeManagers> mgrs(new Qt3DRender::Render::NodeManagers()); + Qt3DRender::Render::OpenGL::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous); + renderer.setNodeManagers(mgrs.data()); + + // GIVEN + Qt3DRender::QAbstractTexture *tex1a = createQTexture(-1, {1,2}, true); + Qt3DRender::QAbstractTexture *tex1b = createQTexture(-1, {1,2}, true); + + // WHEN + Qt3DRender::Render::Texture *bt1a = createBackendTexture(tex1a, + mgrs->textureManager(), + mgrs->textureImageManager(), + &renderer); + Qt3DRender::Render::Texture *bt1b = createBackendTexture(tex1b, + mgrs->textureManager(), + mgrs->textureImageManager(), + &renderer); + renderer.updateTexture(bt1a); + renderer.updateTexture(bt1b); + + // THEN + QCOMPARE(renderer.glResourceManagers()->glTextureManager()->lookupResource(bt1a->peerId()), + renderer.glResourceManagers()->glTextureManager()->lookupResource(bt1b->peerId())); + renderer.shutdown(); + } + + void shouldCreateDifferentGLTexturess() + { + QScopedPointer<Qt3DRender::Render::NodeManagers> mgrs(new Qt3DRender::Render::NodeManagers()); + Qt3DRender::Render::OpenGL::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous); + renderer.setNodeManagers(mgrs.data()); + + // GIVEN + QVector<Qt3DRender::QAbstractTexture*> textures; + textures << createQTexture(-1, {1,2}, true); + textures << createQTexture(-1, {1,2}, false); + textures << createQTexture(1, {1,2}, true); + textures << createQTexture(1, {1,2}, false); + textures << createQTexture(1, {1,2,3}, true); + textures << createQTexture(1, {1,2,3}, false); + + // WHEN + QVector<Qt3DRender::Render::Texture*> backend; + for (auto *t : textures) { + Qt3DRender::Render::Texture *backendTexture = createBackendTexture(t, + mgrs->textureManager(), + mgrs->textureImageManager(), + &renderer); + backend.push_back(backendTexture); + renderer.updateTexture(backendTexture); + } + + // THEN + + // no 2 textures must be the same + for (int i = 0; i < backend.size(); i++) + for (int k = i+1; k < backend.size(); k++) + QVERIFY(renderer.glResourceManagers()->glTextureManager()->lookupResource(backend[i]->peerId()) != + renderer.glResourceManagers()->glTextureManager()->lookupResource(backend[k]->peerId())); + + QVector<Qt3DRender::Render::OpenGL::GLTexture *> glTextures; + for (Qt3DRender::Render::Texture *t : backend) + glTextures.push_back(renderer.glResourceManagers()->glTextureManager()->lookupResource(t->peerId())); + + // some texture generators must be the same + QVERIFY(glTextures[0]->textureGenerator().data() == nullptr); + QVERIFY(glTextures[1]->textureGenerator().data() == nullptr); + QCOMPARE(*(glTextures[2]->textureGenerator()), *(glTextures[3]->textureGenerator())); + + // some images must be the same + QCOMPARE(glTextures[0]->images(), glTextures[1]->images()); + QCOMPARE(glTextures[0]->images(), glTextures[2]->images()); + QCOMPARE(glTextures[0]->images(), glTextures[3]->images()); + QCOMPARE(glTextures[4]->images(), glTextures[5]->images()); + + QCOMPARE(glTextures[0]->properties(), glTextures[2]->properties()); + QCOMPARE(glTextures[1]->properties(), glTextures[3]->properties()); + QVERIFY(glTextures[0]->properties() != glTextures[1]->properties()); + + renderer.shutdown(); + } + + void shouldCreateDifferentGLTexturesWhenUsingSharedTextureIds() + { + QScopedPointer<Qt3DRender::Render::NodeManagers> mgrs(new Qt3DRender::Render::NodeManagers()); + Qt3DRender::Render::OpenGL::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous); + renderer.setNodeManagers(mgrs.data()); + + Qt3DRender::Render::OpenGL::GLResourceManagers *glMgrs = renderer.glResourceManagers(); + + // both texture having the same sharedTextureId + { + // GIVEN + Qt3DRender::QAbstractTexture *tex1a = createQTextureWithTextureId(1); + Qt3DRender::QAbstractTexture *tex1b = createQTextureWithTextureId(1); + + // WHEN + Qt3DRender::Render::Texture *bt1 = createBackendTexture(tex1a, + mgrs->textureManager(), + mgrs->textureImageManager(), + &renderer); + Qt3DRender::Render::Texture *bt2 = createBackendTexture(tex1b, + mgrs->textureManager(), + mgrs->textureImageManager(), + &renderer); + // THEN + QCOMPARE(bt1->sharedTextureId(), 1); + QCOMPARE(bt2->sharedTextureId(), 1); + + // WHEN + renderer.updateTexture(bt1); + renderer.updateTexture(bt2); + + // THEN + Qt3DRender::Render::OpenGL::GLTexture *glt1 = glMgrs->glTextureManager()->lookupResource(bt1->peerId()); + Qt3DRender::Render::OpenGL::GLTexture *glt2 = glMgrs->glTextureManager()->lookupResource(bt2->peerId()); + QVERIFY(glt1 != glt2); + QCOMPARE(glt1->sharedTextureId(), bt1->sharedTextureId()); + QCOMPARE(glt2->sharedTextureId(), bt2->sharedTextureId()); + } + + // textures having a different sharedTextureId + { + // GIVEN + Qt3DRender::QAbstractTexture *tex1a = createQTextureWithTextureId(1); + Qt3DRender::QAbstractTexture *tex1b = createQTextureWithTextureId(2); + + // WHEN + Qt3DRender::Render::Texture *bt1 = createBackendTexture(tex1a, + mgrs->textureManager(), + mgrs->textureImageManager(), + &renderer); + Qt3DRender::Render::Texture *bt2 = createBackendTexture(tex1b, + mgrs->textureManager(), + mgrs->textureImageManager(), + &renderer); + // THEN + QCOMPARE(bt1->sharedTextureId(), 1); + QCOMPARE(bt2->sharedTextureId(), 2); + + // WHEN + renderer.updateTexture(bt1); + renderer.updateTexture(bt2); + + // THEN + Qt3DRender::Render::OpenGL::GLTexture *glt1 = glMgrs->glTextureManager()->lookupResource(bt1->peerId()); + Qt3DRender::Render::OpenGL::GLTexture *glt2 = glMgrs->glTextureManager()->lookupResource(bt2->peerId()); + QVERIFY(glt1 != glt2); + QCOMPARE(glt1->sharedTextureId(), bt1->sharedTextureId()); + QCOMPARE(glt2->sharedTextureId(), bt2->sharedTextureId()); + } + + renderer.shutdown(); + } + + void generatorsShouldCreateSameData() + { + QScopedPointer<Qt3DRender::Render::NodeManagers> mgrs(new Qt3DRender::Render::NodeManagers()); + Qt3DRender::Render::OpenGL::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous); + renderer.setNodeManagers(mgrs.data()); + + // GIVEN + QVector<Qt3DRender::QAbstractTexture*> textures; + textures << createQTexture(1, {1}, true); + textures << createQTexture(2, {1,2}, true); + textures << createQTexture(1, {1,2}, true); + + // WHEN + QVector<Qt3DRender::Render::Texture*> backend; + for (auto *t : textures) { + Qt3DRender::Render::Texture *backendTexture = createBackendTexture(t, + mgrs->textureManager(), + mgrs->textureImageManager(), + &renderer); + backend.push_back(backendTexture); + renderer.updateTexture(backendTexture); + } + + Qt3DRender::QTextureImageDataGeneratorPtr idg1a = renderer.glResourceManagers()->glTextureManager()->lookupResource(backend[0]->peerId())->images()[0].generator; + Qt3DRender::QTextureImageDataGeneratorPtr idg1b = renderer.glResourceManagers()->glTextureManager()->lookupResource(backend[1]->peerId())->images()[0].generator; + Qt3DRender::QTextureImageDataGeneratorPtr idg2 = renderer.glResourceManagers()->glTextureManager()->lookupResource(backend[1]->peerId())->images()[1].generator; + Qt3DRender::QTextureGeneratorPtr tg1a = renderer.glResourceManagers()->glTextureManager()->lookupResource(backend[0]->peerId())->textureGenerator(); + Qt3DRender::QTextureGeneratorPtr tg1b = renderer.glResourceManagers()->glTextureManager()->lookupResource(backend[2]->peerId())->textureGenerator(); + Qt3DRender::QTextureGeneratorPtr tg2 = renderer.glResourceManagers()->glTextureManager()->lookupResource(backend[1]->peerId())->textureGenerator(); + + // THEN + QVERIFY(idg1a); + QVERIFY(idg1b); + QVERIFY(idg2); + QVERIFY(tg1a); + QVERIFY(tg1b); + QVERIFY(tg2); + + QCOMPARE(*idg1a, *idg1b); + QVERIFY(!(*idg1a == *idg2)); + QCOMPARE(*tg1a, *tg1b); + QVERIFY(!(*tg1a == *tg2)); + + renderer.shutdown(); + } + + void checkTextureImageInitialState() + { + // GIVEN + Qt3DRender::Render::TextureImage img; + + // THEN + QCOMPARE(img.layer(), 0); + QCOMPARE(img.mipLevel(), 0); + QCOMPARE(img.isDirty(), false); + QCOMPARE(img.face(), Qt3DRender::QAbstractTexture::CubeMapPositiveX); + QVERIFY(img.dataGenerator().isNull()); + } + + void checkTextureImageCleanupState() + { + // GIVEN + Qt3DRender::Render::OpenGL::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous); + TestTextureImage img(1); + img.setLayer(2); + img.setMipLevel(3); + + // WHEN + Qt3DRender::Render::TextureImage texImgBackend; + texImgBackend.setRenderer(&renderer); + simulateInitializationSync(&img, &texImgBackend); + texImgBackend.cleanup(); + + // THEN + QCOMPARE(texImgBackend.isDirty(), false); + QCOMPARE(texImgBackend.layer(), 0); + QCOMPARE(texImgBackend.mipLevel(), 0); + QCOMPARE(texImgBackend.face(), Qt3DRender::QAbstractTexture::CubeMapPositiveX); + QVERIFY(texImgBackend.dataGenerator().isNull()); + + renderer.shutdown(); + } + + void checkTextureImageInitializeFromPeer() + { + // GIVEN + Qt3DRender::Render::OpenGL::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous); + TestTextureImage img(1); + + { + // WHEN + img.setLayer(2); + img.setMipLevel(3); + + Qt3DRender::Render::TextureImage texImgBackend; + texImgBackend.setRenderer(&renderer); + simulateInitializationSync(&img, &texImgBackend); + + // THEN + QCOMPARE(texImgBackend.isEnabled(), true); + QCOMPARE(texImgBackend.isDirty(), true); + QCOMPARE(texImgBackend.peerId(), img.id()); + QCOMPARE(texImgBackend.layer(), 2); + QCOMPARE(texImgBackend.mipLevel(), 3); + QCOMPARE(texImgBackend.face(), Qt3DRender::QAbstractTexture::CubeMapPositiveX); + QVERIFY(!texImgBackend.dataGenerator().isNull()); + } + + { + // WHEN + img.setEnabled(false); + + Qt3DRender::Render::TextureImage texImgBackend; + texImgBackend.setRenderer(&renderer); + simulateInitializationSync(&img, &texImgBackend); + + // THEN + QCOMPARE(texImgBackend.isEnabled(), false); + QCOMPARE(texImgBackend.peerId(), img.id()); + } + + renderer.shutdown(); + } + + void checkTextureImageSceneChangeEvents() + { + // GIVEN + Qt3DRender::Render::TextureImage backendImage; + TestTextureImage textureImage(1); + TestRenderer renderer; + backendImage.setRenderer(&renderer); + simulateInitializationSync(&textureImage, &backendImage); + + { + // WHEN + const bool newValue = false; + textureImage.setEnabled(newValue); + backendImage.syncFromFrontEnd(&textureImage, false); + + // THEN + QCOMPARE(backendImage.isEnabled(), newValue); + QVERIFY(backendImage.isDirty()); + QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::AllDirty); + renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); + backendImage.unsetDirty(); + } + + { + // WHEN + const int newValue = 7; + textureImage.setLayer(newValue); + backendImage.syncFromFrontEnd(&textureImage, false); + + // THEN + QCOMPARE(backendImage.layer(), newValue); + QVERIFY(backendImage.isDirty()); + QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::AllDirty); + renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); + backendImage.unsetDirty(); + } + + { + // WHEN + const int newValue = 3; + textureImage.setMipLevel(newValue); + backendImage.syncFromFrontEnd(&textureImage, false); + + + // THEN + QCOMPARE(backendImage.mipLevel(), newValue); + QVERIFY(backendImage.isDirty()); + QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::AllDirty); + renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); + backendImage.unsetDirty(); + } + + { + // WHEN + const Qt3DRender::QAbstractTexture::CubeMapFace newValue = Qt3DRender::QAbstractTexture::CubeMapNegativeX; + textureImage.setFace(newValue); + backendImage.syncFromFrontEnd(&textureImage, false); + + // THEN + QCOMPARE(backendImage.face(), newValue); + QVERIFY(backendImage.isDirty()); + QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::AllDirty); + renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); + backendImage.unsetDirty(); + } + + { + // WHEN + textureImage.updateGenerator(); + backendImage.syncFromFrontEnd(&textureImage, false); + + // THEN + QVERIFY(backendImage.isDirty()); + QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::AllDirty); + renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); + backendImage.unsetDirty(); + + // WHEN + textureImage.updateGenerator(); + backendImage.syncFromFrontEnd(&textureImage, false); + + // THEN + QVERIFY(backendImage.isDirty()); + QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::AllDirty); + renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); + backendImage.unsetDirty(); + } + + renderer.shutdown(); + } + + void checkTextureImageProperlyReleaseGenerator() + { + QScopedPointer<Qt3DRender::Render::NodeManagers> mgrs(new Qt3DRender::Render::NodeManagers()); + Qt3DRender::Render::OpenGL::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous); + Qt3DRender::Render::TextureManager *texMgr = mgrs->textureManager(); + Qt3DRender::Render::TextureImageManager *texImgMgr = mgrs->textureImageManager(); + renderer.setNodeManagers(mgrs.data()); + + // GIVEN + Qt3DRender::QAbstractTexture* frontendTexture = createQTexture(1, {1}, true); + + Qt3DRender::Render::Texture *backendTexture = texMgr->getOrCreateResource(frontendTexture->id()); + backendTexture->setRenderer(&renderer); + simulateInitializationSync(frontendTexture, backendTexture); + + // THEN + QCOMPARE(backendTexture->textureImageIds().size(), 1); + QCOMPARE(frontendTexture->textureImages().size(), 1); + + // WHEN + TestTextureImage *texImgFrontend = static_cast<TestTextureImage *>(frontendTexture->textureImages().first()); + const Qt3DRender::QTextureImageDataGeneratorPtr frontendGenerator = texImgFrontend->dataGenerator(); + + // THEN + QVERIFY(!frontendGenerator.isNull()); + + // WHEN + Qt3DRender::Render::TextureImage *texImgBackend = texImgMgr->getOrCreateResource(texImgFrontend->id()); + texImgBackend->setRenderer(&renderer); + simulateInitializationSync(texImgFrontend, texImgBackend); + + // THEN + qDebug() << frontendGenerator << texImgBackend->dataGenerator(); + const Qt3DRender::QTextureImageDataGeneratorPtr backendGenerator = texImgFrontend->dataGenerator(); + QVERIFY(frontendGenerator != backendGenerator); + QVERIFY(*frontendGenerator == *backendGenerator); + + renderer.shutdown(); + } + + void checkTextureIsMarkedForDeletion() + { + QScopedPointer<Qt3DRender::Render::NodeManagers> mgrs(new Qt3DRender::Render::NodeManagers()); + Qt3DRender::Render::OpenGL::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous); + Qt3DRender::Render::TextureManager *texMgr = mgrs->textureManager(); + renderer.setNodeManagers(mgrs.data()); + + Qt3DRender::Render::TextureFunctor textureBackendNodeMapper(&renderer, + texMgr); + + // GIVEN + Qt3DRender::QAbstractTexture* frontendTexture = createQTexture(1, {1}, true); + + Qt3DRender::Render::Texture *backendTexture = static_cast<Qt3DRender::Render::Texture *>(textureBackendNodeMapper.create(creationChange(frontendTexture))); + backendTexture->setRenderer(&renderer); + simulateInitializationSync(frontendTexture, backendTexture); + + // THEN + QVERIFY(backendTexture != nullptr); + QCOMPARE(texMgr->textureIdsToCleanup().size(), 0); + + QCOMPARE(texMgr->lookupResource(frontendTexture->id()), backendTexture); + + // WHEN + textureBackendNodeMapper.destroy(frontendTexture->id()); + + // THEN + QCOMPARE(texMgr->textureIdsToCleanup().size(), 1); + QCOMPARE(texMgr->textureIdsToCleanup().first(), frontendTexture->id()); + QVERIFY(texMgr->lookupResource(frontendTexture->id()) == nullptr); + + renderer.shutdown(); + } + + void checkTextureDestructionReconstructionWithinSameLoop() + { + QScopedPointer<Qt3DRender::Render::NodeManagers> mgrs(new Qt3DRender::Render::NodeManagers()); + Qt3DRender::Render::OpenGL::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous); + Qt3DRender::Render::TextureManager *texMgr = mgrs->textureManager(); + renderer.setNodeManagers(mgrs.data()); + + Qt3DRender::Render::TextureFunctor textureBackendNodeMapper(&renderer, + texMgr); + + // GIVEN + Qt3DRender::QAbstractTexture* frontendTexture = createQTexture(1, {1}, true); + + Qt3DRender::Render::Texture *backendTexture = static_cast<Qt3DRender::Render::Texture *>(textureBackendNodeMapper.create(creationChange(frontendTexture))); + backendTexture->setRenderer(&renderer); + simulateInitializationSync(frontendTexture, backendTexture); + + // WHEN + textureBackendNodeMapper.destroy(frontendTexture->id()); + + // THEN + QCOMPARE(texMgr->textureIdsToCleanup().size(), 1); + QCOMPARE(texMgr->textureIdsToCleanup().first(), frontendTexture->id()); + QVERIFY(texMgr->lookupResource(frontendTexture->id()) == nullptr); + + // WHEN + backendTexture = static_cast<Qt3DRender::Render::Texture *>(textureBackendNodeMapper.create(creationChange(frontendTexture))); + backendTexture->setRenderer(&renderer); + simulateInitializationSync(frontendTexture, backendTexture); + + // THEN + QVERIFY(backendTexture != nullptr); + QCOMPARE(texMgr->textureIdsToCleanup().size(), 0); + QCOMPARE(texMgr->lookupResource(frontendTexture->id()), backendTexture); + + renderer.shutdown(); + } + + void checkTextureImageDirtinessPropagatesToTextures() + { + // GIVEN + QScopedPointer<Qt3DRender::Render::NodeManagers> mgrs(new Qt3DRender::Render::NodeManagers()); + Qt3DRender::Render::OpenGL::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous); + Qt3DRender::Render::TextureManager *texMgr = mgrs->textureManager(); + Qt3DRender::Render::TextureImageManager *texImgMgr = mgrs->textureImageManager(); + renderer.setNodeManagers(mgrs.data()); + + Qt3DRender::QTexture2D *texture1 = new Qt3DRender::QTexture2D(); + TestTextureImage *image1 = new TestTextureImage(1); + + Qt3DRender::QTexture2D *texture2 = new Qt3DRender::QTexture2D(); + TestTextureImage *image2 = new TestTextureImage(2); + + Qt3DRender::QTexture2D *texture3 = new Qt3DRender::QTexture2D(); + + texture1->addTextureImage(image1); + texture2->addTextureImage(image2); + texture3->addTextureImage(image1); + texture3->addTextureImage(image2); + + Qt3DRender::Render::Texture *backendTexture1 = texMgr->getOrCreateResource(texture1->id()); + Qt3DRender::Render::Texture *backendTexture2 = texMgr->getOrCreateResource(texture2->id()); + Qt3DRender::Render::Texture *backendTexture3 = texMgr->getOrCreateResource(texture3->id()); + Qt3DRender::Render::TextureImage *backendImage1 = texImgMgr->getOrCreateResource(image1->id()); + Qt3DRender::Render::TextureImage *backendImage2 = texImgMgr->getOrCreateResource(image2->id()); + + backendTexture1->setRenderer(&renderer); + backendTexture2->setRenderer(&renderer); + backendTexture3->setRenderer(&renderer); + backendImage1->setRenderer(&renderer); + backendImage2->setRenderer(&renderer); + + simulateInitializationSync(texture1, backendTexture1); + simulateInitializationSync(texture2, backendTexture2); + simulateInitializationSync(texture3, backendTexture3); + simulateInitializationSync(image1, backendImage1); + simulateInitializationSync(image2, backendImage2); + + // THEN + QCOMPARE(backendTexture1->textureImageIds().size(), 1); + QCOMPARE(backendTexture1->textureImageIds().first(), image1->id()); + QCOMPARE(backendTexture2->textureImageIds().size(), 1); + QCOMPARE(backendTexture2->textureImageIds().first(), image2->id()); + QCOMPARE(backendTexture3->textureImageIds().size(), 2); + QCOMPARE(backendTexture3->textureImageIds().first(), image1->id()); + QCOMPARE(backendTexture3->textureImageIds().last(), image2->id()); + + // WHEN + backendTexture1->unsetDirty(); + backendTexture2->unsetDirty(); + backendTexture3->unsetDirty(); + backendImage1->unsetDirty(); + backendImage2->unsetDirty(); + + // THEN + QVERIFY(backendTexture1->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty); + QVERIFY(backendTexture2->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty); + QVERIFY(backendTexture3->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty); + + // WHEN + renderer.textureGathererJob()->run(); + + // THEN + QVERIFY(backendTexture1->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty); + QVERIFY(backendTexture2->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty); + QVERIFY(backendTexture3->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty); + + // WHEN + // Make Image1 dirty + image1->updateGenerator(); + backendImage1->syncFromFrontEnd(image1, false); + + // THEN + QVERIFY(backendImage1->isDirty()); + QVERIFY(backendTexture1->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty); + QVERIFY(backendTexture2->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty); + QVERIFY(backendTexture3->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty); + + // WHEN + renderer.textureGathererJob()->run(); + + // THEN + QVERIFY(backendTexture1->dirtyFlags() & Qt3DRender::Render::Texture::DirtyImageGenerators); + QVERIFY(backendTexture2->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty); + QVERIFY(backendTexture3->dirtyFlags() & Qt3DRender::Render::Texture::DirtyImageGenerators); + + backendImage1->unsetDirty(); + backendTexture1->unsetDirty(); + backendTexture3->unsetDirty(); + + // WHEN + image2->updateGenerator(); + backendImage2->syncFromFrontEnd(image2, false); + + // THEN + QVERIFY(backendImage2->isDirty()); + QVERIFY(backendTexture1->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty); + QVERIFY(backendTexture2->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty); + QVERIFY(backendTexture3->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty); + + // WHEN + renderer.textureGathererJob()->run(); + + QVERIFY(backendTexture1->dirtyFlags() == Qt3DRender::Render::Texture::NotDirty); + QVERIFY(backendTexture2->dirtyFlags() & Qt3DRender::Render::Texture::DirtyImageGenerators); + QVERIFY(backendTexture3->dirtyFlags() & Qt3DRender::Render::Texture::DirtyImageGenerators); + + renderer.shutdown(); + } +}; + +QTEST_MAIN(tst_RenderTextures) + +#include "tst_textures.moc" |