Commit 47b330ea authored by Martin Flöser's avatar Martin Flöser
Browse files

[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.
parent 7dddf305
......@@ -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)
{
}
......
......@@ -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
......
......@@ -9,6 +9,7 @@
*/
#include "kwinanimationeffect.h"
#include "kwinglutils.h"
#include "anidata_p.h"
#include <QAction>
......@@ -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<AniData>::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:
......
......@@ -14,7 +14,7 @@
#include <QEasingCurve>
#include <QElapsedTimer>
#include <QtMath>
#include <kwineffects.h>
#include <kwindeformeffect.h>
#include <kwineffects_export.h>
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;
......
......@@ -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)
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment