diff options
author | Wieland Hagen <wieland.hagen@kdab.com> | 2017-02-01 15:38:38 +0700 |
---|---|---|
committer | Wieland Hagen <wieland.hagen@kdab.com> | 2017-02-01 09:29:11 +0000 |
commit | f1c21aaae49d0a356ecfab268994381932b6d327 (patch) | |
tree | 15b1343e9041723b647b49ff89111274475b5ef6 | |
parent | 0da1d0e6a93e9c1f745f5ff3b8d628a2de9b0fa3 (diff) |
Delete abandoned VAOs after each frame
Use a job to traverse all active VAO handles to check if the
geometry and shader objects used to identify the VAO do stil exist.
If not, let the renderer dispose the VAOs.
Make sure to synchronize access to VAO state and hide state changes
behind member functions.
Change-Id: Ib77be67d55daa61885cd914af8d9cfc622cae940
Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
-rw-r--r-- | src/render/backend/openglvertexarrayobject.cpp | 49 | ||||
-rw-r--r-- | src/render/backend/openglvertexarrayobject_p.h | 15 | ||||
-rw-r--r-- | src/render/backend/renderer.cpp | 46 | ||||
-rw-r--r-- | src/render/backend/renderer_p.h | 5 | ||||
-rw-r--r-- | src/render/jobs/job_common_p.h | 1 |
5 files changed, 79 insertions, 37 deletions
diff --git a/src/render/backend/openglvertexarrayobject.cpp b/src/render/backend/openglvertexarrayobject.cpp index 30f79c466..b88ddfb7b 100644 --- a/src/render/backend/openglvertexarrayobject.cpp +++ b/src/render/backend/openglvertexarrayobject.cpp @@ -52,15 +52,8 @@ OpenGLVertexArrayObject::OpenGLVertexArrayObject() : m_ctx(nullptr) , m_specified(false) , m_supportsVao(false) - , m_createdEmulatedVAO(false) {} -void OpenGLVertexArrayObject::setGraphicsContext(GraphicsContext *ctx) -{ - m_ctx = ctx; - m_supportsVao = m_ctx->supportsVAO(); -} - void OpenGLVertexArrayObject::bind() { Q_ASSERT(m_ctx); @@ -99,19 +92,25 @@ void OpenGLVertexArrayObject::release() } } -void OpenGLVertexArrayObject::create() +// called from Render thread +void OpenGLVertexArrayObject::create(GraphicsContext *ctx, const VAOIdentifier &key) { - Q_ASSERT(m_ctx); - if (m_supportsVao) { - Q_ASSERT(!m_vao.isNull()); - m_vao->create(); - } else { - m_createdEmulatedVAO = true; - } + QMutexLocker lock(&m_mutex); + + Q_ASSERT(!m_ctx && !m_vao); + + m_ctx = ctx; + m_supportsVao = m_ctx->supportsVAO(); + m_vao.reset(m_supportsVao ? new QOpenGLVertexArrayObject() : nullptr); + m_vao->create(); + m_owners = key; } +// called from Render thread void OpenGLVertexArrayObject::destroy() { + QMutexLocker locker(&m_mutex); + Q_ASSERT(m_ctx); cleanup(); } @@ -122,20 +121,22 @@ void OpenGLVertexArrayObject::cleanup() m_ctx = nullptr; m_specified = false; m_supportsVao = false; - m_createdEmulatedVAO = false; m_indexAttribute = GraphicsContext::VAOIndexAttribute(); m_vertexAttributes.clear(); } - -bool OpenGLVertexArrayObject::isCreated() const +// called from job +bool OpenGLVertexArrayObject::isAbandoned(GeometryManager *geomMgr, ShaderManager *shaderMgr) { - if (m_supportsVao) { - Q_ASSERT(!m_vao.isNull()); - return m_vao->isCreated(); - } else { - return m_createdEmulatedVAO; - } + QMutexLocker lock(&m_mutex); + + if (!m_ctx) + return false; + + const bool geometryExists = (geomMgr->data(m_owners.first) != nullptr); + const bool shaderExists = (shaderMgr->data(m_owners.second) != nullptr); + + return !geometryExists || !shaderExists; } void OpenGLVertexArrayObject::saveVertexAttribute(const GraphicsContext::VAOVertexAttribute &attr) diff --git a/src/render/backend/openglvertexarrayobject_p.h b/src/render/backend/openglvertexarrayobject_p.h index 6d8eecec8..a564175f6 100644 --- a/src/render/backend/openglvertexarrayobject_p.h +++ b/src/render/backend/openglvertexarrayobject_p.h @@ -59,6 +59,9 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { namespace Render { +class GeometryManager; +class ShaderManager; + typedef QPair<HGeometry, HShader> VAOIdentifier; class OpenGLVertexArrayObject @@ -66,27 +69,29 @@ class OpenGLVertexArrayObject public: OpenGLVertexArrayObject(); - void setGraphicsContext(GraphicsContext *ctx); void bind(); void release(); - void create(); + + void create(GraphicsContext *ctx, const VAOIdentifier &key); void destroy(); void cleanup(); - bool isCreated() const; + + bool isAbandoned(GeometryManager *geomMgr, ShaderManager *shaderMgr); QOpenGLVertexArrayObject *vao() { return m_vao.data(); } const QOpenGLVertexArrayObject *vao() const { return m_vao.data(); } - void setVao(QOpenGLVertexArrayObject *vao) { m_vao.reset(vao); } void setSpecified(bool b) { m_specified = b; } bool isSpecified() const { return m_specified; } + private: + QMutex m_mutex; GraphicsContext *m_ctx; QScopedPointer<QOpenGLVertexArrayObject> m_vao; bool m_specified; bool m_supportsVao; - bool m_createdEmulatedVAO; + VAOIdentifier m_owners; friend class GraphicsContext; diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp index d38df13e2..100c4a33d 100644 --- a/src/render/backend/renderer.cpp +++ b/src/render/backend/renderer.cpp @@ -170,6 +170,7 @@ Renderer::Renderer(QRenderAspect::RenderType type) , m_updateMeshTriangleListJob(Render::UpdateMeshTriangleListJobPtr::create()) , m_filterCompatibleTechniqueJob(Render::FilterCompatibleTechniqueJobPtr::create()) , m_bufferGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyBuffers(); }, JobTypes::DirtyBufferGathering)) + , m_vaoGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForAbandonedVaos(); }, JobTypes::DirtyVaoGathering)) , m_textureGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyTextures(); }, JobTypes::DirtyTextureGathering)) , m_shaderGathererJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { lookForDirtyShaders(); }, JobTypes::DirtyShaderGathering)) , m_syncTextureLoadingJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([] {}, JobTypes::SyncTextureLoading)) @@ -831,6 +832,23 @@ void Renderer::prepareCommandsSubmission(const QVector<RenderView *> &renderView } // Executed in a job +void Renderer::lookForAbandonedVaos() +{ + const QVector<HVao> activeVaos = m_nodesManager->vaoManager()->activeHandles(); + for (HVao handle : activeVaos) { + OpenGLVertexArrayObject *vao = m_nodesManager->vaoManager()->data(handle); + + // Make sure to only mark VAOs for deletion that were already created + // (ignore those that might be currently under construction in the render thread) + if (vao->isAbandoned(m_nodesManager->geometryManager(), m_nodesManager->shaderManager())) { + m_abandonedVaosMutex.lock(); + m_abandonedVaos.push_back(handle); + m_abandonedVaosMutex.unlock(); + } + } +} + +// Executed in a job void Renderer::lookForDirtyBuffers() { const QVector<HBuffer> activeBufferHandles = m_nodesManager->bufferManager()->activeHandles(); @@ -923,8 +941,6 @@ void Renderer::updateGLResources() // We can really release the texture at this point m_nodesManager->textureManager()->releaseResource(textureCleanedUpId); } - - } // Render Thread @@ -1267,6 +1283,7 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs() // Jobs to prepare GL Resource upload renderBinJobs.push_back(m_syncTextureLoadingJob); + renderBinJobs.push_back(m_vaoGathererJob); renderBinJobs.push_back(m_bufferGathererJob); renderBinJobs.push_back(m_textureGathererJob); renderBinJobs.push_back(m_shaderGathererJob); @@ -1368,16 +1385,15 @@ void Renderer::createOrUpdateVAO(RenderCommand *command, HVao *previousVaoHandle, OpenGLVertexArrayObject **vao) { + const VAOIdentifier vaoKey(command->m_geometry, command->m_shader); + VAOManager *vaoManager = m_nodesManager->vaoManager(); - command->m_vao = vaoManager->lookupHandle(QPair<HGeometry, HShader>(command->m_geometry, command->m_shader)); + command->m_vao = vaoManager->lookupHandle(vaoKey); if (command->m_vao.isNull()) { qCDebug(Rendering) << Q_FUNC_INFO << "Allocating new VAO"; - command->m_vao = vaoManager->getOrAcquireHandle(QPair<HGeometry, HShader>(command->m_geometry, command->m_shader)); - vaoManager->data(command->m_vao)->setGraphicsContext(m_graphicsContext.data()); - if (m_graphicsContext->supportsVAO()) - vaoManager->data(command->m_vao)->setVao(new QOpenGLVertexArrayObject()); - vaoManager->data(command->m_vao)->create(); + command->m_vao = vaoManager->getOrAcquireHandle(vaoKey); + vaoManager->data(command->m_vao)->create(m_graphicsContext.data(), vaoKey); } if (*previousVaoHandle != command->m_vao) { @@ -1573,6 +1589,20 @@ void Renderer::cleanGraphicsResources() tex->destroyGLTexture(); delete tex; } + + // Delete abandoned VAOs + m_abandonedVaosMutex.lock(); + const QVector<HVao> abandonedVaos = std::move(m_abandonedVaos); + m_abandonedVaosMutex.unlock(); + for (HVao vaoHandle : abandonedVaos) { + // might have already been destroyed last frame, but added by the cleanup job before, so + // check if the VAO is really still existent + OpenGLVertexArrayObject *vao = m_nodesManager->vaoManager()->data(vaoHandle); + if (vao) { + vao->destroy(); + m_nodesManager->vaoManager()->release(vaoHandle); + } + } } QList<QMouseEvent> Renderer::pendingPickingEvents() const diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h index 9f6e8d857..bd12ecec6 100644 --- a/src/render/backend/renderer_p.h +++ b/src/render/backend/renderer_p.h @@ -322,15 +322,20 @@ private: OpenGLVertexArrayObject **vao); GenericLambdaJobPtr<std::function<void ()>> m_bufferGathererJob; + GenericLambdaJobPtr<std::function<void ()>> m_vaoGathererJob; GenericLambdaJobPtr<std::function<void ()>> m_textureGathererJob; GenericLambdaJobPtr<std::function<void ()>> m_shaderGathererJob; SynchronizerJobPtr m_syncTextureLoadingJob; + void lookForAbandonedVaos(); void lookForDirtyBuffers(); void lookForDirtyTextures(); void lookForDirtyShaders(); + QMutex m_abandonedVaosMutex; + QVector<HVao> m_abandonedVaos; + QVector<HBuffer> m_dirtyBuffers; QVector<HShader> m_dirtyShaders; QVector<HTexture> m_dirtyTextures; diff --git a/src/render/jobs/job_common_p.h b/src/render/jobs/job_common_p.h index f3be2e6b0..4c3a6a6c0 100644 --- a/src/render/jobs/job_common_p.h +++ b/src/render/jobs/job_common_p.h @@ -86,6 +86,7 @@ namespace JobTypes { UpdateWorldBoundingVolume, FrameSubmissionPart2, DirtyBufferGathering, + DirtyVaoGathering, DirtyTextureGathering, DirtyShaderGathering, SendRenderCapture, |