diff options
-rw-r--r-- | src/render/backend/renderer.cpp | 10 | ||||
-rw-r--r-- | src/render/frontend/qrenderaspect.cpp | 5 | ||||
-rw-r--r-- | src/render/graphicshelpers/graphicscontext.cpp | 7 | ||||
-rw-r--r-- | src/render/texture/gltexture.cpp | 91 | ||||
-rw-r--r-- | src/render/texture/gltexture_p.h | 2 | ||||
-rw-r--r-- | src/render/texture/texturedatamanager_p.h | 35 | ||||
-rw-r--r-- | src/render/texture/textureimage.cpp | 29 | ||||
-rw-r--r-- | src/render/texture/textureimage_p.h | 13 | ||||
-rw-r--r-- | tests/auto/render/texturedatamanager/tst_texturedatamanager.cpp | 2 | ||||
-rw-r--r-- | tests/auto/render/textures/textures.pro | 1 | ||||
-rw-r--r-- | tests/auto/render/textures/tst_textures.cpp | 289 |
11 files changed, 372 insertions, 112 deletions
diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index 2dda73679..bdc024308 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -1221,10 +1221,12 @@ void Renderer::updateTexture(Texture *texture) !glTextureManager->setParameters(glTexture, texture->parameters())) qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setParameters failed, should be non-shared"; + // Will make the texture requestUpload if (dirtyFlags.testFlag(Texture::DirtyImageGenerators) && !glTextureManager->setImages(glTexture, texture->textureImages())) qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setGenerators failed, should be non-shared"; + // Will make the texture requestUpload if (dirtyFlags.testFlag(Texture::DirtyDataGenerator) && !glTextureManager->setGenerator(glTexture, texture->dataGenerator())) qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setGenerator failed, should be non-shared"; @@ -1379,7 +1381,7 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren if (!executeCommandsSubmission(renderView)) m_lastFrameCorrect.store(0); // something went wrong; make sure to render the next frame! - // executeCommands takes care of restoring the stateset to the value + // executeCommandsSubmission takes care of restoring the stateset to the value // of gc->currentContext() at the moment it was called (either // renderViewStateSet or m_defaultRenderStateSet) if (!renderView->renderCaptureNodeId().isNull()) { @@ -1836,8 +1838,12 @@ bool Renderer::executeCommandsSubmission(const RenderView *rv) { Profiling::GLTimeRecorder recorder(Profiling::UniformUpdate); //// Update program uniforms - if (!m_graphicsContext->setParameters(command->m_parameterPack)) + if (!m_graphicsContext->setParameters(command->m_parameterPack)) { allCommandsIssued = false; + // If we have failed to set uniform (e.g unable to bind a texture) + // we won't perform the draw call which could show invalid content + continue; + } } //// OpenGL State diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp index e5cce4c7b..1314a7c36 100644 --- a/src/render/frontend/qrenderaspect.cpp +++ b/src/render/frontend/qrenderaspect.cpp @@ -254,7 +254,10 @@ void QRenderAspectPrivate::registerBackendTypes() // Textures q->registerBackendType<QAbstractTexture>(QSharedPointer<Render::TextureFunctor>::create(m_renderer, m_nodeManagers->textureManager(), m_nodeManagers->textureImageManager())); - q->registerBackendType<QAbstractTextureImage>(QSharedPointer<Render::TextureImageFunctor>::create(m_renderer, m_nodeManagers->textureManager(), m_nodeManagers->textureImageManager())); + q->registerBackendType<QAbstractTextureImage>(QSharedPointer<Render::TextureImageFunctor>::create(m_renderer, + m_nodeManagers->textureManager(), + m_nodeManagers->textureImageManager(), + m_nodeManagers->textureImageDataManager())); // Material system q->registerBackendType<QEffect>(QSharedPointer<Render::NodeFunctor<Render::Effect, Render::EffectManager> >::create(m_renderer)); diff --git a/src/render/graphicshelpers/graphicscontext.cpp b/src/render/graphicshelpers/graphicscontext.cpp index d742865c4..7fa112b12 100644 --- a/src/render/graphicshelpers/graphicscontext.cpp +++ b/src/render/graphicshelpers/graphicscontext.cpp @@ -1205,7 +1205,6 @@ bool GraphicsContext::setParameters(ShaderParameterPack ¶meterPack) { // Activate textures and update TextureUniform in the pack // with the correct textureUnit - bool allValid = true; // Set the pinned texture of the previous material texture // to pinable so that we should easily find an available texture unit @@ -1225,10 +1224,8 @@ bool GraphicsContext::setParameters(ShaderParameterPack ¶meterPack) Q_ASSERT(texUniform.valueType() == UniformValue::TextureValue); const int texUnit = activateTexture(TextureScopeMaterial, t); texUniform.data<int>()[namedTex.uniformArrayIndex] = texUnit; - // if the texture data from generators may not be available yet, - // make sure that the next frame is rendered if (texUnit == -1) - allValid = false; + return false; } } } @@ -1283,7 +1280,7 @@ bool GraphicsContext::setParameters(ShaderParameterPack ¶meterPack) applyUniform(uniform, v); } // if not all data is valid, the next frame will be rendered immediately - return allValid; + return true; } void GraphicsContext::readBuffer(GLenum mode) diff --git a/src/render/texture/gltexture.cpp b/src/render/texture/gltexture.cpp index 2fd61f3db..e94122f67 100644 --- a/src/render/texture/gltexture.cpp +++ b/src/render/texture/gltexture.cpp @@ -87,10 +87,6 @@ GLTexture::~GLTexture() void GLTexture::destroyResources() { - // release texture data - for (const Image &img : qAsConst(m_images)) - m_textureImageDataManager->releaseData(img.generator, this); - if (m_dataFunctor) m_textureDataManager->releaseData(m_dataFunctor, this); } @@ -111,7 +107,6 @@ QOpenGLTexture* GLTexture::getOrCreateGLTexture() { QMutexLocker locker(&m_textureMutex); bool needUpload = false; - bool texturedDataInvalid = false; // on the first invocation in the render thread, make sure to // evaluate the texture data generator output @@ -156,31 +151,23 @@ QOpenGLTexture* GLTexture::getOrCreateGLTexture() for (const Image &img : qAsConst(m_images)) { const QTextureImageDataPtr imgData = m_textureImageDataManager->getData(img.generator); - if (imgData) { - m_imageData << imgData; - - maxMipLevel = qMax(maxMipLevel, img.mipLevel); - - // If the texture doesn't have a texture generator, we will - // derive some properties from the first TextureImage (layer=0, miplvl=0, face=0) - if (!m_textureData && img.layer == 0 && img.mipLevel == 0 && img.face == QAbstractTexture::CubeMapPositiveX) { - if (imgData->width() != -1 && imgData->height() != -1 && imgData->depth() != -1) { - m_properties.width = imgData->width(); - m_properties.height = imgData->height(); - m_properties.depth = imgData->depth(); - } - - // Set the format of the texture if the texture format is set to Automatic - if (m_properties.format == QAbstractTexture::Automatic) { - m_properties.format = static_cast<QAbstractTexture::TextureFormat>(imgData->format()); - } - - setDirtyFlag(Properties, true); + Q_ASSERT(imgData); + m_imageData.push_back(imgData); + maxMipLevel = qMax(maxMipLevel, img.mipLevel); + + // If the texture doesn't have a texture generator, we will + // derive some properties from the first TextureImage (layer=0, miplvl=0, face=0) + if (!m_textureData && img.layer == 0 && img.mipLevel == 0 && img.face == QAbstractTexture::CubeMapPositiveX) { + if (imgData->width() != -1 && imgData->height() != -1 && imgData->depth() != -1) { + m_properties.width = imgData->width(); + m_properties.height = imgData->height(); + m_properties.depth = imgData->depth(); + } + // Set the format of the texture if the texture format is set to Automatic + if (m_properties.format == QAbstractTexture::Automatic) { + m_properties.format = static_cast<QAbstractTexture::TextureFormat>(imgData->format()); } - } else { - // No QTextureImageData generated from functor yet, texture will be invalid for this frame - // but will be correctly loaded at frame n+1 - texturedDataInvalid = true; + setDirtyFlag(Properties, true); } } @@ -195,9 +182,6 @@ QOpenGLTexture* GLTexture::getOrCreateGLTexture() if (m_properties.format == QAbstractTexture::Automatic) return nullptr; - if (texturedDataInvalid) - return nullptr; - // if the properties changed, we need to re-allocate the texture if (testDirtyFlag(Properties)) { delete m_gl; @@ -210,13 +194,12 @@ QOpenGLTexture* GLTexture::getOrCreateGLTexture() return nullptr; m_gl->allocateStorage(); if (!m_gl->isStorageAllocated()) { - qWarning() << Q_FUNC_INFO << "texture storage allocation failed"; return nullptr; } } // need to (re-)upload texture data? - if (needUpload && !texturedDataInvalid) { + if (needUpload) { uploadGLTextureData(); setDirtyFlag(TextureData, false); } @@ -294,47 +277,17 @@ void GLTexture::setImages(const QVector<Image> &images) bool same = (images.size() == m_images.size()); if (same) { for (int i = 0; i < images.size(); i++) { - if (images[i] != m_images[i]) + if (images[i] != m_images[i]) { same = false; + break; + } } } - // de-reference all old texture image generators that will no longer be used. - // we need to check all generators against each other to make sure we don't - // de-ref a texture that would still be in use, thus maybe causing it to - // be deleted - if (!same) { - for (const Image &oldImg : qAsConst(m_images)) { - bool stillHaveThatImage = false; - - for (const Image &newImg : images) { - if (oldImg.generator == newImg.generator) { - stillHaveThatImage = true; - break; - } - } - - if (!stillHaveThatImage) - m_textureImageDataManager->releaseData(oldImg.generator, this); - } + if (!same) { m_images = images; - - // Don't mark the texture data as dirty yet. We defer this until the - // generators have been executed and the data is made available to the - // TextureDataManager. - - // make sure the generators are executed - bool newEntriesCreated = false; - for (const Image& img : qAsConst(images)) { - newEntriesCreated |= m_textureImageDataManager->requestData(img.generator, this); - } - - if (!newEntriesCreated) { - // request a data upload (very important in case the image data already - // exists and wouldn't trigger an update) - requestUpload(); - } + requestUpload(); } } diff --git a/src/render/texture/gltexture_p.h b/src/render/texture/gltexture_p.h index a8f5705e8..cde0a6973 100644 --- a/src/render/texture/gltexture_p.h +++ b/src/render/texture/gltexture_p.h @@ -170,8 +170,8 @@ public: { return &m_textureMutex; } -protected: +protected: template<class APITexture, class APITextureImage> friend class APITextureManager; diff --git a/src/render/texture/texturedatamanager_p.h b/src/render/texture/texturedatamanager_p.h index 13ceca0ee..ef330264c 100644 --- a/src/render/texture/texturedatamanager_p.h +++ b/src/render/texture/texturedatamanager_p.h @@ -81,7 +81,7 @@ namespace Render { * If the last texture disassociates from a generator, the QTextureData will * be deleted. */ -template <class GeneratorPtr, class DataPtr, class APITexture> +template <class GeneratorPtr, class DataPtr, class ReferencedType> class GeneratorDataManager { public: @@ -94,7 +94,7 @@ public: * * Returns true if the Entry for a given generator had to be created */ - bool requestData(const GeneratorPtr &generator, APITexture *tex) + bool requestData(const GeneratorPtr &generator, ReferencedType r) { QMutexLocker lock(&m_mutex); @@ -103,8 +103,8 @@ public: if (needsToBeCreated) entry = createEntry(generator); Q_ASSERT(entry); - if (!entry->referencingTextures.contains(tex)) - entry->referencingTextures.push_back(tex); + if (!entry->referencingObjects.contains(r)) + entry->referencingObjects.push_back(r); return needsToBeCreated; } @@ -112,7 +112,7 @@ public: * Dereference given generator from texture. If no other textures still reference * the generator, the associated data will be deleted */ - void releaseData(const GeneratorPtr &generator, APITexture *tex) + void releaseData(const GeneratorPtr &generator, ReferencedType r) { QMutexLocker lock(&m_mutex); @@ -120,9 +120,9 @@ public: for (auto it = m_data.begin(); it != end; ++it) { Entry &entry = *it; if (*entry.generator == *generator) { - entry.referencingTextures.removeAll(tex); + entry.referencingObjects.removeAll(r); // delete, if that was the last reference - if (entry.referencingTextures.empty()) { + if (entry.referencingObjects.empty()) { m_data.erase(it); return; } @@ -166,22 +166,21 @@ public: Entry *entry = findEntry(generator); if (!entry) { qWarning() << "[TextureDataManager] assignData() called with non-existent generator"; - } else { - entry->data = data; - - // Mark each texture that references this data as being dirty - // so that the submission thread knows to upload - for (auto texture : qAsConst(entry->referencingTextures)) { - texture->requestUpload(); - } + return; } + entry->data = data; + } + + bool contains(const GeneratorPtr &generator) + { + return findEntry(generator) != nullptr; } private: struct Entry { GeneratorPtr generator; - QVector<APITexture*> referencingTextures; + QVector<ReferencedType> referencingObjects; DataPtr data; }; @@ -211,12 +210,12 @@ private: }; class Q_AUTOTEST_EXPORT TextureDataManager - : public GeneratorDataManager<QTextureGeneratorPtr, QTextureDataPtr, GLTexture> + : public GeneratorDataManager<QTextureGeneratorPtr, QTextureDataPtr, GLTexture*> { }; class Q_AUTOTEST_EXPORT TextureImageDataManager - : public GeneratorDataManager<QTextureImageDataGeneratorPtr, QTextureImageDataPtr, GLTexture> + : public GeneratorDataManager<QTextureImageDataGeneratorPtr, QTextureImageDataPtr, Qt3DCore::QNodeId> { }; diff --git a/src/render/texture/textureimage.cpp b/src/render/texture/textureimage.cpp index b732be2d9..b718f237b 100644 --- a/src/render/texture/textureimage.cpp +++ b/src/render/texture/textureimage.cpp @@ -42,6 +42,7 @@ #include <Qt3DRender/qtextureimage.h> #include <Qt3DRender/private/managers_p.h> #include <Qt3DRender/private/qabstracttextureimage_p.h> +#include <Qt3DRender/private/texturedatamanager_p.h> QT_BEGIN_NAMESPACE @@ -56,6 +57,7 @@ TextureImage::TextureImage() , m_mipLevel(0) , m_face(QAbstractTexture::CubeMapPositiveX) , m_textureManager(nullptr) + , m_textureImageDataManager(nullptr) { } @@ -65,6 +67,13 @@ TextureImage::~TextureImage() void TextureImage::cleanup() { + if (m_generator) { + m_textureImageDataManager->releaseData(m_generator, peerId()); + m_generator.reset(); + } + m_layer = 0; + m_mipLevel = 0; + m_face = QAbstractTexture::CubeMapPositiveX; } void TextureImage::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) @@ -85,7 +94,11 @@ void TextureImage::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr Q_ASSERT(texture); // Notify the Texture that it has a new TextureImage and needs an update texture->addTextureImage(peerId()); + } + // Request functor upload + if (m_generator) + m_textureImageDataManager->requestData(m_generator, peerId()); } void TextureImage::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) @@ -100,30 +113,35 @@ void TextureImage::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) } else if (propertyChange->propertyName() == QByteArrayLiteral("face")) { m_face = static_cast<QAbstractTexture::CubeMapFace>(propertyChange->value().toInt()); } else if (propertyChange->propertyName() == QByteArrayLiteral("dataGenerator")) { + // Release ref to generator + if (m_generator) + m_textureImageDataManager->releaseData(m_generator, peerId()); m_generator = propertyChange->value().value<QTextureImageDataGeneratorPtr>(); + // Request functor upload + if (m_generator) + m_textureImageDataManager->requestData(m_generator, peerId()); } // Notify the Texture that we were updated and request it to schedule an update job Texture *txt = m_textureManager->data(m_textureProvider); if (txt != nullptr) txt->addDirtyFlag(Texture::DirtyImageGenerators); + } markDirty(AbstractRenderer::AllDirty); BackendNode::sceneChangeEvent(e); } -void TextureImage::setTextureManager(TextureManager *manager) -{ - m_textureManager = manager; -} TextureImageFunctor::TextureImageFunctor(AbstractRenderer *renderer, TextureManager *textureManager, - TextureImageManager *textureImageManager) + TextureImageManager *textureImageManager, + TextureImageDataManager *textureImageDataManager) : m_renderer(renderer) , m_textureManager(textureManager) , m_textureImageManager(textureImageManager) + , m_textureImageDataManager(textureImageDataManager) { } @@ -131,6 +149,7 @@ Qt3DCore::QBackendNode *TextureImageFunctor::create(const Qt3DCore::QNodeCreated { TextureImage *backend = m_textureImageManager->getOrCreateResource(change->subjectId()); backend->setTextureManager(m_textureManager); + backend->setTextureImageDataManager(m_textureImageDataManager); backend->setRenderer(m_renderer); return backend; } diff --git a/src/render/texture/textureimage_p.h b/src/render/texture/textureimage_p.h index e898b2f1a..b7a1fae8e 100644 --- a/src/render/texture/textureimage_p.h +++ b/src/render/texture/textureimage_p.h @@ -64,7 +64,7 @@ namespace Render { class TextureManager; class TextureImageManager; -class TextureDataManager; +class TextureImageDataManager; /** * Backend class for QAbstractTextureImage. @@ -78,7 +78,11 @@ public: void cleanup(); - void setTextureManager(TextureManager *manager); + void setTextureManager(TextureManager *manager) { m_textureManager = manager; } + void setTextureImageDataManager(TextureImageDataManager *dataManager) { m_textureImageDataManager = dataManager; } + + TextureManager *textureManager() const { return m_textureManager; } + TextureImageDataManager *textureImageDataManager() const { return m_textureImageDataManager; } void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) override; @@ -96,6 +100,7 @@ private: QTextureImageDataGeneratorPtr m_generator; TextureManager *m_textureManager; + TextureImageDataManager *m_textureImageDataManager; HTexture m_textureProvider; }; @@ -104,7 +109,8 @@ class TextureImageFunctor : public Qt3DCore::QBackendNodeMapper public: explicit TextureImageFunctor(AbstractRenderer *renderer, TextureManager *textureManager, - TextureImageManager *textureImageManager); + TextureImageManager *textureImageManager, + TextureImageDataManager *textureImageDataManager); Qt3DCore::QBackendNode *create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const final; Qt3DCore::QBackendNode *get(Qt3DCore::QNodeId id) const final; @@ -114,6 +120,7 @@ private: AbstractRenderer *m_renderer; TextureManager *m_textureManager; TextureImageManager *m_textureImageManager; + TextureImageDataManager *m_textureImageDataManager; }; #ifndef QT_NO_DEBUG_STREAM diff --git a/tests/auto/render/texturedatamanager/tst_texturedatamanager.cpp b/tests/auto/render/texturedatamanager/tst_texturedatamanager.cpp index 5ba43aedc..eb7177adf 100644 --- a/tests/auto/render/texturedatamanager/tst_texturedatamanager.cpp +++ b/tests/auto/render/texturedatamanager/tst_texturedatamanager.cpp @@ -73,7 +73,7 @@ struct FakeAPITexture void requestUpload() {} }; -using Manager = Qt3DRender::Render::GeneratorDataManager<FakeGeneratorPtr, FakeDataPtr, FakeAPITexture>; +using Manager = Qt3DRender::Render::GeneratorDataManager<FakeGeneratorPtr, FakeDataPtr, FakeAPITexture*>; } // anonymous diff --git a/tests/auto/render/textures/textures.pro b/tests/auto/render/textures/textures.pro index 0366adfe7..8a7553a54 100644 --- a/tests/auto/render/textures/textures.pro +++ b/tests/auto/render/textures/textures.pro @@ -9,3 +9,4 @@ CONFIG += testcase SOURCES += tst_textures.cpp include(../../core/common/common.pri) +include(../commons/commons.pri) diff --git a/tests/auto/render/textures/tst_textures.cpp b/tests/auto/render/textures/tst_textures.cpp index 8005e998a..f50131e12 100644 --- a/tests/auto/render/textures/tst_textures.cpp +++ b/tests/auto/render/textures/tst_textures.cpp @@ -43,6 +43,8 @@ #include <Qt3DRender/private/gltexture_p.h> #include <Qt3DRender/private/qtexture_p.h> +#include <testrenderer.h> + /** * @brief Dummy QTextureImageDataGenerator */ @@ -122,12 +124,12 @@ public: { } -protected: - int m_genId; Qt3DRender::QTextureImageDataGeneratorPtr dataGenerator() const { return Qt3DRender::QTextureImageDataGeneratorPtr(new TestImageDataGenerator(m_genId)); } +protected: + int m_genId; }; class tst_RenderTextures : public Qt3DCore::QBackendNodeTester @@ -149,7 +151,8 @@ class tst_RenderTextures : public Qt3DCore::QBackendNodeTester Qt3DRender::Render::Texture *createBackendTexture(Qt3DRender::QAbstractTexture *frontend, Qt3DRender::Render::TextureManager *texMgr, - Qt3DRender::Render::TextureImageManager *texImgMgr) + Qt3DRender::Render::TextureImageManager *texImgMgr, + Qt3DRender::Render::TextureImageDataManager *texImgDataManager) { Qt3DRender::Render::Texture *backend = texMgr->getOrCreateResource(frontend->id()); backend->setTextureImageManager(texImgMgr); @@ -161,6 +164,7 @@ class tst_RenderTextures : public Qt3DCore::QBackendNodeTester if (!texImgMgr->contains(texImgFrontend->id())) { Qt3DRender::Render::TextureImage *texImgBackend = texImgMgr->getOrCreateResource(texImgFrontend->id()); texImgBackend->setTextureManager(texMgr); + texImgBackend->setTextureImageDataManager(texImgDataManager); simulateInitialization(texImgFrontend, texImgBackend); } backend->addTextureImage(texImgFrontend->id()); @@ -182,8 +186,14 @@ private Q_SLOTS: Qt3DRender::QAbstractTexture *tex1b = createQTexture(-1, {1,2}, true); // WHEN - Qt3DRender::Render::Texture *bt1a = createBackendTexture(tex1a, mgrs->textureManager(), mgrs->textureImageManager()); - Qt3DRender::Render::Texture *bt1b = createBackendTexture(tex1b, mgrs->textureManager(), mgrs->textureImageManager()); + Qt3DRender::Render::Texture *bt1a = createBackendTexture(tex1a, + mgrs->textureManager(), + mgrs->textureImageManager(), + mgrs->textureImageDataManager()); + Qt3DRender::Render::Texture *bt1b = createBackendTexture(tex1b, + mgrs->textureManager(), + mgrs->textureImageManager(), + mgrs->textureImageDataManager()); renderer.updateTexture(bt1a); renderer.updateTexture(bt1b); @@ -209,7 +219,10 @@ private Q_SLOTS: // WHEN QVector<Qt3DRender::Render::Texture*> backend; for (auto *t : textures) { - Qt3DRender::Render::Texture *backendTexture = createBackendTexture(t, mgrs->textureManager(), mgrs->textureImageManager()); + Qt3DRender::Render::Texture *backendTexture = createBackendTexture(t, + mgrs->textureManager(), + mgrs->textureImageManager(), + mgrs->textureImageDataManager()); backend.push_back(backendTexture); renderer.updateTexture(backendTexture); } @@ -256,7 +269,10 @@ private Q_SLOTS: // WHEN QVector<Qt3DRender::Render::Texture*> backend; for (auto *t : textures) { - Qt3DRender::Render::Texture *backendTexture = createBackendTexture(t, mgrs->textureManager(), mgrs->textureImageManager()); + Qt3DRender::Render::Texture *backendTexture = createBackendTexture(t, + mgrs->textureManager(), + mgrs->textureImageManager(), + mgrs->textureImageDataManager()); backend.push_back(backendTexture); renderer.updateTexture(backendTexture); } @@ -308,6 +324,265 @@ private Q_SLOTS: QVERIFY(texDataMgr->getData(tg1a) != texDataMgr->getData(tg2)); } + void checkTextureImageInitialState() + { + // GIVEN + Qt3DRender::Render::TextureImage img; + + // THEN + QCOMPARE(img.layer(), 0); + QCOMPARE(img.mipLevel(), 0); + QCOMPARE(img.face(), Qt3DRender::QAbstractTexture::CubeMapPositiveX); + QVERIFY(img.dataGenerator().isNull()); + QVERIFY(img.textureManager() == nullptr); + QVERIFY(img.textureImageDataManager() == nullptr); + } + + void checkTextureImageCleanupState() + { + // GIVEN + QScopedPointer<Qt3DRender::Render::NodeManagers> mgrs(new Qt3DRender::Render::NodeManagers()); + Qt3DRender::Render::TextureManager *texMgr = mgrs->textureManager(); + Qt3DRender::Render::TextureImageDataManager *texImgDataMgr = mgrs->textureImageDataManager(); + + TestTextureImage img(1); + img.setLayer(2); + img.setMipLevel(3); + + // WHEN + Qt3DRender::Render::TextureImage texImgBackend; + texImgBackend.setTextureManager(texMgr); + texImgBackend.setTextureImageDataManager(texImgDataMgr); + simulateInitialization(&img, &texImgBackend); + texImgBackend.cleanup(); + + // THEN + QCOMPARE(texImgBackend.layer(), 0); + QCOMPARE(texImgBackend.mipLevel(), 0); + QCOMPARE(texImgBackend.face(), Qt3DRender::QAbstractTexture::CubeMapPositiveX); + QVERIFY(texImgBackend.dataGenerator().isNull()); + QVERIFY(texImgBackend.textureManager() != nullptr); + QVERIFY(texImgBackend.textureImageDataManager() != nullptr); + } + + void checkTextureImageInitializeFromPeer() + { + // GIVEN + QScopedPointer<Qt3DRender::Render::NodeManagers> mgrs(new Qt3DRender::Render::NodeManagers()); + Qt3DRender::Render::TextureManager *texMgr = mgrs->textureManager(); + Qt3DRender::Render::TextureImageDataManager *texImgDataMgr = mgrs->textureImageDataManager(); + + TestTextureImage img(1); + + { + // WHEN + img.setLayer(2); + img.setMipLevel(3); + + Qt3DRender::Render::TextureImage texImgBackend; + texImgBackend.setTextureManager(texMgr); + texImgBackend.setTextureImageDataManager(texImgDataMgr); + simulateInitialization(&img, &texImgBackend); + + // THEN + QCOMPARE(texImgBackend.isEnabled(), 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.setTextureManager(texMgr); + texImgBackend.setTextureImageDataManager(texImgDataMgr); + simulateInitialization(&img, &texImgBackend); + + // THEN + QCOMPARE(texImgBackend.isEnabled(), false); + QCOMPARE(texImgBackend.peerId(), img.id()); + } + } + + void checkTextureImageSceneChangeEvents() + { + // GIVEN + QScopedPointer<Qt3DRender::Render::NodeManagers> mgrs(new Qt3DRender::Render::NodeManagers()); + Qt3DRender::Render::TextureManager *texMgr = mgrs->textureManager(); + Qt3DRender::Render::TextureImageDataManager *texImgDataMgr = mgrs->textureImageDataManager(); + Qt3DRender::Render::TextureImage backendImage; + TestRenderer renderer; + backendImage.setRenderer(&renderer); + backendImage.setTextureManager(texMgr); + backendImage.setTextureImageDataManager(texImgDataMgr); + + { + // WHEN + const bool newValue = false; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("enabled"); + change->setValue(newValue); + backendImage.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendImage.isEnabled(), newValue); + QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::AllDirty); + renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); + } + + { + // WHEN + const int newValue = 7; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("layer"); + change->setValue(newValue); + backendImage.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendImage.layer(), newValue); + QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::AllDirty); + renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); + } + + { + // WHEN + const int newValue = 3; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("mipLevel"); + change->setValue(newValue); + backendImage.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendImage.mipLevel(), newValue); + QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::AllDirty); + renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); + } + + { + // WHEN + const Qt3DRender::QAbstractTexture::CubeMapFace newValue = Qt3DRender::QAbstractTexture::CubeMapNegativeX; + const auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("face"); + change->setValue(newValue); + backendImage.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendImage.face(), newValue); + QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::AllDirty); + renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); + } + + { + // WHEN + Qt3DRender::QTextureImageDataGeneratorPtr generator1(new TestImageDataGenerator(883)); + auto change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("dataGenerator"); + change->setValue(QVariant::fromValue(generator1)); + backendImage.sceneChangeEvent(change); + + // THEN + QCOMPARE(backendImage.dataGenerator(), generator1); + QVERIFY(texImgDataMgr->contains(generator1)); + QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::AllDirty); + renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); + + // WHEN + Qt3DRender::QTextureImageDataGeneratorPtr generator2(new TestImageDataGenerator(1584)); + change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("dataGenerator"); + change->setValue(QVariant::fromValue(generator2)); + backendImage.sceneChangeEvent(change); + + // THEN + QVERIFY(!texImgDataMgr->contains(generator1)); + QVERIFY(texImgDataMgr->contains(generator2)); + QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::AllDirty); + renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); + + // WHEN + Qt3DRender::QTextureImageDataGeneratorPtr generator3; + change = Qt3DCore::QPropertyUpdatedChangePtr::create(Qt3DCore::QNodeId()); + change->setPropertyName("dataGenerator"); + change->setValue(QVariant::fromValue(generator3)); + backendImage.sceneChangeEvent(change); + + // THEN + QVERIFY(!texImgDataMgr->contains(generator1)); + QVERIFY(!texImgDataMgr->contains(generator2)); + QVERIFY(backendImage.dataGenerator().isNull()); + QVERIFY(renderer.dirtyBits() & Qt3DRender::Render::AbstractRenderer::AllDirty); + renderer.clearDirtyBits(Qt3DRender::Render::AbstractRenderer::AllDirty); + } + } + + void checkTextureImageProperlyReleaseGenerator() + { + QScopedPointer<Qt3DRender::Render::NodeManagers> mgrs(new Qt3DRender::Render::NodeManagers()); + Qt3DRender::Render::Renderer renderer(Qt3DRender::QRenderAspect::Synchronous); + Qt3DRender::Render::TextureManager *texMgr = mgrs->textureManager(); + Qt3DRender::Render::TextureImageManager *texImgMgr = mgrs->textureImageManager(); + Qt3DRender::Render::TextureImageDataManager *texImgDataMgr = mgrs->textureImageDataManager(); + renderer.setNodeManagers(mgrs.data()); + + // GIVEN + Qt3DRender::QAbstractTexture* frontendTexture = createQTexture(1, {1}, true); + + Qt3DRender::Render::Texture *backendTexture = texMgr->getOrCreateResource(frontendTexture->id()); + backendTexture->setTextureImageManager(texImgMgr); + simulateInitialization(frontendTexture, backendTexture); + + // THEN + QCOMPARE(backendTexture->textureImages().size(), 0); + QCOMPARE(frontendTexture->textureImages().size(), 1); + + // WHEN + TestTextureImage *texImgFrontend = static_cast<TestTextureImage *>(frontendTexture->textureImages().first()); + const Qt3DRender::QTextureImageDataGeneratorPtr frontendGenerator = texImgFrontend->dataGenerator(); + + // THEN + QVERIFY(!frontendGenerator.isNull()); + QCOMPARE(texImgDataMgr->pendingGenerators().size(), 0); + QVERIFY(!texImgDataMgr->contains(frontendGenerator)); + QVERIFY(texImgDataMgr->getData(frontendGenerator).isNull()); + + // WHEN + Qt3DRender::Render::TextureImage *texImgBackend = texImgMgr->getOrCreateResource(texImgFrontend->id()); + texImgBackend->setTextureManager(texMgr); + texImgBackend->setTextureImageDataManager(texImgDataMgr); + simulateInitialization(texImgFrontend, texImgBackend); + + // THEN + qDebug() << frontendGenerator << texImgBackend->dataGenerator(); + const Qt3DRender::QTextureImageDataGeneratorPtr backendGenerator = texImgFrontend->dataGenerator(); + QVERIFY(frontendGenerator != backendGenerator); + QVERIFY(*frontendGenerator == *backendGenerator); + QVERIFY(texImgDataMgr->contains(frontendGenerator)); + QVERIFY(texImgDataMgr->contains(backendGenerator)); + QVERIFY(texImgDataMgr->getData(frontendGenerator).isNull()); + QCOMPARE(texImgDataMgr->pendingGenerators().size(), 1); + + // WHEN + texImgDataMgr->assignData(frontendGenerator, (*frontendGenerator)()); + + // THEN + QVERIFY(!texImgDataMgr->getData(frontendGenerator).isNull()); + QVERIFY(!texImgDataMgr->getData(backendGenerator).isNull()); + QVERIFY(texImgDataMgr->getData(backendGenerator) == texImgDataMgr->getData(frontendGenerator)); + + // WHEN + texImgBackend->cleanup(); + + // THEN + QVERIFY(!texImgDataMgr->contains(frontendGenerator)); + QVERIFY(!texImgDataMgr->contains(backendGenerator)); + QCOMPARE(texImgDataMgr->pendingGenerators().size(), 0); + QVERIFY(texImgDataMgr->getData(frontendGenerator).isNull()); + QVERIFY(texImgDataMgr->getData(backendGenerator).isNull()); + } }; QTEST_MAIN(tst_RenderTextures) |