mirror of https://github.com/qt/qt3d.git
Destroy FBOs when RenderTarget node is destroyed
It appears we never destroyed FBOs which lead to bugs when destroying and recreating a RenderTarget Change-Id: I99b3df95b821670aa3bbd63209ff9bcc21afbf79 Reviewed-by: Mike Krus <mike.krus@kdab.com>
This commit is contained in:
parent
d046e7cc3e
commit
294894610b
|
|
@ -282,6 +282,35 @@ class RenderTargetManager : public Qt3DCore::QResourceManager<
|
|||
{
|
||||
public:
|
||||
RenderTargetManager() {}
|
||||
|
||||
// Called in AspectThread by RenderTarget node functor destroy
|
||||
void addRenderTargetIdToCleanup(Qt3DCore::QNodeId id)
|
||||
{
|
||||
m_renderTargetIdsToCleanup.push_back(id);
|
||||
}
|
||||
|
||||
// Called in AspectThread by RenderTarget node functor create
|
||||
void removeRenderTargetToCleanup(Qt3DCore::QNodeId id)
|
||||
{
|
||||
m_renderTargetIdsToCleanup.removeAll(id);
|
||||
}
|
||||
|
||||
// Called by RenderThread in updateGLResources (locked)
|
||||
QVector<Qt3DCore::QNodeId> takeRenderTargetIdsToCleanup()
|
||||
{
|
||||
return std::move(m_renderTargetIdsToCleanup);
|
||||
}
|
||||
|
||||
#ifdef QT_BUILD_INTERNAL
|
||||
// For unit testing purposes only
|
||||
QVector<Qt3DCore::QNodeId> renderTargetIdsToCleanup() const
|
||||
{
|
||||
return m_renderTargetIdsToCleanup;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
QVector<Qt3DCore::QNodeId> m_renderTargetIdsToCleanup;
|
||||
};
|
||||
|
||||
class RenderPassManager : public Qt3DCore::QResourceManager<
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#include <Qt3DRender/qrendertarget.h>
|
||||
#include <Qt3DRender/private/qrendertarget_p.h>
|
||||
#include <Qt3DRender/qrendertargetoutput.h>
|
||||
#include <Qt3DRender/private/managers_p.h>
|
||||
#include <QVariant>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
|
@ -94,6 +95,33 @@ QVector<Qt3DCore::QNodeId> RenderTarget::renderOutputs() const
|
|||
return m_renderOutputs;
|
||||
}
|
||||
|
||||
RenderTargetFunctor::RenderTargetFunctor(AbstractRenderer *renderer, RenderTargetManager *manager)
|
||||
: m_renderer(renderer)
|
||||
, m_renderTargetManager(manager)
|
||||
{
|
||||
}
|
||||
|
||||
QBackendNode *RenderTargetFunctor::create(const QNodeCreatedChangeBasePtr &change) const
|
||||
{
|
||||
RenderTarget *backend = m_renderTargetManager->getOrCreateResource(change->subjectId());
|
||||
// Remove from the list of ids to destroy in case we were added to it
|
||||
m_renderTargetManager->removeRenderTargetToCleanup(change->subjectId());
|
||||
backend->setRenderer(m_renderer);
|
||||
return backend;
|
||||
}
|
||||
|
||||
QBackendNode *RenderTargetFunctor::get(QNodeId id) const
|
||||
{
|
||||
return m_renderTargetManager->lookupResource(id);
|
||||
}
|
||||
|
||||
void RenderTargetFunctor::destroy(QNodeId id) const
|
||||
{
|
||||
// We add ourselves to the dirty list to tell the renderer that this rendertarget has been destroyed
|
||||
m_renderTargetManager->addRenderTargetIdToCleanup(id);
|
||||
m_renderTargetManager->releaseResource(id);
|
||||
}
|
||||
|
||||
} // namespace Render
|
||||
} // namespace Qt3DRender
|
||||
|
||||
|
|
|
|||
|
|
@ -82,6 +82,21 @@ private:
|
|||
QVector<Qt3DCore::QNodeId> m_renderOutputs;
|
||||
};
|
||||
|
||||
class Q_AUTOTEST_EXPORT RenderTargetFunctor : public Qt3DCore::QBackendNodeMapper
|
||||
{
|
||||
public:
|
||||
explicit RenderTargetFunctor(AbstractRenderer *renderer,
|
||||
RenderTargetManager *manager);
|
||||
Qt3DCore::QBackendNode *create(const Qt3DCore::QNodeCreatedChangeBasePtr &change) const final;
|
||||
Qt3DCore::QBackendNode *get(Qt3DCore::QNodeId id) const final;
|
||||
void destroy(Qt3DCore::QNodeId id) const final;
|
||||
|
||||
private:
|
||||
AbstractRenderer *m_renderer;
|
||||
RenderTargetManager *m_renderTargetManager;
|
||||
};
|
||||
|
||||
|
||||
} // namespace Render
|
||||
|
||||
} // namespace Qt3DRender
|
||||
|
|
|
|||
|
|
@ -269,7 +269,7 @@ void QRenderAspectPrivate::registerBackendTypes()
|
|||
registerBackendType<QLevelOfDetail, true>(QSharedPointer<Render::NodeFunctor<Render::LevelOfDetail, Render::LevelOfDetailManager> >::create(m_renderer));
|
||||
registerBackendType<QLevelOfDetailSwitch, true>(QSharedPointer<Render::NodeFunctor<Render::LevelOfDetail, Render::LevelOfDetailManager> >::create(m_renderer));
|
||||
registerBackendType<QSceneLoader, true>(QSharedPointer<Render::RenderSceneFunctor>::create(m_renderer, m_nodeManagers->sceneManager()));
|
||||
registerBackendType<QRenderTarget, true>(QSharedPointer<Render::NodeFunctor<Render::RenderTarget, Render::RenderTargetManager> >::create(m_renderer));
|
||||
registerBackendType<QRenderTarget, true>(QSharedPointer<Render::RenderTargetFunctor>::create(m_renderer, m_nodeManagers->renderTargetManager()));
|
||||
registerBackendType<QRenderTargetOutput, true>(QSharedPointer<Render::NodeFunctor<Render::RenderTargetOutput, Render::AttachmentManager> >::create(m_renderer));
|
||||
registerBackendType<QRenderSettings, true>(QSharedPointer<Render::RenderSettingsFunctor>::create(m_renderer));
|
||||
registerBackendType<QRenderState, true>(QSharedPointer<Render::NodeFunctor<Render::RenderStateNode, Render::RenderStateManager> >::create(m_renderer));
|
||||
|
|
|
|||
|
|
@ -506,6 +506,14 @@ void SubmissionContext::activateRenderTarget(Qt3DCore::QNodeId renderTargetNodeI
|
|||
activateDrawBuffers(attachments);
|
||||
}
|
||||
|
||||
void SubmissionContext::releaseRenderTarget(const Qt3DCore::QNodeId id)
|
||||
{
|
||||
if (m_renderTargets.contains(id)) {
|
||||
const GLuint fboId = m_renderTargets.take(id);
|
||||
m_glHelper->releaseFrameBufferObject(fboId);
|
||||
}
|
||||
}
|
||||
|
||||
GLuint SubmissionContext::createRenderTarget(Qt3DCore::QNodeId renderTargetNodeId, const AttachmentPack &attachments)
|
||||
{
|
||||
const GLuint fboId = m_glHelper->createFrameBufferObject();
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ public:
|
|||
// FBO
|
||||
GLuint activeFBO() const { return m_activeFBO; }
|
||||
void activateRenderTarget(const Qt3DCore::QNodeId id, const AttachmentPack &attachments, GLuint defaultFboId);
|
||||
void releaseRenderTarget(const Qt3DCore::QNodeId id);
|
||||
QSize renderTargetSize(const QSize &surfaceSize) const;
|
||||
QImage readFramebuffer(const QRect &rect);
|
||||
void blitFramebuffer(Qt3DCore::QNodeId outputRenderTargetId, Qt3DCore::QNodeId inputRenderTargetId,
|
||||
|
|
|
|||
|
|
@ -1397,6 +1397,13 @@ void Renderer::updateGLResources()
|
|||
|
||||
// Record list of buffer that might need uploading
|
||||
lookForDownloadableBuffers();
|
||||
|
||||
// Remove destroyed FBOs
|
||||
{
|
||||
const QNodeIdVector destroyedRenderTargetIds = m_nodesManager->renderTargetManager()->takeRenderTargetIdsToCleanup();
|
||||
for (const Qt3DCore::QNodeId &renderTargetId : destroyedRenderTargetIds)
|
||||
m_submissionContext->releaseRenderTarget(renderTargetId);
|
||||
}
|
||||
}
|
||||
|
||||
// Render Thread
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include <Qt3DRender/qrendertargetoutput.h>
|
||||
#include <Qt3DRender/private/qrendertarget_p.h>
|
||||
#include <Qt3DRender/private/rendertarget_p.h>
|
||||
#include <Qt3DRender/private/managers_p.h>
|
||||
#include "qbackendnodetester.h"
|
||||
#include "testrenderer.h"
|
||||
|
||||
|
|
@ -205,6 +206,47 @@ private Q_SLOTS:
|
|||
}
|
||||
}
|
||||
|
||||
void checkRenderTargetManager()
|
||||
{
|
||||
// GIVEN
|
||||
Qt3DRender::QRenderTarget renderTarget;
|
||||
TestRenderer renderer;
|
||||
Qt3DRender::Render::RenderTargetManager manager;
|
||||
Qt3DRender::Render::RenderTargetFunctor creationFunctor(&renderer, &manager);
|
||||
|
||||
// THEN
|
||||
QVERIFY(manager.renderTargetIdsToCleanup().isEmpty());
|
||||
|
||||
// WHEN
|
||||
Qt3DCore::QNodeCreatedChangeBase changeObj(&renderTarget);
|
||||
Qt3DCore::QNodeCreatedChangeBasePtr changePtr(&changeObj, [](Qt3DCore::QNodeCreatedChangeBase *) {});
|
||||
auto backend = creationFunctor.create(changePtr);
|
||||
|
||||
// THEN
|
||||
QVERIFY(backend != nullptr);
|
||||
QVERIFY(manager.renderTargetIdsToCleanup().isEmpty());
|
||||
|
||||
{
|
||||
// WHEN
|
||||
auto sameBackend = creationFunctor.get(renderTarget.id());
|
||||
// THEN
|
||||
QCOMPARE(backend, sameBackend);
|
||||
}
|
||||
|
||||
// WHEN
|
||||
creationFunctor.destroy(renderTarget.id());
|
||||
|
||||
// THEN -> Should be in list of ids to remove and return null on get
|
||||
QVERIFY(manager.renderTargetIdsToCleanup().contains(renderTarget.id()));
|
||||
QVERIFY(creationFunctor.get(renderTarget.id()) == nullptr);
|
||||
|
||||
// WHEN -> Should be removed from list of ids to remove
|
||||
creationFunctor.create(changePtr);
|
||||
|
||||
// THEN
|
||||
QVERIFY(manager.renderTargetIdsToCleanup().isEmpty());
|
||||
QVERIFY(creationFunctor.get(renderTarget.id()) != nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_MAIN(tst_RenderTarget)
|
||||
|
|
|
|||
Loading…
Reference in New Issue