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>
This commit is contained in:
Paul Lemire 2018-03-02 10:58:46 +01:00
parent c1b495f70c
commit 00b7e4b76a
11 changed files with 305 additions and 61 deletions

View File

@ -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);
m_localContext->create();
// Launch exec loop
QThread::exec();
}
// Initialize GraphicsContext
m_graphicsContext.reset(new GraphicsContext());
m_graphicsContext->setShaderCache(m_shaderCache);
m_graphicsContext->setOpenGLContext(m_localContext.data());
// Executed in the Command Thread
void CommandThread::executeCommandInternal(Command *command)
{
command->execute(m_renderer, 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}
}
}
@ -1127,17 +1140,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);
@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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()) {