kwin: optimizing the blur effect
This patch adds the capability to draw blurred region top to bottom using paintSimpleScreen. REVIEW: 101898
This commit is contained in:
parent
a145fa564c
commit
afe8048afd
2 changed files with 46 additions and 80 deletions
|
@ -34,7 +34,6 @@ KWIN_EFFECT(blur, BlurEffect)
|
||||||
KWIN_EFFECT_SUPPORTED(blur, BlurEffect::supported())
|
KWIN_EFFECT_SUPPORTED(blur, BlurEffect::supported())
|
||||||
KWIN_EFFECT_ENABLEDBYDEFAULT(blur, BlurEffect::enabledByDefault())
|
KWIN_EFFECT_ENABLEDBYDEFAULT(blur, BlurEffect::enabledByDefault())
|
||||||
|
|
||||||
|
|
||||||
BlurEffect::BlurEffect()
|
BlurEffect::BlurEffect()
|
||||||
{
|
{
|
||||||
shader = BlurShader::create();
|
shader = BlurShader::create();
|
||||||
|
@ -157,11 +156,9 @@ QRegion BlurEffect::expand(const QRegion ®ion) const
|
||||||
{
|
{
|
||||||
QRegion expanded;
|
QRegion expanded;
|
||||||
|
|
||||||
if (region.rectCount() < 20) {
|
foreach (const QRect & rect, region.rects()) {
|
||||||
foreach (const QRect & rect, region.rects())
|
|
||||||
expanded += expand(rect);
|
expanded += expand(rect);
|
||||||
} else
|
}
|
||||||
expanded += expand(region.boundingRect());
|
|
||||||
|
|
||||||
return expanded;
|
return expanded;
|
||||||
}
|
}
|
||||||
|
@ -223,86 +220,58 @@ void BlurEffect::prePaintScreen(ScreenPrePaintData &data, int time)
|
||||||
QLinkedList<QRegion> blurRegions;
|
QLinkedList<QRegion> blurRegions;
|
||||||
bool checkDecos = effects->decorationsHaveAlpha() && effects->decorationSupportsBlurBehind();
|
bool checkDecos = effects->decorationsHaveAlpha() && effects->decorationSupportsBlurBehind();
|
||||||
bool clipChanged = false;
|
bool clipChanged = false;
|
||||||
|
m_damagedArea = QRegion();
|
||||||
|
m_currentBlur = QRegion();
|
||||||
|
|
||||||
effects->prePaintScreen(data, time);
|
effects->prePaintScreen(data, time);
|
||||||
|
}
|
||||||
|
|
||||||
// If the whole screen will be repainted anyway, there is no point in
|
void BlurEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time)
|
||||||
// adding to the paint region.
|
{
|
||||||
if (data.mask & (PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS | PAINT_SCREEN_TRANSFORMED))
|
// this effect relies on prePaintWindow being called in the bottom to top order
|
||||||
|
|
||||||
|
effects->prePaintWindow(w, data, time);
|
||||||
|
|
||||||
|
if (!w->isPaintingEnabled()) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (effects->activeFullScreenEffect())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Walk the window list top->bottom and check if the paint region is fully
|
|
||||||
// contained within opaque windows and doesn't intersect any blurred region.
|
|
||||||
QRegion paint = data.paint;
|
|
||||||
for (int i = windows.count() - 1; i >= 0; --i) {
|
|
||||||
EffectWindow *window = windows.at(i);
|
|
||||||
if (!window->isPaintingEnabled())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!window->hasAlpha()) {
|
|
||||||
paint -= window->contentsRect().translated(window->pos());
|
|
||||||
if (paint.isEmpty())
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// The window decoration is treated as an object below the window
|
|
||||||
// contents, so check it after the contents.
|
|
||||||
if (window->hasAlpha() || (checkDecos && window->hasDecoration())) {
|
|
||||||
QRegion r = blurRegion(window);
|
|
||||||
if (r.isEmpty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
r = expand(r.translated(window->pos()));
|
|
||||||
if (r.intersects(paint))
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (paint.isEmpty())
|
// to blur an area partially we have to shrink the opaque area of a window
|
||||||
return;
|
QRegion newClip;
|
||||||
|
const QRegion oldClip = data.clip;
|
||||||
// Walk the list again bottom->top and expand the paint region when
|
const int radius = shader->radius();
|
||||||
// it intersects a blurred region.
|
foreach (const QRect& rect, data.clip.rects()) {
|
||||||
foreach (EffectWindow *window, windows) {
|
newClip |= rect.adjusted(radius,radius,-radius,-radius);
|
||||||
if (!window->isPaintingEnabled())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!window->hasAlpha() && !(checkDecos && window->hasDecoration()))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
QRegion r = blurRegion(window);
|
|
||||||
if (r.isEmpty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
r = expand(r.translated(window->pos()));
|
|
||||||
|
|
||||||
// We can't do a partial repaint of a blurred region
|
|
||||||
if (r.intersects(data.paint)) {
|
|
||||||
data.paint += r;
|
|
||||||
clipChanged = true;
|
|
||||||
} else
|
|
||||||
blurRegions.append(r);
|
|
||||||
}
|
}
|
||||||
|
data.clip = newClip;
|
||||||
|
|
||||||
while (clipChanged) {
|
// we dont have to blur a region we dont see
|
||||||
clipChanged = false;
|
m_currentBlur -= newClip;
|
||||||
QMutableLinkedListIterator<QRegion> i(blurRegions);
|
// if we have to paint a non-opaque part of this window that intersects with the
|
||||||
while (i.hasNext()) {
|
// currently blurred region we have to redraw the whole region
|
||||||
const QRegion r = i.next();
|
if ((data.paint-oldClip).intersects(m_currentBlur)) {
|
||||||
if (!r.intersects(data.paint))
|
data.paint |= m_currentBlur;
|
||||||
continue;
|
}
|
||||||
|
// TODO: make m_currentBlur a list of connected regions
|
||||||
|
|
||||||
data.paint += r;
|
// in case this window has regions to be blurred
|
||||||
clipChanged = true;
|
const QRegion blurArea = blurRegion(w).translated(w->pos());
|
||||||
i.remove();
|
const QRegion expandedBlur = expand(blurArea);
|
||||||
|
// if this window or an window underneath the blurred area is damaged we have to
|
||||||
|
// blur everything
|
||||||
|
if (m_damagedArea.intersects(blurArea) || data.paint.intersects(blurArea)) {
|
||||||
|
data.paint |= expandedBlur;
|
||||||
|
// we have to check again whether we do not damage an already blurred area
|
||||||
|
if (expandedBlur.intersects(m_currentBlur)) {
|
||||||
|
data.paint |= m_currentBlur;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
m_currentBlur |= expandedBlur;
|
||||||
|
|
||||||
// Force the scene to call paintGenericScreen() so the windows are painted bottom -> top
|
// we dont consider damaged areas which are occluded and are not
|
||||||
data.mask |= PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_WITHOUT_FULL_REPAINTS;
|
// explicitly damaged by this window
|
||||||
|
m_damagedArea -= data.clip;
|
||||||
|
m_damagedArea |= data.paint;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BlurEffect::shouldBlur(const EffectWindow *w, int mask, const WindowPaintData &data) const
|
bool BlurEffect::shouldBlur(const EffectWindow *w, int mask, const WindowPaintData &data) const
|
||||||
|
@ -310,12 +279,6 @@ bool BlurEffect::shouldBlur(const EffectWindow *w, int mask, const WindowPaintDa
|
||||||
if (!target->valid() || !shader->isValid())
|
if (!target->valid() || !shader->isValid())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Don't blur anything if we're painting top-to-bottom
|
|
||||||
if (!(mask & (PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_WITHOUT_FULL_REPAINTS |
|
|
||||||
PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS |
|
|
||||||
PAINT_SCREEN_TRANSFORMED)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (effects->activeFullScreenEffect() && !w->data(WindowForceBlurRole).toBool())
|
if (effects->activeFullScreenEffect() && !w->data(WindowForceBlurRole).toBool())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -341,7 +304,7 @@ void BlurEffect::drawWindow(EffectWindow *w, int mask, QRegion region, WindowPai
|
||||||
{
|
{
|
||||||
if (shouldBlur(w, mask, data)) {
|
if (shouldBlur(w, mask, data)) {
|
||||||
const QRect screen(0, 0, displayWidth(), displayHeight());
|
const QRect screen(0, 0, displayWidth(), displayHeight());
|
||||||
const QRegion shape = blurRegion(w).translated(w->pos()) & screen;
|
const QRegion shape = region & blurRegion(w).translated(w->pos()) & screen;
|
||||||
|
|
||||||
if (!shape.isEmpty() && region.intersects(shape.boundingRect()))
|
if (!shape.isEmpty() && region.intersects(shape.boundingRect()))
|
||||||
doBlur(shape, screen, data.opacity * data.contents_opacity);
|
doBlur(shape, screen, data.opacity * data.contents_opacity);
|
||||||
|
|
|
@ -44,6 +44,7 @@ public:
|
||||||
|
|
||||||
void reconfigure(ReconfigureFlags flags);
|
void reconfigure(ReconfigureFlags flags);
|
||||||
void prePaintScreen(ScreenPrePaintData &data, int time);
|
void prePaintScreen(ScreenPrePaintData &data, int time);
|
||||||
|
void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time);
|
||||||
void drawWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data);
|
void drawWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data);
|
||||||
void paintEffectFrame(EffectFrame *frame, QRegion region, double opacity, double frameOpacity);
|
void paintEffectFrame(EffectFrame *frame, QRegion region, double opacity, double frameOpacity);
|
||||||
|
|
||||||
|
@ -66,6 +67,8 @@ private:
|
||||||
GLRenderTarget *target;
|
GLRenderTarget *target;
|
||||||
GLTexture *tex;
|
GLTexture *tex;
|
||||||
long net_wm_blur_region;
|
long net_wm_blur_region;
|
||||||
|
QRegion m_damagedArea; // keeps track of the area which has been damaged (from bottom to top)
|
||||||
|
QRegion m_currentBlur; // keeps track of the currently blured area (from bottom to top)
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace KWin
|
} // namespace KWin
|
||||||
|
|
Loading…
Reference in a new issue