aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12context.cpp7
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp22
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h9
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp30
-rw-r--r--src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h10
-rw-r--r--src/quick/items/qquickgenericshadereffect.cpp65
-rw-r--r--src/quick/items/qquickgenericshadereffect_p.h9
-rw-r--r--src/quick/items/qquickgraphicsinfo.cpp35
-rw-r--r--src/quick/items/qquickitem_p.h2
-rw-r--r--src/quick/items/qquickopenglshadereffect.cpp31
-rw-r--r--src/quick/items/qquickopenglshadereffect_p.h4
-rw-r--r--src/quick/items/qquickshadereffect.cpp29
-rw-r--r--src/quick/items/qquickshadereffect_p.h3
-rw-r--r--src/quick/items/qquickwindow.cpp25
-rw-r--r--src/quick/scenegraph/coreapi/qsgrendererinterface.cpp41
-rw-r--r--src/quick/scenegraph/qsgcontext.cpp10
16 files changed, 201 insertions, 131 deletions
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12context.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12context.cpp
index 07c9287f80..1b29ddd59c 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12context.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12context.cpp
@@ -109,12 +109,7 @@ QSurfaceFormat QSGD3D12Context::defaultSurfaceFormat() const
QSGRendererInterface *QSGD3D12Context::rendererInterface(QSGRenderContext *renderContext)
{
- QSGD3D12RenderContext *rc = static_cast<QSGD3D12RenderContext *>(renderContext);
- if (!rc->engine()) {
- qWarning("No D3D12 engine available yet (no render thread due to window not exposed?)");
- return nullptr;
- }
- return rc->engine();
+ return static_cast<QSGD3D12RenderContext *>(renderContext);
}
QSGRectangleNode *QSGD3D12Context::createRectangleNode()
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp
index b54d10aa85..e1b076c39a 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp
@@ -535,31 +535,11 @@ void QSGD3D12Engine::simulateDeviceLoss()
d->simulateDeviceLoss();
}
-QSGRendererInterface::GraphicsApi QSGD3D12Engine::graphicsApi() const
-{
- return Direct3D12;
-}
-
-void *QSGD3D12Engine::getResource(Resource resource) const
+void *QSGD3D12Engine::getResource(QSGRendererInterface::Resource resource) const
{
return d->getResource(resource);
}
-QSGRendererInterface::ShaderType QSGD3D12Engine::shaderType() const
-{
- return HLSL;
-}
-
-QSGRendererInterface::ShaderCompilationTypes QSGD3D12Engine::shaderCompilationType() const
-{
- return RuntimeCompilation | OfflineCompilation;
-}
-
-QSGRendererInterface::ShaderSourceTypes QSGD3D12Engine::shaderSourceType() const
-{
- return ShaderSourceString | ShaderByteCode;
-}
-
static inline quint32 alignedSize(quint32 size, quint32 byteAlign)
{
return (size + byteAlign - 1) & ~(byteAlign - 1);
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h
index 2ebe1e733a..ad89696bbe 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h
@@ -281,7 +281,7 @@ inline uint qHash(const QSGD3D12PipelineState &key, uint seed = 0)
+ key.topologyType;
}
-class QSGD3D12Engine : public QSGRendererInterface
+class QSGD3D12Engine
{
public:
QSGD3D12Engine();
@@ -372,12 +372,7 @@ public:
void simulateDeviceLoss();
- // QSGRendererInterface
- GraphicsApi graphicsApi() const override;
- void *getResource(Resource resource) const override;
- ShaderType shaderType() const override;
- ShaderCompilationTypes shaderCompilationType() const override;
- ShaderSourceTypes shaderSourceType() const override;
+ void *getResource(QSGRendererInterface::Resource resource) const;
private:
QSGD3D12EnginePrivate *d;
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp
index b32bfe063a..7e62421380 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp
@@ -126,4 +126,34 @@ void QSGD3D12RenderContext::ensureInitializedEmitted()
emit initialized();
}
+QSGRendererInterface::GraphicsApi QSGD3D12RenderContext::graphicsApi() const
+{
+ return Direct3D12;
+}
+
+void *QSGD3D12RenderContext::getResource(Resource resource) const
+{
+ if (!m_engine) {
+ qWarning("getResource: No D3D12 engine available yet (window not exposed?)");
+ return nullptr;
+ }
+
+ return m_engine->getResource(resource);
+}
+
+QSGRendererInterface::ShaderType QSGD3D12RenderContext::shaderType() const
+{
+ return HLSL;
+}
+
+QSGRendererInterface::ShaderCompilationTypes QSGD3D12RenderContext::shaderCompilationType() const
+{
+ return RuntimeCompilation | OfflineCompilation;
+}
+
+QSGRendererInterface::ShaderSourceTypes QSGD3D12RenderContext::shaderSourceType() const
+{
+ return ShaderSourceString | ShaderByteCode;
+}
+
QT_END_NAMESPACE
diff --git a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h
index 86a300831d..a1029b019e 100644
--- a/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h
+++ b/src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h
@@ -52,12 +52,13 @@
//
#include <private/qsgcontext_p.h>
+#include <qsgrendererinterface.h>
QT_BEGIN_NAMESPACE
class QSGD3D12Engine;
-class QSGD3D12RenderContext : public QSGRenderContext
+class QSGD3D12RenderContext : public QSGRenderContext, public QSGRendererInterface
{
public:
QSGD3D12RenderContext(QSGContext *ctx);
@@ -73,6 +74,13 @@ public:
void ensureInitializedEmitted();
void setInitializedPending() { m_pendingInitialized = true; }
+ // QSGRendererInterface
+ GraphicsApi graphicsApi() const override;
+ void *getResource(Resource resource) const override;
+ ShaderType shaderType() const override;
+ ShaderCompilationTypes shaderCompilationType() const override;
+ ShaderSourceTypes shaderSourceType() const override;
+
private:
QSGD3D12Engine *m_engine = nullptr;
bool m_pendingInitialized = false;
diff --git a/src/quick/items/qquickgenericshadereffect.cpp b/src/quick/items/qquickgenericshadereffect.cpp
index 11259a588a..683453d4ee 100644
--- a/src/quick/items/qquickgenericshadereffect.cpp
+++ b/src/quick/items/qquickgenericshadereffect.cpp
@@ -59,10 +59,11 @@ QQuickGenericShaderEffect::QQuickGenericShaderEffect(QQuickShaderEffect *item, Q
, m_blending(true)
, m_supportsAtlasTextures(false)
, m_mgr(nullptr)
+ , m_fragNeedsUpdate(true)
+ , m_vertNeedsUpdate(true)
, m_dirty(0)
{
qRegisterMetaType<QSGGuiThreadShaderEffectManager::ShaderInfo::Type>("ShaderInfo::Type");
- connect(m_item, SIGNAL(windowChanged(QQuickWindow*)), this, SLOT(itemWindowChanged(QQuickWindow*)));
for (int i = 0; i < NShader; ++i)
m_inProgress[i] = nullptr;
}
@@ -88,12 +89,11 @@ void QQuickGenericShaderEffect::setFragmentShader(const QByteArray &src)
return;
m_fragShader = src;
- m_dirty |= QSGShaderEffectNode::DirtyShaders;
+ m_fragNeedsUpdate = true;
if (m_item->isComponentComplete())
- updateShader(Fragment, src);
+ maybeUpdateShaders();
- m_item->update();
emit m_item->fragmentShaderChanged();
}
@@ -103,12 +103,11 @@ void QQuickGenericShaderEffect::setVertexShader(const QByteArray &src)
return;
m_vertShader = src;
- m_dirty |= QSGShaderEffectNode::DirtyShaders;
+ m_vertNeedsUpdate = true;
if (m_item->isComponentComplete())
- updateShader(Vertex, src);
+ maybeUpdateShaders();
- m_item->update();
emit m_item->vertexShaderChanged();
}
@@ -187,6 +186,12 @@ void QQuickGenericShaderEffect::setSupportsAtlasTextures(bool supports)
emit m_item->supportsAtlasTexturesChanged();
}
+QString QQuickGenericShaderEffect::parseLog()
+{
+ maybeUpdateShaders();
+ return log();
+}
+
QString QQuickGenericShaderEffect::log() const
{
QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
@@ -294,10 +299,14 @@ QSGNode *QQuickGenericShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQui
return node;
}
-void QQuickGenericShaderEffect::handleComponentComplete()
+void QQuickGenericShaderEffect::maybeUpdateShaders()
{
- updateShader(Vertex, m_vertShader);
- updateShader(Fragment, m_fragShader);
+ if (m_vertNeedsUpdate)
+ m_vertNeedsUpdate = !updateShader(Vertex, m_vertShader);
+ if (m_fragNeedsUpdate)
+ m_fragNeedsUpdate = !updateShader(Fragment, m_fragShader);
+ if (m_vertNeedsUpdate || m_fragNeedsUpdate)
+ m_item->polish();
}
void QQuickGenericShaderEffect::handleItemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)
@@ -326,9 +335,8 @@ QSGGuiThreadShaderEffectManager *QQuickGenericShaderEffect::shaderEffectManager(
// return null if this is not the gui thread and not already created
if (QThread::currentThread() != m_item->thread())
return m_mgr;
- // need a window and a rendercontext (i.e. the scenegraph backend is ready)
QQuickWindow *w = m_item->window();
- if (w && w->isSceneGraphInitialized()) {
+ if (w) { // note: just the window, don't care about isSceneGraphInitialized() here
m_mgr = QQuickWindowPrivate::get(w)->context->sceneGraphContext()->createGuiThreadShaderEffectManager();
if (m_mgr) {
connect(m_mgr, SIGNAL(logAndStatusChanged()), m_item, SIGNAL(logChanged()));
@@ -336,34 +344,12 @@ QSGGuiThreadShaderEffectManager *QQuickGenericShaderEffect::shaderEffectManager(
connect(m_mgr, SIGNAL(textureChanged()), this, SLOT(markGeometryDirtyAndUpdateIfSupportsAtlas()));
connect(m_mgr, &QSGGuiThreadShaderEffectManager::shaderCodePrepared, this, &QQuickGenericShaderEffect::shaderCodePrepared);
}
- } else if (!w) {
- // Wait until itemWindowChanged() gets called. Return null for now.
- } else {
- // Have window, but no scenegraph -> ensure the signal is connected. Return null for now.
- const_cast<QQuickGenericShaderEffect *>(this)->itemWindowChanged(w);
}
}
return m_mgr;
}
-void QQuickGenericShaderEffect::itemWindowChanged(QQuickWindow *w)
-{
- if (w) {
- if (w->isSceneGraphInitialized())
- backendChanged();
- else
- connect(w, SIGNAL(sceneGraphInitialized()), this, SLOT(backendChanged()), Qt::UniqueConnection);
- }
-}
-
-void QQuickGenericShaderEffect::backendChanged()
-{
- disconnect(m_item->window(), SIGNAL(sceneGraphInitialized()), this, SLOT(backendChanged()));
- emit m_item->logChanged();
- emit m_item->statusChanged();
-}
-
void QQuickGenericShaderEffect::disconnectSignals(Shader shaderType)
{
for (auto &sm : m_signalMappers[shaderType]) {
@@ -407,11 +393,11 @@ struct ShaderInfoCache
Q_GLOBAL_STATIC(ShaderInfoCache, shaderInfoCache)
-void QQuickGenericShaderEffect::updateShader(Shader shaderType, const QByteArray &src)
+bool QQuickGenericShaderEffect::updateShader(Shader shaderType, const QByteArray &src)
{
QSGGuiThreadShaderEffectManager *mgr = shaderEffectManager();
if (!mgr)
- return;
+ return false;
const bool texturesSeparate = mgr->hasSeparateSamplerAndTextureObjects();
@@ -439,7 +425,7 @@ void QQuickGenericShaderEffect::updateShader(Shader shaderType, const QByteArray
// source->bytecode compilation as well in this step.
mgr->prepareShaderCode(typeHint, src, m_inProgress[shaderType]);
// the rest is handled in shaderCodePrepared()
- return;
+ return true;
}
} else {
m_shaders[shaderType].hasShaderCode = false;
@@ -459,6 +445,9 @@ void QQuickGenericShaderEffect::updateShader(Shader shaderType, const QByteArray
}
updateShaderVars(shaderType);
+ m_dirty |= QSGShaderEffectNode::DirtyShaders;
+ m_item->update();
+ return true;
}
void QQuickGenericShaderEffect::shaderCodePrepared(bool ok, QSGGuiThreadShaderEffectManager::ShaderInfo::Type typeHint,
@@ -486,6 +475,8 @@ void QQuickGenericShaderEffect::shaderCodePrepared(bool ok, QSGGuiThreadShaderEf
m_shaders[shaderType].hasShaderCode = true;
shaderInfoCache()->insert(src, m_shaders[shaderType].shaderInfo);
updateShaderVars(shaderType);
+ m_dirty |= QSGShaderEffectNode::DirtyShaders;
+ m_item->update();
}
void QQuickGenericShaderEffect::updateShaderVars(Shader shaderType)
diff --git a/src/quick/items/qquickgenericshadereffect_p.h b/src/quick/items/qquickgenericshadereffect_p.h
index 5ec83eb60f..ab19816493 100644
--- a/src/quick/items/qquickgenericshadereffect_p.h
+++ b/src/quick/items/qquickgenericshadereffect_p.h
@@ -90,19 +90,20 @@ public:
bool supportsAtlasTextures() const { return m_supportsAtlasTextures; }
void setSupportsAtlasTextures(bool supports);
+ QString parseLog();
+
void handleEvent(QEvent *);
void handleGeometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
QSGNode *handleUpdatePaintNode(QSGNode *, QQuickItem::UpdatePaintNodeData *);
void handleComponentComplete();
void handleItemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value);
+ void maybeUpdateShaders();
private slots:
void propertyChanged(int mappedId);
void sourceDestroyed(QObject *object);
void markGeometryDirtyAndUpdate();
void markGeometryDirtyAndUpdateIfSupportsAtlas();
- void itemWindowChanged(QQuickWindow *w);
- void backendChanged();
void shaderCodePrepared(bool ok, QSGGuiThreadShaderEffectManager::ShaderInfo::Type typeHint,
const QByteArray &src, QSGGuiThreadShaderEffectManager::ShaderInfo *result);
@@ -115,7 +116,7 @@ private:
NShader
};
- void updateShader(Shader shaderType, const QByteArray &src);
+ bool updateShader(Shader shaderType, const QByteArray &src);
void updateShaderVars(Shader shaderType);
void disconnectSignals(Shader shaderType);
bool sourceIsUnique(QQuickItem *source, Shader typeToSkip, int indexToSkip) const;
@@ -129,7 +130,9 @@ private:
bool m_supportsAtlasTextures;
mutable QSGGuiThreadShaderEffectManager *m_mgr;
QByteArray m_fragShader;
+ bool m_fragNeedsUpdate;
QByteArray m_vertShader;
+ bool m_vertNeedsUpdate;
QSGShaderEffectNode::ShaderData m_shaders[NShader];
QSGShaderEffectNode::DirtyShaderFlags m_dirty;
diff --git a/src/quick/items/qquickgraphicsinfo.cpp b/src/quick/items/qquickgraphicsinfo.cpp
index 79b0edf031..761d0c3cad 100644
--- a/src/quick/items/qquickgraphicsinfo.cpp
+++ b/src/quick/items/qquickgraphicsinfo.cpp
@@ -112,11 +112,11 @@ QQuickGraphicsInfo *QQuickGraphicsInfo::qmlAttachedProperties(QObject *object)
\endlist
\note The value is only up-to-date once the item is associated with a
- window and the window's scenegraph has initialized. Bindings relying on the
- value have to keep this in mind since the value may change from
- GraphicsInfo.UnknownShadingLanguage to the actual value after component
- initialization is complete. This is particularly relevant for ShaderEffect
- items inside ShaderEffectSource items set as property values.
+ window. Bindings relying on the value have to keep this in mind since the
+ value may change from GraphicsInfo.UnknownShadingLanguage to the actual
+ value after component initialization is complete. This is particularly
+ relevant for ShaderEffect items inside ShaderEffectSource items set as
+ property values.
\since 5.8
\since QtQuick 2.8
@@ -140,11 +140,10 @@ QQuickGraphicsInfo *QQuickGraphicsInfo::qmlAttachedProperties(QObject *object)
expected to focus more on GraphicsInfo.OfflineCompilation, however.
\note The value is only up-to-date once the item is associated with a
- window and the window's scenegraph has initialized. Bindings relying on the
- value have to keep this in mind since the value may change from \c 0 to the
- actual bitmask after component initialization is complete. This is
- particularly relevant for ShaderEffect items inside ShaderEffectSource
- items set as property values.
+ window. Bindings relying on the value have to keep this in mind since the
+ value may change from \c 0 to the actual bitmask after component
+ initialization is complete. This is particularly relevant for ShaderEffect
+ items inside ShaderEffectSource items set as property values.
\since 5.8
\since QtQuick 2.8
@@ -172,11 +171,10 @@ QQuickGraphicsInfo *QQuickGraphicsInfo::qmlAttachedProperties(QObject *object)
bytecode.
\note The value is only up-to-date once the item is associated with a
- window and the window's scenegraph has initialized. Bindings relying on the
- value have to keep this in mind since the value may change from \c 0 to the
- actual bitmask after component initialization is complete. This is
- particularly relevant for ShaderEffect items inside ShaderEffectSource
- items set as property values.
+ window. Bindings relying on the value have to keep this in mind since the
+ value may change from \c 0 to the actual bitmask after component
+ initialization is complete. This is particularly relevant for ShaderEffect
+ items inside ShaderEffectSource items set as property values.
\since 5.8
\since QtQuick 2.8
@@ -240,9 +238,8 @@ QQuickGraphicsInfo *QQuickGraphicsInfo::qmlAttachedProperties(QObject *object)
void QQuickGraphicsInfo::updateInfo()
{
- const bool sgReady = m_window && m_window->isSceneGraphInitialized();
-
- if (sgReady) {
+ // The queries via the RIF do not depend on isSceneGraphInitialized(), they only need a window.
+ if (m_window) {
QSGRendererInterface *rif = m_window->rendererInterface();
if (rif) {
GraphicsApi newAPI = GraphicsApi(rif->graphicsApi());
@@ -261,7 +258,7 @@ void QQuickGraphicsInfo::updateInfo()
QSurfaceFormat format = QSurfaceFormat::defaultFormat();
#ifndef QT_NO_OPENGL
- if (sgReady) {
+ if (m_window && m_window->isSceneGraphInitialized()) {
QOpenGLContext *context = m_window->openglContext();
if (context)
format = context->format();
diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h
index 3468172484..8328dd513b 100644
--- a/src/quick/items/qquickitem_p.h
+++ b/src/quick/items/qquickitem_p.h
@@ -610,6 +610,8 @@ public:
// recursive helper to let a visual parent mark its visual children
void markObjects(QV4::ExecutionEngine *e);
+
+ virtual void updatePolish() { }
};
/*
diff --git a/src/quick/items/qquickopenglshadereffect.cpp b/src/quick/items/qquickopenglshadereffect.cpp
index 1e66971fdb..f65062ae38 100644
--- a/src/quick/items/qquickopenglshadereffect.cpp
+++ b/src/quick/items/qquickopenglshadereffect.cpp
@@ -556,6 +556,8 @@ QQuickOpenGLShaderEffect::QQuickOpenGLShaderEffect(QQuickShaderEffect *item, QOb
, m_dirtyGeometry(true)
, m_customVertexShader(false)
, m_supportsAtlasTextures(false)
+ , m_vertNeedsUpdate(true)
+ , m_fragNeedsUpdate(true)
{
}
@@ -573,8 +575,9 @@ void QQuickOpenGLShaderEffect::setFragmentShader(const QByteArray &code)
m_dirtyProgram = true;
m_dirtyParseLog = true;
+ m_fragNeedsUpdate = true;
if (m_item->isComponentComplete())
- m_common.updateShader(m_item, Key::FragmentShader);
+ maybeUpdateShaders();
m_item->update();
if (m_status != QQuickShaderEffect::Uncompiled) {
@@ -593,8 +596,9 @@ void QQuickOpenGLShaderEffect::setVertexShader(const QByteArray &code)
m_dirtyParseLog = true;
m_customVertexShader = true;
+ m_vertNeedsUpdate = true;
if (m_item->isComponentComplete())
- m_common.updateShader(m_item, Key::VertexShader);
+ maybeUpdateShaders();
m_item->update();
if (m_status != QQuickShaderEffect::Uncompiled) {
@@ -677,6 +681,8 @@ void QQuickOpenGLShaderEffect::setSupportsAtlasTextures(bool supports)
QString QQuickOpenGLShaderEffect::parseLog()
{
+ maybeUpdateShaders(true);
+
if (m_dirtyParseLog) {
m_common.updateParseLog(m_mesh != 0);
m_dirtyParseLog = false;
@@ -862,10 +868,25 @@ QSGNode *QQuickOpenGLShaderEffect::handleUpdatePaintNode(QSGNode *oldNode, QQuic
return node;
}
-void QQuickOpenGLShaderEffect::handleComponentComplete()
+void QQuickOpenGLShaderEffect::maybeUpdateShaders(bool force)
{
- m_common.updateShader(m_item, Key::VertexShader);
- m_common.updateShader(m_item, Key::FragmentShader);
+ // Defer processing if a window is not yet associated with the item. This
+ // is because the actual scenegraph backend is not known so conditions
+ // based on GraphicsInfo.shaderType and similar evaluate to wrong results.
+ if (!m_item->window() && !force) {
+ m_item->polish();
+ return;
+ }
+
+ if (m_vertNeedsUpdate) {
+ m_vertNeedsUpdate = false;
+ m_common.updateShader(m_item, Key::VertexShader);
+ }
+
+ if (m_fragNeedsUpdate) {
+ m_fragNeedsUpdate = false;
+ m_common.updateShader(m_item, Key::FragmentShader);
+ }
}
void QQuickOpenGLShaderEffect::handleItemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value)
diff --git a/src/quick/items/qquickopenglshadereffect_p.h b/src/quick/items/qquickopenglshadereffect_p.h
index 0e54813443..bc60ba1e83 100644
--- a/src/quick/items/qquickopenglshadereffect_p.h
+++ b/src/quick/items/qquickopenglshadereffect_p.h
@@ -132,8 +132,8 @@ public:
void handleEvent(QEvent *);
void handleGeometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry);
QSGNode *handleUpdatePaintNode(QSGNode *, QQuickItem::UpdatePaintNodeData *);
- void handleComponentComplete();
void handleItemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value);
+ void maybeUpdateShaders(bool force = false);
private Q_SLOTS:
void updateGeometry();
@@ -169,6 +169,8 @@ private:
uint m_dirtyGeometry : 1;
uint m_customVertexShader : 1;
uint m_supportsAtlasTextures : 1;
+ uint m_vertNeedsUpdate : 1;
+ uint m_fragNeedsUpdate : 1;
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp
index 4f1a9a28ec..f7c103a58f 100644
--- a/src/quick/items/qquickshadereffect.cpp
+++ b/src/quick/items/qquickshadereffect.cpp
@@ -39,6 +39,7 @@
#include <private/qquickshadereffect_p.h>
#include <private/qsgcontextplugin_p.h>
+#include <private/qquickitem_p.h>
#ifndef QT_NO_OPENGL
#include <private/qquickopenglshadereffect_p.h>
#endif
@@ -382,10 +383,18 @@ QT_BEGIN_NAMESPACE
\sa {Item Layers}
*/
+class QQuickShaderEffectPrivate : public QQuickItemPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickShaderEffect)
+
+public:
+ void updatePolish() override;
+};
+
QSGContextFactoryInterface::Flags qsg_backend_flags();
QQuickShaderEffect::QQuickShaderEffect(QQuickItem *parent)
- : QQuickItem(parent),
+ : QQuickItem(*new QQuickShaderEffectPrivate, parent),
#ifndef QT_NO_OPENGL
m_glImpl(nullptr),
#endif
@@ -712,12 +721,12 @@ void QQuickShaderEffect::componentComplete()
{
#ifndef QT_NO_OPENGL
if (m_glImpl) {
- m_glImpl->handleComponentComplete();
+ m_glImpl->maybeUpdateShaders();
QQuickItem::componentComplete();
return;
}
#endif
- m_impl->handleComponentComplete();
+ m_impl->maybeUpdateShaders();
QQuickItem::componentComplete();
}
@@ -745,7 +754,19 @@ QString QQuickShaderEffect::parseLog() // for OpenGL-based autotests
if (m_glImpl)
return m_glImpl->parseLog();
#endif
- return QString();
+ return m_impl->parseLog();
+}
+
+void QQuickShaderEffectPrivate::updatePolish()
+{
+ Q_Q(QQuickShaderEffect);
+#ifndef QT_NO_OPENGL
+ if (q->m_glImpl) {
+ q->m_glImpl->maybeUpdateShaders();
+ return;
+ }
+#endif
+ q->m_impl->maybeUpdateShaders();
}
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h
index 62d7e6fe5f..17b009039a 100644
--- a/src/quick/items/qquickshadereffect_p.h
+++ b/src/quick/items/qquickshadereffect_p.h
@@ -58,6 +58,7 @@ QT_BEGIN_NAMESPACE
class QQuickOpenGLShaderEffect;
class QQuickGenericShaderEffect;
+class QQuickShaderEffectPrivate;
class Q_QUICK_PRIVATE_EXPORT QQuickShaderEffect : public QQuickItem
{
@@ -134,6 +135,8 @@ private:
QQuickOpenGLShaderEffect *m_glImpl;
#endif
QQuickGenericShaderEffect *m_impl;
+
+ Q_DECLARE_PRIVATE(QQuickShaderEffect)
};
QT_END_NAMESPACE
diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp
index 10b769b5b0..c3c886de35 100644
--- a/src/quick/items/qquickwindow.cpp
+++ b/src/quick/items/qquickwindow.cpp
@@ -293,7 +293,9 @@ void QQuickWindowPrivate::polishItems()
int recursionSafeguard = INT_MAX;
while (!itemsToPolish.isEmpty() && --recursionSafeguard > 0) {
QQuickItem *item = itemsToPolish.takeLast();
- QQuickItemPrivate::get(item)->polishScheduled = false;
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ itemPrivate->polishScheduled = false;
+ itemPrivate->updatePolish();
item->updatePolish();
}
@@ -4450,16 +4452,31 @@ qreal QQuickWindow::effectiveDevicePixelRatio() const
}
/*!
- Returns the current renderer interface if there is one. Otherwise null is returned.
+ \return the current renderer interface. The value is always valid and is never null.
+
+ \note This function can be called at any time after constructing the
+ QQuickWindow, even while isSceneGraphInitialized() is still false. However,
+ some renderer interface functions, in particular
+ QSGRendererInterface::getResource() will not be functional until the
+ scenegraph is up and running. Backend queries, like
+ QSGRendererInterface::graphicsApi() or QSGRendererInterface::shaderType(),
+ will always be functional on the other hand.
- \sa QSGRenderNode, QSGRendererInterface, isSceneGraphInitialized()
+ \sa QSGRenderNode, QSGRendererInterface
\since 5.8
*/
QSGRendererInterface *QQuickWindow::rendererInterface() const
{
Q_D(const QQuickWindow);
- return isSceneGraphInitialized() ? d->context->sceneGraphContext()->rendererInterface(d->context) : nullptr;
+
+ // no context validity check - it is essential to be able to return a
+ // renderer interface instance before scenegraphInitialized() is emitted
+ // (depending on the backend, that can happen way too late for some of the
+ // rif use cases, like examining the graphics api or shading language in
+ // use)
+
+ return d->context->sceneGraphContext()->rendererInterface(d->context);
}
/*!
diff --git a/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp b/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp
index 149baab3a9..e818d35dd7 100644
--- a/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp
+++ b/src/quick/scenegraph/coreapi/qsgrendererinterface.cpp
@@ -54,12 +54,21 @@ QT_BEGIN_NAMESPACE
necessary to query certain values, for instance the graphics device (e.g.
the Direct3D or Vulkan device) that is used by the scenegraph.
- \note QSGRendererInterface is only available after the scenegraph is
- initialized. Additionally, there may be backend-specific limitations on
- when the functions can be called. The only way that is guaranteed to
- succeed is calling them when the rendering of a node (i.e. the preparation
- of the command list for the next frame) is active. In practice this
- typically means QSGRenderNode::render().
+ QSGRendererInterface's functions have varying availability. API and
+ language queries, like graphicsApi() or shaderType() are always available,
+ meaning it is sufficient to construct a QQuickWindow or QQuickView, and the
+ graphics API or shading language in use can be queried right after via
+ QQuickWindow::rendererInterface(). This guarantees that utilities like the
+ GraphicsInfo QML type are able to report the correct values as early as
+ possible, without having conditional property values - depending on for
+ instance shaderType() - evaluate to unexpected values.
+
+ Engine-specific accessors, like getResource(), are however available only
+ after the scenegraph is initialized. Additionally, there may be
+ backend-specific limitations on when such functions can be called. The only
+ way that is guaranteed to succeed is calling them when the rendering of a
+ node (i.e. the preparation of the command list for the next frame) is
+ active. In practice this typically means QSGRenderNode::render().
*/
/*!
@@ -112,10 +121,7 @@ QSGRendererInterface::~QSGRendererInterface()
Returns the graphics API that is in use by the Qt Quick scenegraph.
- \note This function can be called on any thread. However, the renderer
- interface's lifetime may be tied to the render thread and therefore calling
- this function from other threads during the process of application shutdown
- or QQuickWindow closing is likely to become invalid.
+ \note This function can be called on any thread.
*/
/*!
@@ -155,10 +161,7 @@ void *QSGRendererInterface::getResource(const char *resource) const
\return the shading language supported by the Qt Quick backend the
application is using.
- \note This function can be called on any thread. However, the renderer
- interface's lifetime may be tied to the render thread and therefore calling
- this function from other threads during the process of application shutdown
- or QQuickWindow closing is likely to become invalid.
+ \note This function can be called on any thread.
\sa QtQuick::GraphicsInfo
*/
@@ -169,10 +172,7 @@ void *QSGRendererInterface::getResource(const char *resource) const
\return a bitmask of the shader compilation approaches supported by the Qt
Quick backend the application is using.
- \note This function can be called on any thread. However, the renderer
- interface's lifetime may be tied to the render thread and therefore calling
- this function from other threads during the process of application shutdown
- or QQuickWindow closing is likely to become invalid.
+ \note This function can be called on any thread.
\sa QtQuick::GraphicsInfo
*/
@@ -182,10 +182,7 @@ void *QSGRendererInterface::getResource(const char *resource) const
\return a bitmask of the supported ways of providing shader sources in ShaderEffect items.
- \note This function can be called on any thread. However, the renderer
- interface's lifetime may be tied to the render thread and therefore calling
- this function from other threads during the process of application shutdown
- or QQuickWindow closing is likely to become invalid.
+ \note This function can be called on any thread.
\sa QtQuick::GraphicsInfo
*/
diff --git a/src/quick/scenegraph/qsgcontext.cpp b/src/quick/scenegraph/qsgcontext.cpp
index fa77c2d6cc..83aceb79f4 100644
--- a/src/quick/scenegraph/qsgcontext.cpp
+++ b/src/quick/scenegraph/qsgcontext.cpp
@@ -318,7 +318,15 @@ QSize QSGContext::minimumFBOSize() const
Returns a pointer to the (presumably) global renderer interface.
\note This function may be called on the gui thread in order to get access
- to QSGRendererInterface::graphicsApi().
+ to QSGRendererInterface::graphicsApi() and other getters.
+
+ \note it is expected that the simple queries (graphicsApi, shaderType,
+ etc.) are available regardless of the render context validity (i.e.
+ scenegraph status). This does not apply to engine-specific getters like
+ getResource(). In the end this means that this function must always return
+ a valid object in subclasses, even when renderContext->isValid() is false.
+ The typical pattern is to implement the QSGRendererInterface in the
+ QSGContext or QSGRenderContext subclass itself, whichever is more suitable.
*/
QSGRendererInterface *QSGContext::rendererInterface(QSGRenderContext *renderContext)
{