summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Lemire <paul.lemire@kdab.com>2018-07-11 11:18:24 +0200
committerPaul Lemire <paul.lemire@kdab.com>2018-07-18 13:44:26 +0000
commitcdf92a8ba06c3df17a11c8931d540a4bf9229f61 (patch)
tree4ef115907f603ac321f4bfc97fb6dcecc1637603 /src
parentee53b5366eb925b2fbe3cd28209e2f8c7bc9e143 (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.cpp3
-rw-r--r--src/render/renderers/opengl/renderer/renderer.cpp37
-rw-r--r--src/render/texture/apitexturemanager_p.h22
-rw-r--r--src/render/texture/qabstracttexture.cpp2
-rw-r--r--src/render/texture/texture.cpp48
-rw-r--r--src/render/texture/texture_p.h15
-rw-r--r--src/render/texture/textureimage.cpp29
-rw-r--r--src/render/texture/textureimage_p.h9
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;
};