From b6478e1b12f737f87bb94a3192f6eef8c1c6f4b7 Mon Sep 17 00:00:00 2001 From: Philipp Knechtges Date: Sun, 18 Sep 2011 17:53:14 +0200 Subject: [PATCH] kwin: Optimizing Blur Part III This patch introduces some kind of damage propagation. In the old version of the blur effect we had to repaint the whole window if sth behind the blurred area was damaged. The new texture cache, which was introduced by the last patch, gives us the opportunity to only update parts of blurred background texture. This means that the damaged area can only propagate with the speed of the blurring radius per window layer. REVIEW: 102665 --- effects/blur/blur.cpp | 40 ++++++++++++++--------- effects/blur/blur.h | 2 +- effects/presentwindows/presentwindows.cpp | 1 + 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/effects/blur/blur.cpp b/effects/blur/blur.cpp index 3c4a4b88fb..1ce748e93c 100644 --- a/effects/blur/blur.cpp +++ b/effects/blur/blur.cpp @@ -284,17 +284,18 @@ void BlurEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int t // if a window underneath the blurred area is damaged we have to // blur everything if (m_damagedArea.intersects(blurArea)) { - data.paint |= expandedBlur; + const QRegion damagedArea = expand(blurArea & m_damagedArea); + data.paint |= expand(damagedArea); + if (windows.contains(w)) { + windows[w].damagedRegion |= damagedArea; + } // we keep track of the "damage propagation" - m_damagedArea |= expand(blurArea & m_damagedArea); + m_damagedArea |= damagedArea; // we have to check again whether we do not damage a blurred area // of a window we do not cache if (expandedBlur.intersects(m_currentBlur)) { data.paint |= m_currentBlur; } - if (windows.contains(w)) { - windows[w].textureValid = false; - } // Normally we would have shrink the clip of the following windows to get a // full cached copy of the background of this window. But we do not do a full @@ -358,8 +359,8 @@ bool BlurEffect::shouldBlur(const EffectWindow *w, int mask, const WindowPaintDa void BlurEffect::drawWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) { + const QRect screen(0, 0, displayWidth(), displayHeight()); if (shouldBlur(w, mask, data)) { - const QRect screen(0, 0, displayWidth(), displayHeight()); const QRegion shape = region & blurRegion(w).translated(w->pos()) & screen; if (!shape.isEmpty()) { @@ -369,6 +370,10 @@ void BlurEffect::drawWindow(EffectWindow *w, int mask, QRegion region, WindowPai doBlur(shape, screen, data.opacity * data.contents_opacity); } } + } else if (windows.contains(w)) { + // in case the window has a texture cache but is not drawn, we have to reset + // the texture cache + windows[w].damagedRegion = expand(blurRegion(w).translated(w->pos())) & screen; } // Draw the window over the blurred area @@ -485,13 +490,13 @@ void BlurEffect::doCachedBlur(EffectWindow *w, const QRegion& region, const floa if (!windows.contains(w)) { BlurWindowInfo bwi; bwi.blurredBackground = GLTexture(r.width(),r.height()); - bwi.textureValid = false; + bwi.damagedRegion = expanded; windows[w] = bwi; } if (windows[w].blurredBackground.size() != r.size()) { windows[w].blurredBackground = GLTexture(r.width(),r.height()); - windows[w].textureValid = false; + windows[w].damagedRegion = expanded; } GLTexture targetTexture = windows[w].blurredBackground; @@ -510,23 +515,26 @@ void BlurEffect::doCachedBlur(EffectWindow *w, const QRegion& region, const floa pushMatrix(); #endif - if (!windows[w].textureValid) { + const QRegion updateBackground = windows[w].damagedRegion & region; + + if (!updateBackground.isEmpty()) { + const QRect updateRect = (expand(updateBackground) & expanded).boundingRect(); // Create a scratch texture and copy the area in the back buffer that we're // going to blur into it - GLTexture scratch(r.width(), r.height()); + GLTexture scratch(updateRect.width(), updateRect.height()); scratch.setFilter(GL_LINEAR); scratch.setWrapMode(GL_CLAMP_TO_EDGE); scratch.bind(); - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, r.x(), displayHeight() - r.y() - r.height(), - r.width(), r.height()); + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, updateRect.x(), displayHeight() - updateRect.y() - updateRect.height(), + updateRect.width(), updateRect.height()); // Draw the texture on the offscreen framebuffer object, while blurring it horizontally target->attachTexture(targetTexture); GLRenderTarget::pushRenderTarget(target); shader->setDirection(Qt::Horizontal); - shader->setPixelDistance(1.0 / r.width()); + shader->setPixelDistance(1.0 / updateRect.width()); modelViewProjectionMatrix.ortho(0, r.width(), r.height(), 0 , 0, 65535); modelViewProjectionMatrix.translate(-r.x(), -r.y(), 0); @@ -536,7 +544,7 @@ void BlurEffect::doCachedBlur(EffectWindow *w, const QRegion& region, const floa // Set up the texture matrix to transform from screen coordinates // to texture coordinates. textureMatrix.scale(1.0 / scratch.width(), -1.0 / scratch.height(), 1); - textureMatrix.translate(-r.x(), -scratch.height() - r.y(), 0); + textureMatrix.translate(-updateRect.x(), -scratch.height() - updateRect.y(), 0); #ifndef KWIN_HAVE_OPENGLES glMatrixMode(GL_TEXTURE); loadMatrix(textureMatrix); @@ -544,11 +552,11 @@ void BlurEffect::doCachedBlur(EffectWindow *w, const QRegion& region, const floa #endif shader->setTextureMatrix(textureMatrix); - drawRegion(expanded); + drawRegion(updateBackground & screen); GLRenderTarget::popRenderTarget(); scratch.unbind(); - windows[w].textureValid = true; + windows[w].damagedRegion -= updateBackground; } // Now draw the horizontally blurred area back to the backbuffer, while diff --git a/effects/blur/blur.h b/effects/blur/blur.h index d96f9f6057..a1d13c600d 100644 --- a/effects/blur/blur.h +++ b/effects/blur/blur.h @@ -76,7 +76,7 @@ private: struct BlurWindowInfo { GLTexture blurredBackground; // keeps the horizontally blurred background - bool textureValid; + QRegion damagedRegion; }; QHash< const EffectWindow*, BlurWindowInfo > windows; diff --git a/effects/presentwindows/presentwindows.cpp b/effects/presentwindows/presentwindows.cpp index 5e7589c88c..80c258a70b 100755 --- a/effects/presentwindows/presentwindows.cpp +++ b/effects/presentwindows/presentwindows.cpp @@ -246,6 +246,7 @@ void PresentWindowsEffect::postPaintScreen() } } effects->setActiveFullScreenEffect(NULL); + effects->addRepaintFull(); } // Update windows that are changing brightness or opacity