summaryrefslogtreecommitdiffstats
path: root/src/render/backend/renderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/render/backend/renderer.cpp')
-rw-r--r--src/render/backend/renderer.cpp279
1 files changed, 143 insertions, 136 deletions
diff --git a/src/render/backend/renderer.cpp b/src/render/backend/renderer.cpp
index 70daa9904..bb0585e6f 100644
--- a/src/render/backend/renderer.cpp
+++ b/src/render/backend/renderer.cpp
@@ -162,7 +162,6 @@ Renderer::Renderer(QRenderAspect::RenderType type)
, m_waitForInitializationToBeCompleted(0)
, m_pickEventFilter(new PickEventFilter())
, m_exposed(0)
- , m_changeSet(0)
, m_lastFrameCorrect(0)
, m_glContext(nullptr)
, m_shareContext(nullptr)
@@ -207,6 +206,7 @@ Renderer::Renderer(QRenderAspect::RenderType type)
m_updateWorldBoundingVolumeJob->addDependency(m_calculateBoundingVolumeJob);
m_expandBoundingVolumeJob->addDependency(m_updateWorldBoundingVolumeJob);
m_updateShaderDataTransformJob->addDependency(m_worldTransformJob);
+ m_pickBoundingVolumeJob->addDependency(m_expandBoundingVolumeJob);
// Dirty texture gathering depends on m_syncTextureLoadingJob
// m_syncTextureLoadingJob will depend on the texture loading jobs
@@ -220,6 +220,8 @@ Renderer::Renderer(QRenderAspect::RenderType type)
m_pickBoundingVolumeJob->addDependency(m_updateMeshTriangleListJob);
m_rayCastingJob->addDependency(m_updateMeshTriangleListJob);
+ m_shaderGathererJob->addDependency(m_filterCompatibleTechniqueJob);
+
m_filterCompatibleTechniqueJob->setRenderer(this);
m_defaultRenderStateSet = new RenderStateSet;
@@ -308,7 +310,11 @@ NodeManagers *Renderer::nodeManagers() const
*/
QOpenGLContext *Renderer::shareContext() const
{
- return m_shareContext ? m_shareContext : m_graphicsContext->openGLContext()->shareContext();
+ QMutexLocker lock(&m_shareContextMutex);
+ return m_shareContext ? m_shareContext
+ : (m_graphicsContext->openGLContext()
+ ? m_graphicsContext->openGLContext()->shareContext()
+ : nullptr);
}
void Renderer::setOpenGLContext(QOpenGLContext *context)
@@ -326,45 +332,48 @@ void Renderer::initialize()
QOpenGLContext* ctx = m_glContext;
- // If we are using our own context (not provided by QtQuick),
- // we need to create it
- if (!m_glContext) {
- ctx = new QOpenGLContext;
- ctx->setShareContext(qt_gl_global_share_context());
-
- // TO DO: Shouldn't we use the highest context available and trust
- // QOpenGLContext to fall back on the best lowest supported ?
- const QByteArray debugLoggingMode = qgetenv("QT3DRENDER_DEBUG_LOGGING");
+ {
+ QMutexLocker lock(&m_shareContextMutex);
+ // If we are using our own context (not provided by QtQuick),
+ // we need to create it
+ if (!m_glContext) {
+ ctx = new QOpenGLContext;
+ ctx->setShareContext(qt_gl_global_share_context());
+
+ // TO DO: Shouldn't we use the highest context available and trust
+ // QOpenGLContext to fall back on the best lowest supported ?
+ const QByteArray debugLoggingMode = qgetenv("QT3DRENDER_DEBUG_LOGGING");
+
+ if (!debugLoggingMode.isEmpty()) {
+ QSurfaceFormat sf = ctx->format();
+ sf.setOption(QSurfaceFormat::DebugContext);
+ ctx->setFormat(sf);
+ }
- if (!debugLoggingMode.isEmpty()) {
- QSurfaceFormat sf = ctx->format();
- sf.setOption(QSurfaceFormat::DebugContext);
- ctx->setFormat(sf);
+ // Create OpenGL context
+ if (ctx->create())
+ qCDebug(Backend) << "OpenGL context created with actual format" << ctx->format();
+ else
+ qCWarning(Backend) << Q_FUNC_INFO << "OpenGL context creation failed";
+ m_ownedContext = true;
+ } else {
+ // Context is not owned by us, so we need to know if it gets destroyed
+ m_contextConnection = QObject::connect(m_glContext, &QOpenGLContext::aboutToBeDestroyed,
+ [this] { releaseGraphicsResources(); });
}
- // Create OpenGL context
- if (ctx->create())
- qCDebug(Backend) << "OpenGL context created with actual format" << ctx->format();
- else
- qCWarning(Backend) << Q_FUNC_INFO << "OpenGL context creation failed";
- m_ownedContext = true;
- } else {
- // Context is not owned by us, so we need to know if it gets destroyed
- m_contextConnection = QObject::connect(m_glContext, &QOpenGLContext::aboutToBeDestroyed,
- [this] { releaseGraphicsResources(); });
- }
+ if (!ctx->shareContext()) {
+ m_shareContext = new QOpenGLContext;
+ m_shareContext->setFormat(ctx->format());
+ m_shareContext->setShareContext(ctx);
+ m_shareContext->create();
+ }
- if (!ctx->shareContext()) {
- m_shareContext = new QOpenGLContext;
- m_shareContext->setFormat(ctx->format());
- m_shareContext->setShareContext(ctx);
- m_shareContext->create();
+ // Note: we don't have a surface at this point
+ // The context will be made current later on (at render time)
+ m_graphicsContext->setOpenGLContext(ctx);
}
- // Note: we don't have a surface at this point
- // The context will be made current later on (at render time)
- m_graphicsContext->setOpenGLContext(ctx);
-
// Store the format used by the context and queue up creating an
// offscreen surface in the main thread so that it is available
// for use when we want to shutdown the renderer. We need to create
@@ -518,7 +527,7 @@ void Renderer::setSceneRoot(QBackendNodeFactory *factory, Entity *sgRoot)
m_updateTreeEnabledJob->setRoot(m_renderSceneRoot);
// Set all flags to dirty
- m_changeSet |= AbstractRenderer::AllDirty;
+ m_dirtyBits.marked |= AbstractRenderer::AllDirty;
}
void Renderer::registerEventFilter(QEventFilterService *service)
@@ -1016,72 +1025,71 @@ void Renderer::lookForDirtyTextures()
// Executed in a job
void Renderer::lookForDirtyShaders()
{
- if (isRunning()) {
- const QVector<HTechnique> activeTechniques = m_nodesManager->techniqueManager()->activeHandles();
- const QVector<HShaderBuilder> activeBuilders = m_nodesManager->shaderBuilderManager()->activeHandles();
- for (const HTechnique &techniqueHandle : activeTechniques) {
- Technique *technique = m_nodesManager->techniqueManager()->data(techniqueHandle);
- // If api of the renderer matches the one from the technique
- if (technique->isCompatibleWithRenderer()) {
- const auto passIds = technique->renderPasses();
- for (const QNodeId passId : passIds) {
- RenderPass *renderPass = m_nodesManager->renderPassManager()->lookupResource(passId);
- HShader shaderHandle = m_nodesManager->shaderManager()->lookupHandle(renderPass->shaderProgram());
- Shader *shader = m_nodesManager->shaderManager()->data(shaderHandle);
-
- ShaderBuilder *shaderBuilder = nullptr;
- for (const HShaderBuilder &builderHandle : activeBuilders) {
- ShaderBuilder *builder = m_nodesManager->shaderBuilderManager()->data(builderHandle);
- if (builder->shaderProgramId() == shader->peerId()) {
- shaderBuilder = builder;
- break;
- }
+ Q_ASSERT(isRunning());
+ const QVector<HTechnique> activeTechniques = m_nodesManager->techniqueManager()->activeHandles();
+ const QVector<HShaderBuilder> activeBuilders = m_nodesManager->shaderBuilderManager()->activeHandles();
+ for (const HTechnique &techniqueHandle : activeTechniques) {
+ Technique *technique = m_nodesManager->techniqueManager()->data(techniqueHandle);
+ // If api of the renderer matches the one from the technique
+ if (technique->isCompatibleWithRenderer()) {
+ const auto passIds = technique->renderPasses();
+ for (const QNodeId passId : passIds) {
+ RenderPass *renderPass = m_nodesManager->renderPassManager()->lookupResource(passId);
+ HShader shaderHandle = m_nodesManager->shaderManager()->lookupHandle(renderPass->shaderProgram());
+ Shader *shader = m_nodesManager->shaderManager()->data(shaderHandle);
+
+ ShaderBuilder *shaderBuilder = nullptr;
+ for (const HShaderBuilder &builderHandle : activeBuilders) {
+ ShaderBuilder *builder = m_nodesManager->shaderBuilderManager()->data(builderHandle);
+ if (builder->shaderProgramId() == shader->peerId()) {
+ shaderBuilder = builder;
+ break;
}
+ }
+
+ if (shaderBuilder) {
+ shaderBuilder->setGraphicsApi(*technique->graphicsApiFilter());
+
+ for (int i = 0; i <= ShaderBuilder::Compute; i++) {
+ const auto builderType = static_cast<ShaderBuilder::ShaderType>(i);
+ if (!shaderBuilder->shaderGraph(builderType).isValid())
+ continue;
- if (shaderBuilder) {
- shaderBuilder->setGraphicsApi(*technique->graphicsApiFilter());
-
- for (int i = 0; i <= ShaderBuilder::Compute; i++) {
- const auto builderType = static_cast<ShaderBuilder::ShaderType>(i);
- if (!shaderBuilder->shaderGraph(builderType).isValid())
- continue;
-
- if (shaderBuilder->isShaderCodeDirty(builderType)) {
- shaderBuilder->generateCode(builderType);
- }
-
- QShaderProgram::ShaderType shaderType = QShaderProgram::Vertex;
- switch (builderType) {
- case ShaderBuilder::Vertex:
- shaderType = QShaderProgram::Vertex;
- break;
- case ShaderBuilder::TessellationControl:
- shaderType = QShaderProgram::TessellationControl;
- break;
- case ShaderBuilder::TessellationEvaluation:
- shaderType = QShaderProgram::TessellationEvaluation;
- break;
- case ShaderBuilder::Geometry:
- shaderType = QShaderProgram::Geometry;
- break;
- case ShaderBuilder::Fragment:
- shaderType = QShaderProgram::Fragment;
- break;
- case ShaderBuilder::Compute:
- shaderType = QShaderProgram::Compute;
- break;
- }
-
- const auto code = shaderBuilder->shaderCode(builderType);
- shader->setShaderCode(shaderType, code);
+ if (shaderBuilder->isShaderCodeDirty(builderType)) {
+ shaderBuilder->generateCode(builderType);
+ }
+
+ QShaderProgram::ShaderType shaderType = QShaderProgram::Vertex;
+ switch (builderType) {
+ case ShaderBuilder::Vertex:
+ shaderType = QShaderProgram::Vertex;
+ break;
+ case ShaderBuilder::TessellationControl:
+ shaderType = QShaderProgram::TessellationControl;
+ break;
+ case ShaderBuilder::TessellationEvaluation:
+ shaderType = QShaderProgram::TessellationEvaluation;
+ break;
+ case ShaderBuilder::Geometry:
+ shaderType = QShaderProgram::Geometry;
+ break;
+ case ShaderBuilder::Fragment:
+ shaderType = QShaderProgram::Fragment;
+ break;
+ case ShaderBuilder::Compute:
+ shaderType = QShaderProgram::Compute;
+ break;
}
- }
- if (Q_UNLIKELY(shader->hasPendingNotifications()))
- shader->submitPendingNotifications();
- if (shader != nullptr && !shader->isLoaded())
- m_dirtyShaders.push_back(shaderHandle);
+ const auto code = shaderBuilder->shaderCode(builderType);
+ shader->setShaderCode(shaderType, code);
+ }
}
+
+ if (Q_UNLIKELY(shader->hasPendingNotifications()))
+ shader->submitPendingNotifications();
+ if (shader != nullptr && !shader->isLoaded())
+ m_dirtyShaders.push_back(shaderHandle);
}
}
}
@@ -1449,25 +1457,29 @@ Renderer::ViewSubmissionResultData Renderer::submitRenderViews(const QVector<Ren
void Renderer::markDirty(BackendNodeDirtySet changes, BackendNode *node)
{
Q_UNUSED(node);
- m_changeSet |= changes;
+ m_dirtyBits.marked |= changes;
}
Renderer::BackendNodeDirtySet Renderer::dirtyBits()
{
- return m_changeSet;
+ return m_dirtyBits.marked;
}
+#if defined(QT_BUILD_INTERNAL)
void Renderer::clearDirtyBits(BackendNodeDirtySet changes)
{
- m_changeSet &= ~changes;
+ m_dirtyBits.remaining &= ~changes;
+ m_dirtyBits.marked &= ~changes;
}
+#endif
bool Renderer::shouldRender()
{
// Only render if something changed during the last frame, or the last frame
// was not rendered successfully (or render-on-demand is disabled)
return (m_settings->renderPolicy() == QRenderSettings::Always
- || m_changeSet != 0
+ || m_dirtyBits.marked != 0
+ || m_dirtyBits.remaining != 0
|| !m_lastFrameCorrect.load());
}
@@ -1501,28 +1513,31 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
m_updateLevelOfDetailJob->setFrameGraphRoot(frameGraphRoot());
- BackendNodeDirtySet changesToUnset = dirtyBits();
+ const BackendNodeDirtySet dirtyBitsForFrame = m_dirtyBits.marked | m_dirtyBits.remaining;
+ m_dirtyBits.marked = 0;
+ m_dirtyBits.remaining = 0;
+ BackendNodeDirtySet notCleared = 0;
// Add jobs
- const bool entitiesEnabledDirty = changesToUnset & AbstractRenderer::EntityEnabledDirty;
+ const bool entitiesEnabledDirty = dirtyBitsForFrame & AbstractRenderer::EntityEnabledDirty;
if (entitiesEnabledDirty) {
renderBinJobs.push_back(m_updateTreeEnabledJob);
m_calculateBoundingVolumeJob->addDependency(m_updateTreeEnabledJob);
}
- if (changesToUnset & AbstractRenderer::TransformDirty) {
+ if (dirtyBitsForFrame & AbstractRenderer::TransformDirty) {
renderBinJobs.push_back(m_worldTransformJob);
renderBinJobs.push_back(m_updateWorldBoundingVolumeJob);
renderBinJobs.push_back(m_updateShaderDataTransformJob);
}
- if (changesToUnset & AbstractRenderer::GeometryDirty) {
+ if (dirtyBitsForFrame & AbstractRenderer::GeometryDirty) {
renderBinJobs.push_back(m_calculateBoundingVolumeJob);
renderBinJobs.push_back(m_updateMeshTriangleListJob);
}
- if (changesToUnset & AbstractRenderer::GeometryDirty ||
- changesToUnset & AbstractRenderer::TransformDirty) {
+ if (dirtyBitsForFrame & AbstractRenderer::GeometryDirty ||
+ dirtyBitsForFrame & AbstractRenderer::TransformDirty) {
renderBinJobs.push_back(m_expandBoundingVolumeJob);
}
@@ -1532,19 +1547,15 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
renderBinJobs.push_back(m_cleanupJob);
renderBinJobs.push_back(m_sendRenderCaptureJob);
renderBinJobs.push_back(m_sendBufferCaptureJob);
- renderBinJobs.push_back(m_filterCompatibleTechniqueJob);
renderBinJobs.append(bufferJobs);
// Jobs to prepare GL Resource upload
renderBinJobs.push_back(m_vaoGathererJob);
- if (changesToUnset & AbstractRenderer::BuffersDirty)
+ if (dirtyBitsForFrame & AbstractRenderer::BuffersDirty)
renderBinJobs.push_back(m_bufferGathererJob);
- if (changesToUnset & AbstractRenderer::ShadersDirty)
- renderBinJobs.push_back(m_shaderGathererJob);
-
- if (changesToUnset & AbstractRenderer::TexturesDirty) {
+ if (dirtyBitsForFrame & AbstractRenderer::TexturesDirty) {
renderBinJobs.push_back(m_syncTextureLoadingJob);
renderBinJobs.push_back(m_textureGathererJob);
}
@@ -1552,12 +1563,10 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
// Layer cache is dependent on layers, layer filters and the enabled flag
// on entities
- const bool layersDirty = changesToUnset & AbstractRenderer::LayersDirty;
+ const bool layersDirty = dirtyBitsForFrame & AbstractRenderer::LayersDirty;
const bool layersCacheNeedsToBeRebuilt = layersDirty || entitiesEnabledDirty;
- bool layersCacheRebuilt = false;
- const bool materialDirty = changesToUnset & AbstractRenderer::MaterialDirty;
- bool materialGathererCacheRebuilt = false;
+ const bool materialDirty = dirtyBitsForFrame & AbstractRenderer::MaterialDirty;
QMutexLocker lock(m_renderQueue->mutex());
if (m_renderQueue->wasReset()) { // Have we rendered yet? (Scene3D case)
@@ -1584,30 +1593,28 @@ QVector<Qt3DCore::QAspectJobPtr> Renderer::renderBinJobs()
builder.prepareJobs();
renderBinJobs.append(builder.buildJobHierachy());
}
- layersCacheRebuilt = true;
- materialGathererCacheRebuilt = true;
// Set target number of RenderViews
m_renderQueue->setTargetRenderViewCount(fgBranchCount);
+ } else {
+ // FilterLayerEntityJob is part of the RenderViewBuilder jobs and must be run later
+ // if none of those jobs are started this frame
+ notCleared |= AbstractRenderer::EntityEnabledDirty;
+ notCleared |= AbstractRenderer::LayersDirty;
}
- // Only reset dirty flags once we have really rebuilt the caches
- if (layersDirty && !layersCacheRebuilt)
- changesToUnset.setFlag(AbstractRenderer::LayersDirty, false);
- if (entitiesEnabledDirty && !layersCacheRebuilt)
- changesToUnset.setFlag(AbstractRenderer::EntityEnabledDirty, false);
- if (materialDirty && !materialGathererCacheRebuilt)
- changesToUnset.setFlag(AbstractRenderer::MaterialDirty, false);
-
- // Clear dirty bits
- // TO DO: When secondary GL thread is integrated, the following line can be removed
- changesToUnset.setFlag(AbstractRenderer::ShadersDirty, false);
+ if (isRunning() && m_graphicsContext->isInitialized()) {
+ if (dirtyBitsForFrame & AbstractRenderer::TechniquesDirty )
+ renderBinJobs.push_back(m_filterCompatibleTechniqueJob);
+ if (dirtyBitsForFrame & AbstractRenderer::ShadersDirty)
+ renderBinJobs.push_back(m_shaderGathererJob);
+ } else {
+ notCleared |= AbstractRenderer::TechniquesDirty;
+ notCleared |= AbstractRenderer::ShadersDirty;
+ notCleared |= AbstractRenderer::MaterialDirty;
+ }
- // Clear all dirty flags but Compute so that
- // we still render every frame when a compute shader is used in a scene
- if (changesToUnset.testFlag(Renderer::ComputeDirty))
- changesToUnset.setFlag(Renderer::ComputeDirty, false);
- clearDirtyBits(changesToUnset);
+ m_dirtyBits.remaining = dirtyBitsForFrame & notCleared;
return renderBinJobs;
}
@@ -1745,7 +1752,7 @@ void Renderer::performCompute(const RenderView *, RenderCommand *command)
command->m_workGroups[2]);
}
// HACK: Reset the compute flag to dirty
- m_changeSet |= AbstractRenderer::ComputeDirty;
+ m_dirtyBits.marked |= AbstractRenderer::ComputeDirty;
#if defined(QT3D_RENDER_ASPECT_OPENGL_DEBUG)
int err = m_graphicsContext->openGLContext()->functions()->glGetError();