From bd1c28a82c2ff955e0d154fac2e2df8d5a110dd7 Mon Sep 17 00:00:00 2001 From: Jonas Karlsson Date: Tue, 23 Jun 2020 13:25:39 +0200 Subject: Reimplement UniformAnimator for ShaderEffect Fixes: QTBUG-83976 Change-Id: I307e96be0d3d2edeb8d9065d100c1ef38c8824c7 Reviewed-by: Laszlo Agocs --- src/quick/doc/snippets/qml/animators.qml | 82 +++++++++++----------------- src/quick/items/qquickshadereffect.cpp | 94 +++++++++++++++++++++++++++----- src/quick/items/qquickshadereffect_p.h | 2 + src/quick/util/qquickanimator.cpp | 2 - src/quick/util/qquickanimator_p.h | 4 -- src/quick/util/qquickanimatorjob.cpp | 77 ++++++-------------------- src/quick/util/qquickanimatorjob_p.h | 14 ++--- 7 files changed, 139 insertions(+), 136 deletions(-) (limited to 'src/quick') diff --git a/src/quick/doc/snippets/qml/animators.qml b/src/quick/doc/snippets/qml/animators.qml index 87684f2792..73c8097974 100644 --- a/src/quick/doc/snippets/qml/animators.qml +++ b/src/quick/doc/snippets/qml/animators.qml @@ -219,55 +219,39 @@ Rectangle { } } //! [opacity target] -//![shaderon] -// Uniform animators are not yet ported to Qt 6 -//ShaderEffect { -// width: 50 -// height: 50 -// property variant t; -// UniformAnimator on t { -// from: 0 -// to: 1 -// duration: 1000 -// } -// fragmentShader: -// " -// uniform lowp float t; -// varying highp vec2 qt_TexCoord0; -// void main() { -// lowp float c = qt_TexCoord0.y; -// gl_FragColor = vec4(c * t, 0, 0, 1); -// } -// " -//} -//![shaderon] -//![shader target] -// Uniform animators are not yet ported to Qt 6 -//ShaderEffect { -// id: shader -// width: 50 -// height: 50 -// property variant t; -// UniformAnimator { -// target: shader -// uniform: "t" -// from: 0 -// to: 1 -// duration: 1000 -// running: true -// } -// fragmentShader: -// " -// uniform lowp float t; -// varying highp vec2 qt_TexCoord0; -// void main() { -// lowp float c = qt_TexCoord0.y; -// gl_FragColor = vec4(0, 0, c * t, 1); -// } -// " -//} -//![shader target] -//![mixed] +//! [shaderon] +ShaderEffect { + width: 50 + height: 50 + property variant t; + UniformAnimator on t { + from: 0 + to: 1 + duration: 1000 + } + fragmentShader: "qrc:shader.frag.qsb" +} + +//! [shaderon] +//! [shader target] +ShaderEffect { + id: shader + width: 50 + height: 50 + property variant t; + UniformAnimator { + target: shader + uniform: "t" + from: 0 + to: 1 + duration: 1000 + running: true + } + fragmentShader: "qrc:shader.frag.qsb" +} + +//! [shader target] +//! [mixed] Rectangle { id: mixBox width: 50 diff --git a/src/quick/items/qquickshadereffect.cpp b/src/quick/items/qquickshadereffect.cpp index bc4cfad87b..df900d1f5e 100644 --- a/src/quick/items/qquickshadereffect.cpp +++ b/src/quick/items/qquickshadereffect.cpp @@ -435,6 +435,8 @@ public: void handleComponentComplete(); void handleItemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value); void maybeUpdateShaders(); + bool updateUniformValue(const QByteArray &name, const QVariant &value, + QSGShaderEffectNode *node); private slots: void propertyChanged(int mappedId); @@ -458,6 +460,7 @@ private: void disconnectSignals(Shader shaderType); void clearMappers(Shader shaderType); bool sourceIsUnique(QQuickItem *source, Shader typeToSkip, int indexToSkip) const; + std::optional findMappedShaderVariableId(const QByteArray &name) const; QQuickShaderEffect *m_item; const QMetaObject *m_itemMetaObject = nullptr; @@ -747,6 +750,15 @@ QString QQuickShaderEffect::parseLog() // for OpenGL-based autotests return m_impl->parseLog(); } +bool QQuickShaderEffect::updateUniformValue(const QByteArray &name, const QVariant &value) +{ + auto node = static_cast(QQuickItemPrivate::get(this)->paintNode); + if (!node) + return false; + + return m_impl->updateUniformValue(name, value, node); +} + void QQuickShaderEffectPrivate::updatePolish() { Q_Q(QQuickShaderEffect); @@ -755,6 +767,21 @@ void QQuickShaderEffectPrivate::updatePolish() q->m_impl->maybeUpdateShaders(); } +constexpr int indexToMappedId(const int shaderType, const int idx) +{ + return idx | (shaderType << 16); +} + +constexpr int mappedIdToIndex(const int mappedId) +{ + return mappedId & 0xFFFF; +} + +constexpr int mappedIdToShaderType(const int mappedId) +{ + return mappedId >> 16; +} + QQuickShaderEffectImpl::QQuickShaderEffectImpl(QQuickShaderEffect *item) : QObject(item) , m_item(item) @@ -916,16 +943,10 @@ QQuickShaderEffect::Status QQuickShaderEffectImpl::status() const void QQuickShaderEffectImpl::handleEvent(QEvent *event) { if (event->type() == QEvent::DynamicPropertyChange) { - QDynamicPropertyChangeEvent *e = static_cast(event); - for (int shaderType = 0; shaderType < NShader; ++shaderType) { - const auto &vars(m_shaders[shaderType].shaderInfo.variables); - for (int idx = 0; idx < vars.count(); ++idx) { - if (vars[idx].name == e->propertyName()) { - propertyChanged((shaderType << 16) | idx); - break; - } - } - } + const auto propertyName = static_cast(event)->propertyName(); + const auto mappedId = findMappedShaderVariableId(propertyName); + if (mappedId) + propertyChanged(*mappedId); } } @@ -1026,6 +1047,40 @@ void QQuickShaderEffectImpl::maybeUpdateShaders() } } +bool QQuickShaderEffectImpl::updateUniformValue(const QByteArray &name, const QVariant &value, + QSGShaderEffectNode *node) +{ + const auto mappedId = findMappedShaderVariableId(name); + if (!mappedId) + return false; + + const Shader type = Shader(mappedIdToShaderType(*mappedId)); + const int idx = mappedIdToIndex(*mappedId); + + // Update value + m_shaders[type].varData[idx].value = value; + + // Insert dirty uniform + QSet dirtyConstants[NShader]; + dirtyConstants[type].insert(idx); + + // Sync material change + QSGShaderEffectNode::SyncData sd; + sd.dirty = QSGShaderEffectNode::DirtyShaderConstant; + sd.cullMode = QSGShaderEffectNode::CullMode(m_cullMode); + sd.blending = m_blending; + sd.vertex.shader = &m_shaders[Vertex]; + sd.vertex.dirtyConstants = &dirtyConstants[Vertex]; + sd.vertex.dirtyTextures = {}; + sd.fragment.shader = &m_shaders[Fragment]; + sd.fragment.dirtyConstants = &dirtyConstants[Fragment]; + sd.fragment.dirtyTextures = {}; + + node->syncMaterial(&sd); + + return true; +} + void QQuickShaderEffectImpl::handleItemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value) { // Move the window ref. @@ -1290,7 +1345,7 @@ void QQuickShaderEffectImpl::updateShaderVars(Shader shaderType) } else { auto *&mapper = m_mappers[shaderType][i]; if (!mapper) { - const int mappedId = i | (shaderType << 16); + const int mappedId = indexToMappedId(shaderType, i); mapper = new QtPrivate::EffectSlotMapper([this, mappedId](){ this->propertyChanged(mappedId); }); @@ -1339,10 +1394,23 @@ bool QQuickShaderEffectImpl::sourceIsUnique(QQuickItem *source, Shader typeToSki return true; } +std::optional QQuickShaderEffectImpl::findMappedShaderVariableId(const QByteArray &name) const +{ + for (int shaderType = 0; shaderType < NShader; ++shaderType) { + const auto &vars = m_shaders[shaderType].shaderInfo.variables; + for (int idx = 0; idx < vars.count(); ++idx) { + if (vars[idx].name == name) + return indexToMappedId(shaderType, idx); + } + } + + return {}; +} + void QQuickShaderEffectImpl::propertyChanged(int mappedId) { - const Shader type = Shader(mappedId >> 16); - const int idx = mappedId & 0xFFFF; + const Shader type = Shader(mappedIdToShaderType(mappedId)); + const int idx = mappedIdToIndex(mappedId); const auto &v(m_shaders[type].shaderInfo.variables[idx]); auto &vd(m_shaders[type].varData[idx]); diff --git a/src/quick/items/qquickshadereffect_p.h b/src/quick/items/qquickshadereffect_p.h index f0abeb8cb7..184a69fdc7 100644 --- a/src/quick/items/qquickshadereffect_p.h +++ b/src/quick/items/qquickshadereffect_p.h @@ -119,6 +119,8 @@ public: bool isComponentComplete() const; QString parseLog(); + bool updateUniformValue(const QByteArray &name, const QVariant &value); + Q_SIGNALS: void fragmentShaderChanged(); void vertexShaderChanged(); diff --git a/src/quick/util/qquickanimator.cpp b/src/quick/util/qquickanimator.cpp index 3a7c3ef808..f53f7e2f39 100644 --- a/src/quick/util/qquickanimator.cpp +++ b/src/quick/util/qquickanimator.cpp @@ -504,7 +504,6 @@ QQuickRotationAnimator::RotationDirection QQuickRotationAnimator::direction() co return d->direction; } -#if 0 // QTBUG-83976 /*! \qmltype UniformAnimator \instantiates QQuickUniformAnimator @@ -582,7 +581,6 @@ QQuickAnimatorJob *QQuickUniformAnimator::createJob() const job->setUniform(u.toLatin1()); return job; } -#endif QT_END_NAMESPACE diff --git a/src/quick/util/qquickanimator_p.h b/src/quick/util/qquickanimator_p.h index a7c219ce1a..d34073c7ff 100644 --- a/src/quick/util/qquickanimator_p.h +++ b/src/quick/util/qquickanimator_p.h @@ -184,7 +184,6 @@ protected: QString propertyName() const override { return QStringLiteral("rotation"); } }; -#if 0 // QTBUG-83976 class QQuickUniformAnimatorPrivate; class Q_QUICK_PRIVATE_EXPORT QQuickUniformAnimator : public QQuickAnimator { @@ -207,7 +206,6 @@ protected: QQuickAnimatorJob *createJob() const override; QString propertyName() const override; }; -#endif QT_END_NAMESPACE @@ -217,7 +215,5 @@ QML_DECLARE_TYPE(QQuickYAnimator) QML_DECLARE_TYPE(QQuickScaleAnimator) QML_DECLARE_TYPE(QQuickRotationAnimator) QML_DECLARE_TYPE(QQuickOpacityAnimator) -#if 0 // QTBUG-83976 QML_DECLARE_TYPE(QQuickUniformAnimator) -#endif #endif // QQUICKANIMATOR_P_H diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp index b46e2db258..1c2472dc49 100644 --- a/src/quick/util/qquickanimatorjob.cpp +++ b/src/quick/util/qquickanimatorjob.cpp @@ -43,12 +43,7 @@ #include "qquickanimator_p.h" #include "qquickanimator_p_p.h" #include -#if 0 // QTBUG-83976 -# include -# include -# include -# include -#endif +#include #include #include @@ -595,28 +590,31 @@ void QQuickOpacityAnimatorJob::updateCurrentTime(int time) m_opacityNode->setOpacity(m_value); } - -#if 0 // QTBUG-83976 QQuickUniformAnimatorJob::QQuickUniformAnimatorJob() - : m_node(nullptr) - , m_uniformIndex(-1) - , m_uniformType(-1) { m_isUniform = true; } void QQuickUniformAnimatorJob::setTarget(QQuickItem *target) { - QQuickShaderEffect* effect = qobject_cast(target); - if (effect && effect->isOpenGLShaderEffect()) + // Check target is of expected type + if (qobject_cast(target) != nullptr) m_target = target; } -void QQuickUniformAnimatorJob::invalidate() +void QQuickUniformAnimatorJob::updateCurrentTime(int time) +{ + if (!m_effect) + return; + + m_value = m_from + (m_to - m_from) * progress(time); + m_effect->updateUniformValue(m_uniform, m_value); +} + +void QQuickUniformAnimatorJob::writeBack() { - m_node = nullptr; - m_uniformIndex = -1; - m_uniformType = -1; + if (m_target) + m_target->setProperty(m_uniform, value()); } void QQuickUniformAnimatorJob::postSync() @@ -626,52 +624,13 @@ void QQuickUniformAnimatorJob::postSync() return; } - m_node = static_cast(QQuickItemPrivate::get(m_target)->paintNode); - - if (m_node && m_uniformIndex == -1 && m_uniformType == -1) { - QQuickOpenGLShaderEffectMaterial *material = - static_cast(m_node->material()); - bool found = false; - for (int t=0; !found && t &uniforms = material->uniforms[t]; - for (int i=0; i(m_target); } -void QQuickUniformAnimatorJob::updateCurrentTime(int time) -{ - if (!m_controller) - return; - - if (!m_node || m_uniformIndex == -1 || m_uniformType == -1) - return; - - m_value = m_from + (m_to - m_from) * progress(time); - - QQuickOpenGLShaderEffectMaterial *material = - static_cast(m_node->material()); - material->uniforms[m_uniformType][m_uniformIndex].value = m_value; - // As we're not touching the nodes, we need to explicitly mark it dirty. - // Otherwise, the renderer will abort repainting if this was the only - // change in the graph currently rendering. - m_node->markDirty(QSGNode::DirtyMaterial); -} - -void QQuickUniformAnimatorJob::writeBack() +void QQuickUniformAnimatorJob::invalidate() { - if (m_target) - m_target->setProperty(m_uniform, value()); + m_effect = nullptr; } -#endif QT_END_NAMESPACE diff --git a/src/quick/util/qquickanimatorjob_p.h b/src/quick/util/qquickanimatorjob_p.h index eaec1946ba..0ec1253118 100644 --- a/src/quick/util/qquickanimatorjob_p.h +++ b/src/quick/util/qquickanimatorjob_p.h @@ -69,7 +69,6 @@ class QQuickAbstractAnimation; class QQuickAnimatorController; class QQuickAnimatorProxyJobPrivate; -class QQuickShaderEffectNode; class QSGOpacityNode; @@ -289,7 +288,9 @@ public: private: QSGOpacityNode *m_opacityNode; }; -#if 0 // QTBUG-83976 + +class QQuickShaderEffect; + class Q_QUICK_PRIVATE_EXPORT QQuickUniformAnimatorJob : public QQuickAnimatorJob { public: @@ -300,21 +301,16 @@ public: void setUniform(const QByteArray &uniform) { m_uniform = uniform; } QByteArray uniform() const { return m_uniform; } - void postSync() override; - void updateCurrentTime(int time) override; void writeBack() override; + void postSync() override; void invalidate() override; private: QByteArray m_uniform; - QQuickOpenGLShaderEffectNode *m_node; - - int m_uniformIndex : 8; - int m_uniformType : 8; + QQuickShaderEffect *m_effect = nullptr; }; -#endif QT_END_NAMESPACE -- cgit v1.2.3