summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Lemire <paul.lemire@kdab.com>2018-03-02 10:58:46 +0100
committerPaul Lemire <paul.lemire@kdab.com>2018-03-16 11:21:07 +0000
commit00b7e4b76ab0454178a7f6412100152cc52d0581 (patch)
tree43f3486a16a58378a2b069d68e31a27d3370a0c0
parentc1b495f70c3b4f0c23d44dfcd99aed5882312100 (diff)
Perform Shader loading within frame
- CommandThread has been improved to not use an exec loop and properly instantiate its own GL context + GraphicsContext that is bound to an offscreen surface - The dirtyShaderGathering job has been renamed and now performs the loading of shaders and their introspection. It is also run before the materiaparameter gathering, so that these jobs and the following can assume a shader is ready Change-Id: I6d99b3a104bd96530dc45f4b05d3aaac09d2d077 Reviewed-by: Mike Krus <mike.krus@kdab.com> Reviewed-by: Svenn-Arne Dragly <svenn-arne.dragly@qt.io> Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
-rw-r--r--src/render/backend/commandthread.cpp108
-rw-r--r--src/render/backend/commandthread_p.h28
-rw-r--r--src/render/backend/glcommands.cpp67
-rw-r--r--src/render/backend/glcommands_p.h89
-rw-r--r--src/render/backend/render-backend.pri6
-rw-r--r--src/render/backend/renderer.cpp36
-rw-r--r--src/render/backend/renderer_p.h8
-rw-r--r--src/render/backend/renderview.cpp4
-rw-r--r--src/render/backend/renderviewbuilder.cpp3
-rw-r--r--src/render/graphicshelpers/graphicscontext.cpp14
-rw-r--r--tests/auto/render/renderviewbuilder/tst_renderviewbuilder.cpp7
11 files changed, 307 insertions, 63 deletions
diff --git a/src/render/backend/commandthread.cpp b/src/render/backend/commandthread.cpp
index 9e764f0dd..387fc1113 100644
--- a/src/render/backend/commandthread.cpp
+++ b/src/render/backend/commandthread.cpp
@@ -38,7 +38,13 @@
****************************************************************************/
#include "commandthread_p.h"
+#include <Qt3DRender/private/glcommands_p.h>
+#include <Qt3DRender/private/offscreensurfacehelper_p.h>
+#include <Qt3DRender/private/graphicscontext_p.h>
+#include <Qt3DRender/private/shadercache_p.h>
#include <QOpenGLContext>
+#include <QOffscreenSurface>
+#include <QDebug>
QT_BEGIN_NAMESPACE
@@ -51,6 +57,13 @@ CommandThread::CommandThread(Renderer *renderer)
, m_renderer(renderer)
, m_waitForStartSemaphore(0)
, m_initializedSemaphore(0)
+ , m_commandRequestedSemaphore(0)
+ , m_commandExecutionSemaphore(0)
+ , m_mainContext(nullptr)
+ , m_shaderCache(nullptr)
+ , m_offsreenSurfaceHelper(nullptr)
+ , m_currentCommand(nullptr)
+ , m_running(0)
{
}
@@ -58,8 +71,13 @@ CommandThread::~CommandThread()
{
}
+void CommandThread::setShaderCache(ShaderCache *shaderCache)
+{
+ m_shaderCache = shaderCache;
+}
+
// Called by RenderThread or MainThread (Scene3d)
-void CommandThread::initialize(QOpenGLContext *mainContext)
+void CommandThread::initialize(QOpenGLContext *mainContext, OffscreenSurfaceHelper *offsreenSurfaceHelper)
{
// Start the thread
start();
@@ -68,36 +86,58 @@ void CommandThread::initialize(QOpenGLContext *mainContext)
m_waitForStartSemaphore.acquire();
m_mainContext = mainContext;
- Q_ASSERT(m_mainContext);
+ m_offsreenSurfaceHelper = offsreenSurfaceHelper;
+ Q_ASSERT(m_mainContext && offsreenSurfaceHelper);
+ m_running.fetchAndStoreOrdered(1);
// Allow thread to proceed
m_initializedSemaphore.release();
}
-// Called by RenderThread of MainThread (Scene3D)
+// Called by RenderThread or MainThread (Scene3D)
void CommandThread::shutdown()
{
- // Tell thread to exit event loop
- QThread::quit();
+ m_running.fetchAndStoreOrdered(0);
+
+ // Unblock thread
+ m_commandRequestedSemaphore.release(1);
// Wait for thread to exit
wait();
// Reset semaphores (in case we ever want to restart)
- m_waitForStartSemaphore.release(m_waitForStartSemaphore.available());
- m_initializedSemaphore.release(m_initializedSemaphore.available());
+ m_waitForStartSemaphore.acquire(m_waitForStartSemaphore.available());
+ m_initializedSemaphore.acquire(m_initializedSemaphore.available());
+ m_commandRequestedSemaphore.acquire(m_commandRequestedSemaphore.available());
+ m_commandExecutionSemaphore.acquire(m_commandExecutionSemaphore.available());
m_localContext.reset();
}
// Any thread can call this, this is a blocking command
-void CommandThread::executeCommand(Command *command)
+void CommandThread::executeCommand(GLCommand *command)
{
if (!isRunning())
return;
- QMetaObject::invokeMethod(this,
- "executeCommandInternal",
- Qt::BlockingQueuedConnection,
- Q_ARG(Command*, command));
+
+ // We lock to prevent any other call to executeCommand to be executed
+ // before we have received the result of our command
+ m_blockingCallerMutex.lock();
+
+ // Store command to be executed
+ m_currentCommand = command;
+
+ // Allow thread to proceed and execute command
+ m_commandRequestedSemaphore.release();
+
+ // Wait for thread to be done
+ m_commandExecutionSemaphore.acquire();
+
+ // Reset command
+ m_currentCommand = nullptr;
+
+ // Unlock blocking semaphore so that other calls to executeCommand
+ // can proceed
+ m_blockingCallerMutex.unlock();
}
void CommandThread::run()
@@ -108,18 +148,44 @@ void CommandThread::run()
// Wait for initialize to be completed
m_initializedSemaphore.acquire();
+ Q_ASSERT(m_mainContext && m_shaderCache);
+
// Initialize shared context and resources for the thread
m_localContext.reset(new QOpenGLContext());
m_localContext->setShareContext(m_mainContext);
-
- // Launch exec loop
- QThread::exec();
-}
-
-// Executed in the Command Thread
-void CommandThread::executeCommandInternal(Command *command)
-{
- command->execute(m_renderer, m_localContext.data());
+ m_localContext->create();
+
+ // Initialize GraphicsContext
+ m_graphicsContext.reset(new GraphicsContext());
+ m_graphicsContext->setShaderCache(m_shaderCache);
+ m_graphicsContext->setOpenGLContext(m_localContext.data());
+
+ bool initialized = false;
+ while (true) {
+
+ // Wait for command
+ m_commandRequestedSemaphore.acquire();
+
+ // Are we still running?
+ if (!m_running.load()) {
+ m_graphicsContext->doneCurrent();
+ // to prevent executeCommand being locked
+ m_commandExecutionSemaphore.release();
+ break;
+ }
+
+ if (Q_UNLIKELY(!initialized)) {
+ QOffscreenSurface *offscreenSurface = m_offsreenSurfaceHelper->offscreenSurface();
+ Q_ASSERT(offscreenSurface);
+ m_graphicsContext->makeCurrent(offscreenSurface);
+ initialized = true;
+ }
+
+ m_currentCommand->execute(m_renderer, m_graphicsContext.data());
+
+ // Allow caller to proceed as we are done with the command
+ m_commandExecutionSemaphore.release();
+ }
}
} // Render
diff --git a/src/render/backend/commandthread_p.h b/src/render/backend/commandthread_p.h
index a87d13a2e..0508675c4 100644
--- a/src/render/backend/commandthread_p.h
+++ b/src/render/backend/commandthread_p.h
@@ -53,6 +53,7 @@
#include <QtCore/QThread>
#include <QtCore/QSemaphore>
+#include <QtCore/QMutex>
QT_BEGIN_NAMESPACE
@@ -63,12 +64,10 @@ namespace Qt3DRender {
namespace Render {
class Renderer;
-
-class Command
-{
-public:
- virtual void execute(Renderer *renderer, QOpenGLContext *localContext) = 0;
-};
+class GLCommand;
+class OffscreenSurfaceHelper;
+class GraphicsContext;
+class ShaderCache;
class CommandThread : public QThread
{
@@ -79,21 +78,32 @@ public:
Render::Renderer* renderer() const { return m_renderer; }
- void initialize(QOpenGLContext *mainContext);
+ void setShaderCache(ShaderCache *shaderCache);
+ ShaderCache *shaderCache() const { return m_shaderCache; }
+
+ void initialize(QOpenGLContext *mainContext, OffscreenSurfaceHelper *offsreenSurfaceHelper);
void shutdown();
- void executeCommand(Command *command);
+ void executeCommand(GLCommand *command);
private:
void run() override;
- Q_INVOKABLE void executeCommandInternal(Command *command);
+ void executeCommandInternal(Qt3DRender::Render::GLCommand *command);
private:
Renderer* m_renderer;
QSemaphore m_waitForStartSemaphore;
QSemaphore m_initializedSemaphore;
+ QSemaphore m_commandRequestedSemaphore;
+ QSemaphore m_commandExecutionSemaphore;
+ QMutex m_blockingCallerMutex;
QOpenGLContext *m_mainContext;
+ ShaderCache *m_shaderCache;
+ OffscreenSurfaceHelper *m_offsreenSurfaceHelper;
QScopedPointer<QOpenGLContext> m_localContext;
+ QScopedPointer<GraphicsContext> m_graphicsContext;
+ GLCommand *m_currentCommand;
+ QAtomicInt m_running;
};
} // Render
diff --git a/src/render/backend/glcommands.cpp b/src/render/backend/glcommands.cpp
new file mode 100644
index 000000000..fd7ee9fe8
--- /dev/null
+++ b/src/render/backend/glcommands.cpp
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "glcommands_p.h"
+#include <Qt3DRender/private/renderer_p.h>
+#include <Qt3DRender/private/graphicscontext_p.h>
+#include <Qt3DRender/private/nodemanagers_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace Qt3DRender {
+
+namespace Render {
+
+LoadShaderCommand::LoadShaderCommand(Shader *shader)
+ : m_shader(shader)
+{
+ Q_ASSERT(m_shader);
+}
+
+void LoadShaderCommand::execute(Renderer *renderer, GraphicsContext *ctx)
+{
+ NodeManagers *nodeManagers = renderer->nodeManagers();
+ ctx->loadShader(m_shader, nodeManagers->shaderManager());
+}
+
+} // Render
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
diff --git a/src/render/backend/glcommands_p.h b/src/render/backend/glcommands_p.h
new file mode 100644
index 000000000..5ed360759
--- /dev/null
+++ b/src/render/backend/glcommands_p.h
@@ -0,0 +1,89 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt3D module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QT3DRENDER_RENDER_GLCOMMANDS_P_H
+#define QT3DRENDER_RENDER_GLCOMMANDS_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <Qt3DRender/qt3drender_global.h>
+
+QT_BEGIN_NAMESPACE
+
+
+namespace Qt3DRender {
+
+namespace Render {
+
+class GraphicsContext;
+class Renderer;
+class Shader;
+
+class GLCommand
+{
+public:
+ virtual void execute(Renderer *renderer, GraphicsContext *ctx) = 0;
+};
+
+class Q_AUTOTEST_EXPORT LoadShaderCommand : public GLCommand
+{
+public:
+ explicit LoadShaderCommand(Shader *shader);
+ Shader *shader() const { return m_shader; }
+ void execute(Renderer *renderer, GraphicsContext *ctx) Q_DECL_OVERRIDE;
+
+private:
+ Shader *m_shader = nullptr;
+};
+} // Render
+
+} // Qt3DRender
+
+QT_END_NAMESPACE
+
+#endif // QT3DRENDER_RENDER_GLCOMMANDS_P_H
diff --git a/src/render/backend/render-backend.pri b/src/render/backend/render-backend.pri
index f7f30b5c9..cde9e77b9 100644
--- a/src/render/backend/render-backend.pri
+++ b/src/render/backend/render-backend.pri
@@ -45,7 +45,8 @@ HEADERS += \
$$PWD/visitorutils_p.h \
$$PWD/segmentsvisitor_p.h \
$$PWD/pointsvisitor_p.h \
- $$PWD/renderercache_p.h
+ $$PWD/renderercache_p.h \
+ $$PWD/glcommands_p.h
SOURCES += \
$$PWD/renderthread.cpp \
@@ -82,7 +83,8 @@ SOURCES += \
$$PWD/resourceaccessor.cpp \
$$PWD/segmentsvisitor.cpp \
$$PWD/commandthread.cpp \
- $$PWD/pointsvisitor.cpp
+ $$PWD/pointsvisitor.cpp \
+ $$PWD/glcommands.cpp
include($$QT3D_BUILD_ROOT/src/core/qt3dcore-config.pri)
QT_FOR_CONFIG += 3dcore-private
diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp
index cdec9af01..2611fb6cc 100644
--- a/src/render/backend/renderer.cpp
+++ b/src/render/backend/renderer.cpp
@@ -90,6 +90,7 @@
#include <Qt3DRender/private/offscreensurfacehelper_p.h>
#include <Qt3DRender/private/renderviewbuilder_p.h>
#include <Qt3DRender/private/commandthread_p.h>
+#include <Qt3DRender/private/glcommands_p.h>
#include <Qt3DRender/qcameralens.h>
#include <Qt3DCore/private/qeventfilterservice_p.h>
@@ -188,7 +189,7 @@ Renderer::Renderer(QRenderAspect::RenderType type)
, 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_introspectShaderJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([this] { reloadDirtyShaders(); }, JobTypes::DirtyShaderGathering))
, m_syncTextureLoadingJob(Render::GenericLambdaJobPtr<std::function<void ()>>::create([] {}, JobTypes::SyncTextureLoading))
, m_ownedContext(false)
, m_offscreenHelper(nullptr)
@@ -223,7 +224,7 @@ Renderer::Renderer(QRenderAspect::RenderType type)
m_pickBoundingVolumeJob->addDependency(m_updateMeshTriangleListJob);
m_rayCastingJob->addDependency(m_updateMeshTriangleListJob);
- m_shaderGathererJob->addDependency(m_filterCompatibleTechniqueJob);
+ m_introspectShaderJob->addDependency(m_filterCompatibleTechniqueJob);
m_filterCompatibleTechniqueJob->setRenderer(this);
@@ -321,9 +322,12 @@ QOpenGLContext *Renderer::shareContext() const
: nullptr);
}
+// Executed in the command thread
void Renderer::loadShader(Shader *shader) const
{
- Q_UNUSED(shader);
+ Profiling::GLTimeRecorder recorder(Profiling::ShaderUpload);
+ LoadShaderCommand cmd(shader);
+ m_commandThread->executeCommand(&cmd);
}
void Renderer::setOpenGLContext(QOpenGLContext *context)
@@ -380,6 +384,7 @@ void Renderer::initialize()
// Set shader cache on submission context and command thread
m_submissionContext->setShaderCache(m_shaderCache);
+ m_commandThread->setShaderCache(m_shaderCache);
// Note: we don't have a surface at this point
// The context will be made current later on (at render time)
@@ -392,6 +397,13 @@ void Renderer::initialize()
// (MS Windows), an offscreen surface is just a hidden QWindow.
m_format = ctx->format();
QMetaObject::invokeMethod(m_offscreenHelper, "createOffscreenSurface");
+
+ // Initialize command thread (uses the offscreen surface to make its own ctx current)
+ m_commandThread->initialize(ctx, m_offscreenHelper);
+ // Note: the offscreen surface is also used at shutdown time to release resources
+ // of the submission gl context (when the window is already gone).
+ // By that time (in releaseGraphicResources), the commandThread has been destroyed
+ // and the offscreenSurface can be reused
}
// Awake setScenegraphRoot in case it was waiting
@@ -1037,7 +1049,7 @@ void Renderer::lookForDirtyTextures()
}
// Executed in a job
-void Renderer::lookForDirtyShaders()
+void Renderer::reloadDirtyShaders()
{
Q_ASSERT(isRunning());
const QVector<HTechnique> activeTechniques = m_nodesManager->techniqueManager()->activeHandles();
@@ -1102,8 +1114,9 @@ void Renderer::lookForDirtyShaders()
if (Q_UNLIKELY(shader->hasPendingNotifications()))
shader->submitPendingNotifications();
+ // If the shader hasn't be loaded, load it
if (shader != nullptr && !shader->isLoaded())
- m_dirtyShaders.push_back(shaderHandle);
+ loadShader(shader);
}
}
}
@@ -1128,17 +1141,6 @@ void Renderer::updateGLResources()
}
{
- Profiling::GLTimeRecorder recorder(Profiling::ShaderUpload);
- const QVector<HShader> dirtyShaderHandles = std::move(m_dirtyShaders);
- ShaderManager *shaderManager = m_nodesManager->shaderManager();
- for (const HShader &handle: dirtyShaderHandles) {
- Shader *shader = shaderManager->data(handle);
- // Compile shader
- m_submissionContext->loadShader(shader, shaderManager);
- }
- }
-
- {
Profiling::GLTimeRecorder recorder(Profiling::TextureUpload);
const QVector<HTexture> activeTextureHandles = std::move(m_dirtyTextures);
for (const HTexture &handle: activeTextureHandles) {
@@ -1624,7 +1626,7 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
if (dirtyBitsForFrame & AbstractRenderer::TechniquesDirty )
renderBinJobs.push_back(m_filterCompatibleTechniqueJob);
if (dirtyBitsForFrame & AbstractRenderer::ShadersDirty)
- renderBinJobs.push_back(m_shaderGathererJob);
+ renderBinJobs.push_back(m_introspectShaderJob);
} else {
notCleared |= AbstractRenderer::TechniquesDirty;
notCleared |= AbstractRenderer::ShadersDirty;
diff --git a/src/render/backend/renderer_p.h b/src/render/backend/renderer_p.h
index d174fa428..b4ad0b0fe 100644
--- a/src/render/backend/renderer_p.h
+++ b/src/render/backend/renderer_p.h
@@ -148,6 +148,7 @@ class UpdateLevelOfDetailJob;
typedef QSharedPointer<UpdateLevelOfDetailJob> UpdateLevelOfDetailJobPtr;
using SynchronizerJobPtr = GenericLambdaJobPtr<std::function<void()>>;
+using IntrospectShadersJobPtr = GenericLambdaJobPtr<std::function<void()>>;
class QT3DRENDERSHARED_PRIVATE_EXPORT Renderer : public AbstractRenderer
{
@@ -211,7 +212,7 @@ public:
inline FilterCompatibleTechniqueJobPtr filterCompatibleTechniqueJob() const { return m_filterCompatibleTechniqueJob; }
inline SynchronizerJobPtr textureLoadSyncJob() const { return m_syncTextureLoadingJob; }
inline UpdateSkinningPaletteJobPtr updateSkinningPaletteJob() const { return m_updateSkinningPaletteJob; }
- inline Qt3DCore::QAspectJobPtr shaderGathererJob() const { return m_shaderGathererJob; }
+ inline IntrospectShadersJobPtr introspectShadersJob() const { return m_introspectShaderJob; }
inline Qt3DCore::QAspectJobPtr bufferGathererJob() const { return m_bufferGathererJob; }
inline Qt3DCore::QAspectJobPtr textureGathererJob() const { return m_textureGathererJob; }
@@ -365,7 +366,7 @@ private:
GenericLambdaJobPtr<std::function<void ()>> m_bufferGathererJob;
GenericLambdaJobPtr<std::function<void ()>> m_vaoGathererJob;
GenericLambdaJobPtr<std::function<void ()>> m_textureGathererJob;
- GenericLambdaJobPtr<std::function<void ()>> m_shaderGathererJob;
+ IntrospectShadersJobPtr m_introspectShaderJob;
SynchronizerJobPtr m_syncTextureLoadingJob;
@@ -373,14 +374,13 @@ private:
void lookForDirtyBuffers();
void lookForDownloadableBuffers();
void lookForDirtyTextures();
- void lookForDirtyShaders();
+ void reloadDirtyShaders();
QMutex m_abandonedVaosMutex;
QVector<HVao> m_abandonedVaos;
QVector<HBuffer> m_dirtyBuffers;
QVector<HBuffer> m_downloadableBuffers;
- QVector<HShader> m_dirtyShaders;
QVector<HTexture> m_dirtyTextures;
bool m_ownedContext;
diff --git a/src/render/backend/renderview.cpp b/src/render/backend/renderview.cpp
index 8a45e1fa9..c29448570 100644
--- a/src/render/backend/renderview.cpp
+++ b/src/render/backend/renderview.cpp
@@ -934,8 +934,8 @@ void RenderView::setShaderAndUniforms(RenderCommand *command,
if (rPass != nullptr) {
// Index Shader by Shader UUID
command->m_shader = m_manager->lookupHandle<Shader, ShaderManager, HShader>(rPass->shaderProgram());
- Shader *shader = nullptr;
- if ((shader = m_manager->data<Shader, ShaderManager>(command->m_shader)) != nullptr) {
+ Shader *shader = m_manager->data<Shader, ShaderManager>(command->m_shader);
+ if (shader != nullptr && shader->isLoaded()) {
command->m_shaderDna = shader->dna();
// Builds the QUniformPack, sets shader standard uniforms and store attributes name / glname bindings
diff --git a/src/render/backend/renderviewbuilder.cpp b/src/render/backend/renderviewbuilder.cpp
index 2fd8e4acf..d08bd6dd4 100644
--- a/src/render/backend/renderviewbuilder.cpp
+++ b/src/render/backend/renderviewbuilder.cpp
@@ -559,7 +559,7 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const
// Ensure the RenderThread won't be able to process dirtyResources
// before they have been completely gathered
- m_syncRenderCommandBuildingJob->addDependency(m_renderer->shaderGathererJob());
+ m_syncRenderCommandBuildingJob->addDependency(m_renderer->introspectShadersJob());
m_syncRenderCommandBuildingJob->addDependency(m_renderer->bufferGathererJob());
m_syncRenderCommandBuildingJob->addDependency(m_renderer->textureGathererJob());
@@ -598,6 +598,7 @@ QVector<Qt3DCore::QAspectJobPtr> RenderViewBuilder::buildJobHierachy() const
if (m_materialGathererCacheNeedsToBeRebuilt) {
for (const auto &materialGatherer : qAsConst(m_materialGathererJobs)) {
materialGatherer->addDependency(m_syncRenderViewInitializationJob);
+ materialGatherer->addDependency(m_renderer->introspectShadersJob());
materialGatherer->addDependency(m_renderer->filterCompatibleTechniqueJob());
jobs.push_back(materialGatherer); // Step3
m_syncMaterialGathererJob->addDependency(materialGatherer);
diff --git a/src/render/graphicshelpers/graphicscontext.cpp b/src/render/graphicshelpers/graphicscontext.cpp
index ddd7281d1..c2ec3db59 100644
--- a/src/render/graphicshelpers/graphicscontext.cpp
+++ b/src/render/graphicshelpers/graphicscontext.cpp
@@ -213,8 +213,10 @@ void GraphicsContext::doneCurrent()
{
Q_ASSERT(m_gl);
m_gl->doneCurrent();
+ m_glHelper = nullptr;
}
+// Called by GL Command Thread
QOpenGLShaderProgram *GraphicsContext::createShaderProgram(Shader *shaderNode)
{
QScopedPointer<QOpenGLShaderProgram> shaderProgram(new QOpenGLShaderProgram);
@@ -249,17 +251,21 @@ QOpenGLShaderProgram *GraphicsContext::createShaderProgram(Shader *shaderNode)
return shaderProgram.take();
}
+// Called by GL Command Thread (can't use global glHelpers)
// That assumes that the shaderProgram in Shader stays the same
void GraphicsContext::introspectShaderInterface(Shader *shader, QOpenGLShaderProgram *shaderProgram)
{
- shader->initializeUniforms(m_glHelper->programUniformsAndLocations(shaderProgram->programId()));
- shader->initializeAttributes(m_glHelper->programAttributesAndLocations(shaderProgram->programId()));
+ GraphicsHelperInterface *glHelper = resolveHighestOpenGLFunctions();
+ shader->initializeUniforms(glHelper->programUniformsAndLocations(shaderProgram->programId()));
+ shader->initializeAttributes(glHelper->programAttributesAndLocations(shaderProgram->programId()));
if (m_glHelper->supportsFeature(GraphicsHelperInterface::UniformBufferObject))
- shader->initializeUniformBlocks(m_glHelper->programUniformBlocks(shaderProgram->programId()));
+ shader->initializeUniformBlocks(glHelper->programUniformBlocks(shaderProgram->programId()));
if (m_glHelper->supportsFeature(GraphicsHelperInterface::ShaderStorageObject))
- shader->initializeShaderStorageBlocks(m_glHelper->programShaderStorageBlocks(shaderProgram->programId()));
+ shader->initializeShaderStorageBlocks(glHelper->programShaderStorageBlocks(shaderProgram->programId()));
}
+
+// Called by GL Command Thread
void GraphicsContext::loadShader(Shader *shader, ShaderManager *manager)
{
bool wasPresent = false;
diff --git a/tests/auto/render/renderviewbuilder/tst_renderviewbuilder.cpp b/tests/auto/render/renderviewbuilder/tst_renderviewbuilder.cpp
index c9bfd646a..14b304be6 100644
--- a/tests/auto/render/renderviewbuilder/tst_renderviewbuilder.cpp
+++ b/tests/auto/render/renderviewbuilder/tst_renderviewbuilder.cpp
@@ -296,7 +296,8 @@ private Q_SLOTS:
QVERIFY(renderViewBuilder.syncFrustumCullingJob()->dependencies().contains(testAspect.renderer()->updateShaderDataTransformJob()));
for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) {
- QCOMPARE(materialGatherer->dependencies().size(), 2);
+ QCOMPARE(materialGatherer->dependencies().size(), 3);
+ QVERIFY(materialGatherer->dependencies().contains(testAspect.renderer()->introspectShadersJob()));
QVERIFY(materialGatherer->dependencies().contains(renderViewBuilder.syncRenderViewInitializationJob()));
QVERIFY(materialGatherer->dependencies().contains(testAspect.renderer()->filterCompatibleTechniqueJob()));
}
@@ -314,7 +315,7 @@ private Q_SLOTS:
QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.filterProximityJob()));
QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.lightGathererJob()));
QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.frustumCullingJob()));
- QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(testAspect.renderer()->shaderGathererJob()));
+ QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(testAspect.renderer()->introspectShadersJob()));
QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(testAspect.renderer()->bufferGathererJob()));
QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(testAspect.renderer()->textureGathererJob()));
for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) {
@@ -390,7 +391,7 @@ private Q_SLOTS:
QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.lightGathererJob()));
QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.frustumCullingJob()));
QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(renderViewBuilder.filterProximityJob()));
- QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(testAspect.renderer()->shaderGathererJob()));
+ QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(testAspect.renderer()->introspectShadersJob()));
QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(testAspect.renderer()->bufferGathererJob()));
QVERIFY(renderViewBuilder.syncRenderCommandBuildingJob()->dependencies().contains(testAspect.renderer()->textureGathererJob()));
for (const auto materialGatherer : renderViewBuilder.materialGathererJobs()) {