diff options
author | Paul Lemire <paul.lemire@kdab.com> | 2018-07-11 11:18:24 +0200 |
---|---|---|
committer | Paul Lemire <paul.lemire@kdab.com> | 2018-07-18 13:44:26 +0000 |
commit | cdf92a8ba06c3df17a11c8931d540a4bf9229f61 (patch) | |
tree | 4ef115907f603ac321f4bfc97fb6dcecc1637603 /src | |
parent | ee53b5366eb925b2fbe3cd28209e2f8c7bc9e143 (diff) |
Fix: Do not enforce TextureImage to be parented only by Texture
This behavior prevented using TextureImage not directly parented by the
Texture that uses them (assert would be triggered). In turn, this also
prevents sharing a TextureImage among several Texture instances which is
counter productive since this is where the data is actually stored.
This patch fixes this issue. It removes all direct coupling between Texture
and TextureImages. Now Texture only contains the list of TextureImage ids it
references. This allows to not make look-ups into the TextureImageManager to
retrieve handles, which could be an issue if TextureImages have not yet had
their backend created. TextureImage doesn't keep track of the referencing texture
that uses it anymore. Instead, we let the renderer do the job of checking if any of
the TextureImage referenced by a Texture has changed to trigger actual Texture
update.
Change-Id: I3c63379d0f4b314e9b53f225870eeaded0bb4aec
Task-number: QTBUG-69407
Reviewed-by: Mike Krus <mike.krus@kdab.com>
Diffstat (limited to 'src')
-rw-r--r-- | src/render/frontend/qrenderaspect.cpp | 3 | ||||
-rw-r--r-- | src/render/renderers/opengl/renderer/renderer.cpp | 37 | ||||
-rw-r--r-- | src/render/texture/apitexturemanager_p.h | 22 | ||||
-rw-r--r-- | src/render/texture/qabstracttexture.cpp | 2 | ||||
-rw-r--r-- | src/render/texture/texture.cpp | 48 | ||||
-rw-r--r-- | src/render/texture/texture_p.h | 15 | ||||
-rw-r--r-- | src/render/texture/textureimage.cpp | 29 | ||||
-rw-r--r-- | src/render/texture/textureimage_p.h | 9 |
8 files changed, 73 insertions, 92 deletions
diff --git a/src/render/frontend/qrenderaspect.cpp b/src/render/frontend/qrenderaspect.cpp index 1470448e5..09cb75e46 100644 --- a/src/render/frontend/qrenderaspect.cpp +++ b/src/render/frontend/qrenderaspect.cpp @@ -253,9 +253,8 @@ void QRenderAspectPrivate::registerBackendTypes() q->registerBackendType<Qt3DCore::QJoint>(QSharedPointer<Render::JointFunctor>::create(m_renderer, m_nodeManagers->jointManager(), m_nodeManagers->skeletonManager())); // Textures - q->registerBackendType<QAbstractTexture>(QSharedPointer<Render::TextureFunctor>::create(m_renderer, m_nodeManagers->textureManager(), m_nodeManagers->textureImageManager())); + q->registerBackendType<QAbstractTexture>(QSharedPointer<Render::TextureFunctor>::create(m_renderer, m_nodeManagers->textureManager())); q->registerBackendType<QAbstractTextureImage>(QSharedPointer<Render::TextureImageFunctor>::create(m_renderer, - m_nodeManagers->textureManager(), m_nodeManagers->textureImageManager(), m_nodeManagers->textureImageDataManager())); diff --git a/src/render/renderers/opengl/renderer/renderer.cpp b/src/render/renderers/opengl/renderer/renderer.cpp index 1e0a43b30..904527cd5 100644 --- a/src/render/renderers/opengl/renderer/renderer.cpp +++ b/src/render/renderers/opengl/renderer/renderer.cpp @@ -1057,13 +1057,42 @@ void Renderer::lookForDownloadableBuffers() // Executed in a job void Renderer::lookForDirtyTextures() { - const QVector<HTexture> activeTextureHandles = m_nodesManager->textureManager()->activeHandles(); + // To avoid having Texture or TextureImage maintain relationships between + // one another, we instead perform a lookup here to check if a texture + // image has been updated to then notify textures referencing the image + // that they need to be updated + TextureImageManager *imageManager = m_nodesManager->textureImageManager(); + const QVector<HTextureImage> activeTextureImageHandles = imageManager->activeHandles(); + Qt3DCore::QNodeIdVector dirtyImageIds; + for (const HTextureImage &handle: activeTextureImageHandles) { + TextureImage *image = imageManager->data(handle); + if (image->isDirty()) { + dirtyImageIds.push_back(image->peerId()); + image->unsetDirty(); + } + } + + TextureManager *textureManager = m_nodesManager->textureManager(); + const QVector<HTexture> activeTextureHandles = textureManager->activeHandles(); for (const HTexture &handle: activeTextureHandles) { - Texture *texture = m_nodesManager->textureManager()->data(handle); + Texture *texture = textureManager->data(handle); + const QNodeIdVector imageIds = texture->textureImageIds(); + + // Does the texture reference any of the dirty texture images? + for (const QNodeId imageId: imageIds) { + if (dirtyImageIds.contains(imageId)) { + texture->addDirtyFlag(Texture::DirtyImageGenerators); + break; + } + } + // Dirty meaning that something has changed on the texture // either properties, parameters, generator or a texture image if (texture->dirtyFlags() != Texture::NotDirty) m_dirtyTextures.push_back(handle); + // Note: texture dirty flags are reset when actually updating the + // textures in updateGLResources() as resetting flags here would make + // us lose information about what was dirty exactly. } } @@ -1204,7 +1233,7 @@ void Renderer::updateGLResources() void Renderer::updateTexture(Texture *texture) { // Check that the current texture images are still in place, if not, do not update - const bool isValid = texture->isValid(); + const bool isValid = texture->isValid(m_nodesManager->textureImageManager()); if (!isValid) return; @@ -1278,7 +1307,7 @@ void Renderer::updateTexture(Texture *texture) // Will make the texture requestUpload if (dirtyFlags.testFlag(Texture::DirtyImageGenerators) && - !glTextureManager->setImages(glTexture, texture->textureImages())) + !glTextureManager->setImages(glTexture, texture->textureImageIds())) qWarning() << "[Qt3DRender::TextureNode] updateTexture: TextureImpl.setGenerators failed, should be non-shared"; // Will make the texture requestUpload diff --git a/src/render/texture/apitexturemanager_p.h b/src/render/texture/apitexturemanager_p.h index 97dc1eb27..58a73e09e 100644 --- a/src/render/texture/apitexturemanager_p.h +++ b/src/render/texture/apitexturemanager_p.h @@ -219,7 +219,7 @@ public: // Change the texture images of the given texture, if it is a non-shared texture // Return true, if it was changed successfully, false otherwise - bool setImages(APITexture *tex, const QVector<HTextureImage> &images) + bool setImages(APITexture *tex, const Qt3DCore::QNodeIdVector &imageIds) { Q_ASSERT(tex); @@ -227,8 +227,8 @@ public: return false; // create Image structs - QVector<APITextureImage> texImgs = texImgsFromNodes(images); - if (texImgs.size() != images.size()) + QVector<APITextureImage> texImgs = texImgsFromNodes(imageIds); + if (texImgs.size() != imageIds.size()) return false; tex->setImages(texImgs); @@ -293,11 +293,11 @@ private: // make sure the image generators are the same const QVector<APITextureImage> texImgGens = tex->images(); - const QVector<HTextureImage> texImgs = texNode->textureImages(); + const Qt3DCore::QNodeIdVector texImgs = texNode->textureImageIds(); if (texImgGens.size() != texImgs.size()) return false; for (int i = 0; i < texImgGens.size(); ++i) { - const TextureImage *img = m_textureImageManager->data(texImgs[i]); + const TextureImage *img = m_textureImageManager->lookupResource(texImgs[i]); Q_ASSERT(img != nullptr); if (!(*img->dataGenerator() == *texImgGens[i].generator) || img->layer() != texImgGens[i].layer @@ -330,8 +330,8 @@ private: APITexture *createTexture(const Texture *node, bool unique) { // create Image structs - const QVector<APITextureImage> texImgs = texImgsFromNodes(node->textureImages()); - if (texImgs.empty() && !node->textureImages().empty()) + const QVector<APITextureImage> texImgs = texImgsFromNodes(node->textureImageIds()); + if (texImgs.empty() && !node->textureImageIds().empty()) return nullptr; // no matching shared texture was found, create a new one @@ -345,13 +345,13 @@ private: return newTex; } - QVector<APITextureImage> texImgsFromNodes(const QVector<HTextureImage> &images) const + QVector<APITextureImage> texImgsFromNodes(const Qt3DCore::QNodeIdVector &imageIds) const { QVector<APITextureImage> ret; - ret.resize(images.size()); + ret.resize(imageIds.size()); - for (int i = 0; i < images.size(); ++i) { - const TextureImage *img = m_textureImageManager->data(images[i]); + for (int i = 0; i < imageIds.size(); ++i) { + const TextureImage *img = m_textureImageManager->lookupResource(imageIds[i]); if (!img) { qWarning() << "[Qt3DRender::TextureManager] invalid TextureImage handle"; return QVector<APITextureImage>(); diff --git a/src/render/texture/qabstracttexture.cpp b/src/render/texture/qabstracttexture.cpp index c4c693852..03746620e 100644 --- a/src/render/texture/qabstracttexture.cpp +++ b/src/render/texture/qabstracttexture.cpp @@ -630,8 +630,6 @@ void QAbstractTexture::addTextureImage(QAbstractTextureImage *textureImage) // Ensures proper bookkeeping d->registerDestructionHelper(textureImage, &QAbstractTexture::removeTextureImage, d->m_textureImages); - if (textureImage->parent() && textureImage->parent() != this) - qWarning() << "A QAbstractTextureImage was shared, expect a crash, undefined behavior at best"; // We need to add it as a child of the current node if it has been declared inline // Or not previously added as a child of the current node so that // 1) The backend gets notified about it's creation diff --git a/src/render/texture/texture.cpp b/src/render/texture/texture.cpp index 914a4d9d8..5a50fb30f 100644 --- a/src/render/texture/texture.cpp +++ b/src/render/texture/texture.cpp @@ -62,7 +62,6 @@ Texture::Texture() // We need backend -> frontend notifications to update the status of the texture : BackendNode(ReadWrite) , m_dirty(DirtyImageGenerators|DirtyProperties|DirtyParameters|DirtyDataGenerator) - , m_textureImageManager(nullptr) { } @@ -74,11 +73,6 @@ Texture::~Texture() // would have been called } -void Texture::setTextureImageManager(TextureImageManager *manager) -{ - m_textureImageManager = manager; -} - void Texture::addDirtyFlag(DirtyFlags flags) { QMutexLocker lock(&m_flagsMutex); @@ -101,34 +95,16 @@ void Texture::unsetDirty() void Texture::addTextureImage(Qt3DCore::QNodeId id) { - if (!m_textureImageManager) { - qWarning() << "[Qt3DRender::TextureNode] addTextureImage: invalid TextureImageManager"; - return; - } - - const HTextureImage handle = m_textureImageManager->lookupHandle(id); - if (handle.isNull()) { - qWarning() << "[Qt3DRender::TextureNode] addTextureImage: image handle is NULL"; - } else if (!m_textureImages.contains(handle)) { - m_textureImages << handle; + if (!m_textureImageIds.contains(id)) { + m_textureImageIds.push_back(id); addDirtyFlag(DirtyImageGenerators); } } void Texture::removeTextureImage(Qt3DCore::QNodeId id) { - if (!m_textureImageManager) { - qWarning() << "[Qt3DRender::TextureNode] removeTextureImage: invalid TextureImageManager"; - return; - } - - const HTextureImage handle = m_textureImageManager->lookupHandle(id); - if (handle.isNull()) { - qWarning() << "[Qt3DRender::TextureNode] removeTextureImage: image handle is NULL"; - } else { - m_textureImages.removeAll(handle); - addDirtyFlag(DirtyImageGenerators); - } + m_textureImageIds.removeAll(id); + addDirtyFlag(DirtyImageGenerators); } // This is called by Renderer::updateGLResources @@ -138,7 +114,7 @@ void Texture::cleanup() // Whoever calls this must make sure to also check if this // texture is being referenced by a shared API specific texture (GLTexture) m_dataFunctor.reset(); - m_textureImages.clear(); + m_textureImageIds.clear(); // set default values m_properties.width = 1; @@ -321,10 +297,10 @@ void Texture::updateFromData(QTextureDataPtr data) } } -bool Texture::isValid() const +bool Texture::isValid(TextureImageManager *manager) const { - for (const auto &handle : m_textureImages) { - TextureImage *img = m_textureImageManager->data(handle); + for (const QNodeId id : m_textureImageIds) { + TextureImage *img = manager->lookupResource(id); if (img == nullptr) return false; } @@ -354,23 +330,23 @@ void Texture::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &chan m_parameters.comparisonMode = data.comparisonMode; m_dataFunctor = data.dataFunctor; + for (const QNodeId imgId : data.textureImageIds) + addTextureImage(imgId); + addDirtyFlag(DirtyFlags(DirtyImageGenerators|DirtyProperties|DirtyParameters)); } TextureFunctor::TextureFunctor(AbstractRenderer *renderer, - TextureManager *textureNodeManager, - TextureImageManager *textureImageManager) + TextureManager *textureNodeManager) : m_renderer(renderer) , m_textureNodeManager(textureNodeManager) - , m_textureImageManager(textureImageManager) { } Qt3DCore::QBackendNode *TextureFunctor::create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const { Texture *backend = m_textureNodeManager->getOrCreateResource(change->subjectId()); - backend->setTextureImageManager(m_textureImageManager); backend->setRenderer(m_renderer); // Remove id from cleanupList if for some reason we were in the dirty list of texture // (Can happen when a node destroyed is followed by a node created change diff --git a/src/render/texture/texture_p.h b/src/render/texture/texture_p.h index 7e23f124c..789285644 100644 --- a/src/render/texture/texture_p.h +++ b/src/render/texture/texture_p.h @@ -140,8 +140,6 @@ public: }; Q_DECLARE_FLAGS(DirtyFlags, DirtyFlag) - void setTextureImageManager(TextureImageManager *manager); - void addDirtyFlag(DirtyFlags flags); DirtyFlags dirtyFlags(); void unsetDirty(); @@ -154,13 +152,13 @@ public: inline const TextureProperties& properties() const { return m_properties; } inline const TextureParameters& parameters() const { return m_parameters; } - inline const QVector<HTextureImage>& textureImages() const { return m_textureImages; } + inline const Qt3DCore::QNodeIdVector textureImageIds() const { return m_textureImageIds; } inline const QTextureGeneratorPtr& dataGenerator() const { return m_dataFunctor; } void notifyStatus(QAbstractTexture::Status status); void updateFromData(QTextureDataPtr data); - bool isValid() const; + bool isValid(TextureImageManager *manager) const; private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final; @@ -169,9 +167,8 @@ private: TextureParameters m_parameters; QTextureGeneratorPtr m_dataFunctor; - QVector<HTextureImage> m_textureImages; + Qt3DCore::QNodeIdVector m_textureImageIds; - TextureImageManager *m_textureImageManager; QMutex m_flagsMutex; }; @@ -179,8 +176,7 @@ class Q_AUTOTEST_EXPORT TextureFunctor : public Qt3DCore::QBackendNodeMapper { public: explicit TextureFunctor(AbstractRenderer *renderer, - TextureManager *textureNodeManager, - TextureImageManager *textureImageManager); + TextureManager *textureNodeManager); Qt3DCore::QBackendNode *create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const final; Qt3DCore::QBackendNode *get(Qt3DCore::QNodeId id) const final; void destroy(Qt3DCore::QNodeId id) const final; @@ -188,14 +184,13 @@ public: private: AbstractRenderer *m_renderer; TextureManager *m_textureNodeManager; - TextureImageManager *m_textureImageManager; }; #ifndef QT_NO_DEBUG_STREAM inline QDebug operator<<(QDebug dbg, const Texture &texture) { QDebugStateSaver saver(dbg); - dbg << "QNodeId =" << texture.peerId() << "imageCount =" << texture.textureImages().size() << endl; + dbg << "QNodeId =" << texture.peerId() << "imageCount =" << texture.textureImageIds().size() << endl; return dbg; } #endif diff --git a/src/render/texture/textureimage.cpp b/src/render/texture/textureimage.cpp index b718f237b..880562b87 100644 --- a/src/render/texture/textureimage.cpp +++ b/src/render/texture/textureimage.cpp @@ -53,10 +53,10 @@ namespace Render { TextureImage::TextureImage() : BackendNode(ReadWrite) + , m_dirty(false) , m_layer(0) , m_mipLevel(0) , m_face(QAbstractTexture::CubeMapPositiveX) - , m_textureManager(nullptr) , m_textureImageDataManager(nullptr) { } @@ -71,6 +71,7 @@ void TextureImage::cleanup() m_textureImageDataManager->releaseData(m_generator, peerId()); m_generator.reset(); } + m_dirty = false; m_layer = 0; m_mipLevel = 0; m_face = QAbstractTexture::CubeMapPositiveX; @@ -84,18 +85,8 @@ void TextureImage::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr m_layer = data.layer; m_face = data.face; m_generator = data.generator; + m_dirty = true; - if (!change->parentId()) { - qWarning() << "No QAbstractTexture parent found"; - } else { - const QNodeId id = change->parentId(); - m_textureProvider = m_textureManager->lookupHandle(id); - Texture *texture = m_textureManager->data(m_textureProvider); - 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()); @@ -121,25 +112,22 @@ void TextureImage::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) 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); - + m_dirty = true; } markDirty(AbstractRenderer::AllDirty); BackendNode::sceneChangeEvent(e); } +void TextureImage::unsetDirty() +{ + m_dirty = false; +} TextureImageFunctor::TextureImageFunctor(AbstractRenderer *renderer, - TextureManager *textureManager, TextureImageManager *textureImageManager, TextureImageDataManager *textureImageDataManager) : m_renderer(renderer) - , m_textureManager(textureManager) , m_textureImageManager(textureImageManager) , m_textureImageDataManager(textureImageDataManager) { @@ -148,7 +136,6 @@ TextureImageFunctor::TextureImageFunctor(AbstractRenderer *renderer, Qt3DCore::QBackendNode *TextureImageFunctor::create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const { 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 b7a1fae8e..19801ee77 100644 --- a/src/render/texture/textureimage_p.h +++ b/src/render/texture/textureimage_p.h @@ -78,10 +78,8 @@ public: void cleanup(); - 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; @@ -90,25 +88,25 @@ public: inline int mipLevel() const { return m_mipLevel; } inline QAbstractTexture::CubeMapFace face() const { return m_face; } inline QTextureImageDataGeneratorPtr dataGenerator() const { return m_generator; } + inline bool isDirty() const { return m_dirty; } + void unsetDirty(); private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) final; + bool m_dirty; int m_layer; int m_mipLevel; QAbstractTexture::CubeMapFace m_face; QTextureImageDataGeneratorPtr m_generator; - TextureManager *m_textureManager; TextureImageDataManager *m_textureImageDataManager; - HTexture m_textureProvider; }; class TextureImageFunctor : public Qt3DCore::QBackendNodeMapper { public: explicit TextureImageFunctor(AbstractRenderer *renderer, - TextureManager *textureManager, TextureImageManager *textureImageManager, TextureImageDataManager *textureImageDataManager); @@ -118,7 +116,6 @@ public: private: AbstractRenderer *m_renderer; - TextureManager *m_textureManager; TextureImageManager *m_textureImageManager; TextureImageDataManager *m_textureImageDataManager; }; |