summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Lemire <paul.lemire@kdab.com>2018-02-23 09:09:03 +0100
committerPaul Lemire <paul.lemire@kdab.com>2018-02-28 10:46:24 +0000
commit6ea64e9ba9c17302c50648e4c3836a7563679f6a (patch)
treea2e5979fb59e2c49c0e90fb14b04784c71b9e449
parent3dff7c204da1d834629544b54b9f6efaafe165e2 (diff)
Load textures in a single frame
Because of texture sharing, Qt3D compares functor before executing them. Instead of blindly loading a TextureImage functor which could turn out to not be used, Qt3D required 2 frames to fully update a texture. This behavior has been removed, now when a texture image functor is updated, it updates the texture in one frame. It is assumed that the user is responsible for declaring only TextureImage that he is actually going to use. Any scene that uses OnDemand rendering and frequently changes a texture image functor can be used to test this. (ex-painted-cube is a good example for KDAB) or paintedtexture-cpp in manual tests Change-Id: I8c2f13876244a862633e10e472e2b49cbd6e126b Task-number: QTBUG-63561 Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
-rw-r--r--src/render/backend/renderer.cpp10
-rw-r--r--src/render/frontend/qrenderaspect.cpp5
-rw-r--r--src/render/graphicshelpers/graphicscontext.cpp7
-rw-r--r--src/render/texture/gltexture.cpp91
-rw-r--r--src/render/texture/gltexture_p.h2
-rw-r--r--src/render/texture/texturedatamanager_p.h35
-rw-r--r--src/render/texture/textureimage.cpp29
-rw-r--r--src/render/texture/textureimage_p.h13
-rw-r--r--tests/auto/render/texturedatamanager/tst_texturedatamanager.cpp2
-rw-r--r--tests/auto/render/textures/textures.pro1
-rw-r--r--tests/auto/render/textures/tst_textures.cpp289
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 &parameterPack)
{
// 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 &parameterPack)
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 &parameterPack)
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)