diff options
-rw-r--r-- | src/plugins/scenegraph/d3d12/qsgd3d12context.cpp | 7 | ||||
-rw-r--r-- | src/plugins/scenegraph/d3d12/qsgd3d12engine.cpp | 22 | ||||
-rw-r--r-- | src/plugins/scenegraph/d3d12/qsgd3d12engine_p.h | 9 | ||||
-rw-r--r-- | src/plugins/scenegraph/d3d12/qsgd3d12rendercontext.cpp | 30 | ||||
-rw-r--r-- | src/plugins/scenegraph/d3d12/qsgd3d12rendercontext_p.h | 10 | ||||
-rw-r--r-- | src/quick/items/qquickgenericshadereffect.cpp | 65 | ||||
-rw-r--r-- | src/quick/items/qquickgenericshadereffect_p.h | 9 | ||||
-rw-r--r-- | src/quick/items/qquickgraphicsinfo.cpp | 35 | ||||
-rw-r--r-- | src/quick/items/qquickitem_p.h | 2 | ||||
-rw-r--r-- | src/quick/items/qquickopenglshadereffect.cpp | 31 | ||||
-rw-r--r-- | src/quick/items/qquickopenglshadereffect_p.h | 4 | ||||
-rw-r--r-- | src/quick/items/qquickshadereffect.cpp | 29 | ||||
-rw-r--r-- | src/quick/items/qquickshadereffect_p.h | 3 | ||||
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 25 | ||||
-rw-r--r-- | src/quick/scenegraph/coreapi/qsgrendererinterface.cpp | 41 | ||||
-rw-r--r-- | src/quick/scenegraph/qsgcontext.cpp | 10 |
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) { |