[effects] Add a simplified fullscreen blur

If a window is fullscreen and wants fullscreen blur behind it, we
use the blur from logout effect. This is mostly intended for the
Application Dashboard which requires a fullscreen blur. The generic
blur effect is not designed for such usage and is rather costly.

This simplified blur just needs framebuffer blit and midmaps. This
makes it rather cheap in usage and also doesn't need a cached texture.

REVIEW: 126906
This commit is contained in:
Martin Gräßlin 2016-01-27 14:15:32 +01:00
parent 1fb0c31bb4
commit 22bd8badbf
2 changed files with 35 additions and 1 deletions

View file

@ -40,6 +40,10 @@ static const QByteArray s_blurAtomName = QByteArrayLiteral("_KDE_NET_WM_BLUR_BEH
BlurEffect::BlurEffect()
{
shader = BlurShader::create();
m_simpleShader = ShaderManager::instance()->generateShaderFromResources(ShaderTrait::MapTexture, QString(), QStringLiteral("logout-blur.frag"));
if (!m_simpleShader->isValid()) {
qCDebug(KWINEFFECTS) << "Simple blur shader failed to load";
}
// Offscreen texture that's used as the target for the horizontal blur pass
// and the source for the vertical pass.
@ -78,6 +82,7 @@ BlurEffect::~BlurEffect()
{
windows.clear();
delete m_simpleShader;
delete shader;
delete target;
}
@ -438,7 +443,9 @@ void BlurEffect::drawWindow(EffectWindow *w, int mask, QRegion region, WindowPai
}
if (!shape.isEmpty()) {
if (m_shouldCache && !translated && !w->isDeleted()) {
if (w->isFullScreen() && GLRenderTarget::blitSupported() && m_simpleShader->isValid() && shape.boundingRect() == w->geometry()) {
doSimpleBlur(w, data.opacity(), data.screenProjectionMatrix());
} else if (m_shouldCache && !translated && !w->isDeleted()) {
doCachedBlur(w, region, data.opacity(), data.screenProjectionMatrix());
} else {
doBlur(shape, screen, data.opacity(), data.screenProjectionMatrix());
@ -461,6 +468,31 @@ void BlurEffect::paintEffectFrame(EffectFrame *frame, QRegion region, double opa
effects->paintEffectFrame(frame, region, opacity, frameOpacity);
}
void BlurEffect::doSimpleBlur(EffectWindow *w, const float opacity, const QMatrix4x4 &screenProjection)
{
// The fragment shader uses a LOD bias of 1.75, so we need 3 mipmap levels.
GLTexture blurTexture = GLTexture(GL_RGBA8, w->size(), 3);
blurTexture.setFilter(GL_LINEAR_MIPMAP_LINEAR);
blurTexture.setWrapMode(GL_CLAMP_TO_EDGE);
target->attachTexture(blurTexture);
target->blitFromFramebuffer(w->geometry(), QRect(QPoint(0, 0), w->size()));
// Unmodified base image
ShaderBinder binder(m_simpleShader);
QMatrix4x4 mvp = screenProjection;
mvp.translate(w->x(), w->y());
m_simpleShader->setUniform(GLShader::ModelViewProjectionMatrix, mvp);
m_simpleShader->setUniform("u_alphaProgress", opacity);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
blurTexture.bind();
blurTexture.generateMipmaps();
blurTexture.render(infiniteRegion(), w->geometry());
blurTexture.unbind();
glDisable(GL_BLEND);
}
void BlurEffect::doBlur(const QRegion& shape, const QRect& screen, const float opacity, const QMatrix4x4 &screenProjection)
{
const QRegion expanded = expand(shape) & screen;

View file

@ -81,6 +81,7 @@ private:
QRegion blurRegion(const EffectWindow *w) const;
bool shouldBlur(const EffectWindow *w, int mask, const WindowPaintData &data) const;
void updateBlurRegion(EffectWindow *w) const;
void doSimpleBlur(EffectWindow *w, const float opacity, const QMatrix4x4 &screenProjection);
void doBlur(const QRegion &shape, const QRect &screen, const float opacity, const QMatrix4x4 &screenProjection);
void doCachedBlur(EffectWindow *w, const QRegion& region, const float opacity, const QMatrix4x4 &screenProjection);
void uploadRegion(QVector2D *&map, const QRegion &region);
@ -88,6 +89,7 @@ private:
private:
BlurShader *shader;
GLShader *m_simpleShader;
GLRenderTarget *target;
GLTexture tex;
long net_wm_blur_region;