From 47b330ea2391f8feda67133d6dafb4b4b63e86fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Fl=C3=B6ser?= Date: Mon, 11 Apr 2022 20:45:18 +0200 Subject: [PATCH] [libkwineffects] Add support for shaders in AnimationEffect The animate and set calls are extended for an optional GLShader* to allow specifying a custom shader to use during the animation. To properly support rendering a complete window in the effect the AnimationEffect gets based on the DeformEffect. If a shader is used during the animation the window gets redirected. For the animation with shaders two new enum values are added to the AnimationType enum: * Shader * ShaderUniform The Shader animation type is for specifying that the animation uses a shader. During the animation a uniform "animationProgress" is set on the shader. The ShaderUniform animation type behaves exactly like the Shader type, but also animates a user provided uniform. The meta data of the animation is interpreted as a uniform location for a float uniform and during the animation this uniform is updated with the interpolated animation data. --- src/libkwineffects/anidata.cpp | 3 +- src/libkwineffects/anidata_p.h | 3 +- src/libkwineffects/kwinanimationeffect.cpp | 33 ++++++++++++++++++++-- src/libkwineffects/kwinanimationeffect.h | 26 ++++++++++++----- src/libkwineffects/kwineffects.h | 2 +- 5 files changed, 55 insertions(+), 12 deletions(-) diff --git a/src/libkwineffects/anidata.cpp b/src/libkwineffects/anidata.cpp index ff213986de..3fb5e5ca6b 100644 --- a/src/libkwineffects/anidata.cpp +++ b/src/libkwineffects/anidata.cpp @@ -72,7 +72,7 @@ AniData::AniData() AniData::AniData(AnimationEffect::Attribute a, int meta_, const FPx2 &to_, int delay, const FPx2 &from_, bool waitAtSource_, FullScreenEffectLockPtr fullScreenEffectLock_, bool keepAlive, - PreviousWindowPixmapLockPtr previousWindowPixmapLock_) + PreviousWindowPixmapLockPtr previousWindowPixmapLock_, GLShader *shader) : attribute(a) , from(from_) , to(to_) @@ -84,6 +84,7 @@ AniData::AniData(AnimationEffect::Attribute a, int meta_, const FPx2 &to_, , keepAlive(keepAlive) , previousWindowPixmapLock(std::move(previousWindowPixmapLock_)) , lastPresentTime(std::chrono::milliseconds::zero()) + , shader(shader) { } diff --git a/src/libkwineffects/anidata_p.h b/src/libkwineffects/anidata_p.h index d30cdaeaf0..2df63abc4e 100644 --- a/src/libkwineffects/anidata_p.h +++ b/src/libkwineffects/anidata_p.h @@ -69,7 +69,7 @@ public: AniData(AnimationEffect::Attribute a, int meta, const FPx2 &to, int delay, const FPx2 &from, bool waitAtSource, FullScreenEffectLockPtr = FullScreenEffectLockPtr(), - bool keepAlive = true, PreviousWindowPixmapLockPtr previousWindowPixmapLock = {}); + bool keepAlive = true, PreviousWindowPixmapLockPtr previousWindowPixmapLock = {}, GLShader *shader = nullptr); bool isActive() const; @@ -94,6 +94,7 @@ public: PreviousWindowPixmapLockPtr previousWindowPixmapLock; AnimationEffect::TerminationFlags terminationFlags; std::chrono::milliseconds lastPresentTime; + GLShader *shader{nullptr}; }; } // namespace diff --git a/src/libkwineffects/kwinanimationeffect.cpp b/src/libkwineffects/kwinanimationeffect.cpp index 098752243f..054b11a1f6 100644 --- a/src/libkwineffects/kwinanimationeffect.cpp +++ b/src/libkwineffects/kwinanimationeffect.cpp @@ -9,6 +9,7 @@ */ #include "kwinanimationeffect.h" +#include "kwinglutils.h" #include "anidata_p.h" #include @@ -207,7 +208,7 @@ void AnimationEffect::validate(Attribute a, uint &meta, FPx2 *from, FPx2 *to, co } } -quint64 AnimationEffect::p_animate(EffectWindow *w, Attribute a, uint meta, int ms, FPx2 to, const QEasingCurve &curve, int delay, FPx2 from, bool keepAtTarget, bool fullScreenEffect, bool keepAlive) +quint64 AnimationEffect::p_animate(EffectWindow *w, Attribute a, uint meta, int ms, FPx2 to, const QEasingCurve &curve, int delay, FPx2 from, bool keepAtTarget, bool fullScreenEffect, bool keepAlive, GLShader *shader) { const bool waitAtSource = from.isValid(); validate(a, meta, &from, &to, w); @@ -249,7 +250,8 @@ quint64 AnimationEffect::p_animate(EffectWindow *w, Attribute a, uint meta, int waitAtSource, // Whether the animation should be kept at source fullscreen, // Full screen effect lock keepAlive, // Keep alive flag - previousPixmap // Previous window pixmap lock + previousPixmap, // Previous window pixmap lock + shader )); const quint64 ret_id = ++d->m_animCounter; @@ -280,6 +282,9 @@ quint64 AnimationEffect::p_animate(EffectWindow *w, Attribute a, uint meta, int } else { triggerRepaint(); } + if (shader) { + DeformEffect::redirect(w); + } return ret_id; } @@ -405,6 +410,9 @@ bool AnimationEffect::cancel(quint64 animationId) for (AniMap::iterator entry = d->m_animations.begin(), mapEnd = d->m_animations.end(); entry != mapEnd; ++entry) { for (QList::iterator anim = entry->first.begin(), animEnd = entry->first.end(); anim != animEnd; ++anim) { if (anim->id == animationId) { + if (anim->shader && std::none_of(entry->first.begin(), entry->first.end(), [animationId] (const auto &anim) { return anim.id != animationId && anim.shader; })) { + unredirect(entry.key()); + } entry->first.erase(anim); // remove the animation if (entry->first.isEmpty()) { // no other animations on the window, release it. d->m_animations.erase(entry); @@ -642,11 +650,27 @@ void AnimationEffect::paintWindow(EffectWindow *w, int mask, QRegion region, Win case CrossFadePrevious: data.setCrossFadeProgress(progress(*anim)); break; + case Shader: + if (anim->shader && anim->shader->isValid()) { + ShaderBinder binder{anim->shader}; + anim->shader->setUniform("animationProgress", progress(*anim)); + setShader(w, anim->shader); + } + break; + case ShaderUniform: + if (anim->shader && anim->shader->isValid()) { + ShaderBinder binder{anim->shader}; + anim->shader->setUniform("animationProgress", progress(*anim)); + anim->shader->setUniform(anim->meta, interpolated(*anim)); + setShader(w, anim->shader); + } + break; default: break; } } } + effects->paintWindow(w, mask, region, data); } @@ -667,6 +691,9 @@ void AnimationEffect::postPaintScreen() } EffectWindow *window = entry.key(); d->m_justEndedAnimation = anim->id; + if (anim->shader && std::none_of(entry->first.begin(), entry->first.end(), [anim] (const auto &other) { return anim->id != other.id && other.shader; })) { + unredirect(window); + } animationEnded(window, anim->attribute, anim->meta); d->m_justEndedAnimation = 0; // NOTICE animationEnded is an external call and might have called "::animate" @@ -854,6 +881,8 @@ void AnimationEffect::updateLayerRepaints() case Brightness: case Saturation: case CrossFadePrevious: + case Shader: + case ShaderUniform: createRegion = true; break; case Rotation: diff --git a/src/libkwineffects/kwinanimationeffect.h b/src/libkwineffects/kwinanimationeffect.h index cad9298a56..c86f4591ab 100644 --- a/src/libkwineffects/kwinanimationeffect.h +++ b/src/libkwineffects/kwinanimationeffect.h @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include namespace KWin @@ -191,7 +191,7 @@ class AnimationEffectPrivate; * * @since 4.8 */ -class KWINEFFECTS_EXPORT AnimationEffect : public Effect +class KWINEFFECTS_EXPORT AnimationEffect : public DeformEffect { Q_OBJECT @@ -217,6 +217,16 @@ public: Clip, Generic, CrossFadePrevious, + /** + * Performs an animation with a provided shader. + * The float uniform @c animationProgress is set to the current progress of the animation. + **/ + Shader, + /** + * Like Shader, but additionally allows to animate a float uniform passed to the shader. + * The uniform location must be provided as metadata. + **/ + ShaderUniform, NonFloatBase = Position }; Q_ENUM(Attribute) @@ -360,12 +370,13 @@ protected: * @param fullScreen Sets this effect as the active full screen effect for the * duration of the animation. * @param keepAlive Whether closed windows should be kept alive during animation. + * @param shader Optional shader to use to render the window. * @returns An ID that you can use to cancel a running animation. * @since 4.8 */ - quint64 animate(EffectWindow *w, Attribute a, uint meta, int ms, const FPx2 &to, const QEasingCurve &curve = QEasingCurve(), int delay = 0, const FPx2 &from = FPx2(), bool fullScreen = false, bool keepAlive = true) + quint64 animate(EffectWindow *w, Attribute a, uint meta, int ms, const FPx2 &to, const QEasingCurve &curve = QEasingCurve(), int delay = 0, const FPx2 &from = FPx2(), bool fullScreen = false, bool keepAlive = true, GLShader *shader = nullptr) { - return p_animate(w, a, meta, ms, to, curve, delay, from, false, fullScreen, keepAlive); + return p_animate(w, a, meta, ms, to, curve, delay, from, false, fullScreen, keepAlive, shader); } /** @@ -392,12 +403,13 @@ protected: * @param fullScreen Sets this effect as the active full screen effect for the * duration of the animation. * @param keepAlive Whether closed windows should be kept alive during animation. + * @param shader Optional shader to use to render the window. * @returns An ID that you need to use to cancel this manipulation. * @since 4.11 */ - quint64 set(EffectWindow *w, Attribute a, uint meta, int ms, const FPx2 &to, const QEasingCurve &curve = QEasingCurve(), int delay = 0, const FPx2 &from = FPx2(), bool fullScreen = false, bool keepAlive = true) + quint64 set(EffectWindow *w, Attribute a, uint meta, int ms, const FPx2 &to, const QEasingCurve &curve = QEasingCurve(), int delay = 0, const FPx2 &from = FPx2(), bool fullScreen = false, bool keepAlive = true, GLShader *shader = nullptr) { - return p_animate(w, a, meta, ms, to, curve, delay, from, true, fullScreen, keepAlive); + return p_animate(w, a, meta, ms, to, curve, delay, from, true, fullScreen, keepAlive, shader); } /** @@ -506,7 +518,7 @@ protected: AniMap state() const; private: - quint64 p_animate(EffectWindow *w, Attribute a, uint meta, int ms, FPx2 to, const QEasingCurve &curve, int delay, FPx2 from, bool keepAtTarget, bool fullScreenEffect, bool keepAlive); + quint64 p_animate(EffectWindow *w, Attribute a, uint meta, int ms, FPx2 to, const QEasingCurve &curve, int delay, FPx2 from, bool keepAtTarget, bool fullScreenEffect, bool keepAlive, GLShader *shader); QRect clipRect(const QRect &windowRect, const AniData &) const; float interpolated(const AniData &, int i = 0) const; float progress(const AniData &) const; diff --git a/src/libkwineffects/kwineffects.h b/src/libkwineffects/kwineffects.h index d03fbb760f..34967695df 100644 --- a/src/libkwineffects/kwineffects.h +++ b/src/libkwineffects/kwineffects.h @@ -180,7 +180,7 @@ X-KDE-Library=kwin4_effect_cooleffect #define KWIN_EFFECT_API_MAKE_VERSION(major, minor) ((major) << 8 | (minor)) #define KWIN_EFFECT_API_VERSION_MAJOR 0 -#define KWIN_EFFECT_API_VERSION_MINOR 233 +#define KWIN_EFFECT_API_VERSION_MINOR 234 #define KWIN_EFFECT_API_VERSION KWIN_EFFECT_API_MAKE_VERSION( \ KWIN_EFFECT_API_VERSION_MAJOR, KWIN_EFFECT_API_VERSION_MINOR)