From cf66e4c86d477ea0ff54b7c542460e4313658768 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20L=C3=BCbking?= Date: Sat, 9 Jul 2011 01:26:58 +0200 Subject: [PATCH] KWin: Make damageNotifyEvent handling more aggressively aggregate rects and skip damage handling if the window is already completely damaged. Also avoid QRegion handling during this since we know about the rects and the region is handled when adding the damage anyway. --- composite.cpp | 58 ++++++++++++++++++++++++++++++++------------------- toplevel.h | 1 + 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/composite.cpp b/composite.cpp index 513faaf5c9..1c4b530cac 100644 --- a/composite.cpp +++ b/composite.cpp @@ -620,44 +620,51 @@ typedef union { XDamageNotifyEvent de; } EventUnion; +static QVector damageRects; + void Toplevel::damageNotifyEvent(XDamageNotifyEvent* e) { - QRegion damage(e->area.x, e->area.y, e->area.width, e->area.height); + if (damageRatio == 1.0) // we know that we're completely damaged, no need to tell us again + return; + + const float area = rect().width()*rect().height(); + damageRects.reserve(16); + damageRects.clear(); + damageRects << QRect(e->area.x, e->area.y, e->area.width, e->area.height); + + // we can not easily say anything about the overall ratio since the new rects may intersect the present + float newDamageRatio = damageRects.last().width()*damageRects.last().height() / area; + // compress - int cnt = 1; while (XPending(display())) { EventUnion e2; if (XPeekEvent(display(), &e2.e) && e2.e.type == Extensions::damageNotifyEvent() && e2.e.xany.window == frameId()) { XNextEvent(display(), &e2.e); - if (cnt > 200) { - // If there are way too many damage events in the queue, just discard them + if (damageRatio >= 0.8 || newDamageRatio > 0.8 || damageRects.count() > 15) { + // If there are too many damage events in the queue, just discard them // and damage the whole window. Otherwise the X server can just overload // us with a flood of damage events. Should be probably optimized // in the X server, as this is rather lame. - damage = rect(); + newDamageRatio = 1.0; + damageRects.clear(); continue; } - QRect r(e2.de.area.x, e2.de.area.y, e2.de.area.width, e2.de.area.height); - ++cnt; - // If there are too many damaged rectangles, increase them - // to be multiples of 100x100 px grid, since QRegion get quite - // slow with many rectangles, and there is little to gain by using - // many small rectangles (rather the opposite, several large should - // be often faster). - if (cnt > 50) { - r.setLeft(r.left() / 100 * 100); - r.setRight((r.right() + 99) / 100 * 100); - r.setTop(r.top() / 100 * 100); - r.setBottom((r.bottom() + 99) / 100 * 100); - } - damage += r; + damageRects << QRect(e2.de.area.x, e2.de.area.y, e2.de.area.width, e2.de.area.height); + newDamageRatio += damageRects.last().width()*damageRects.last().height() / area; continue; } break; } - foreach (const QRect & r, damage.rects()) - addDamage(r); + + + if ((damageRects.count() == 1 && damageRects.last() == rect()) || + (damageRects.isEmpty() && newDamageRatio == 1.0)) { + addDamageFull(); + } else { + foreach (const QRect &r, damageRects) + addDamage(r); + } } void Client::damageNotifyEvent(XDamageNotifyEvent* e) @@ -686,6 +693,10 @@ void Toplevel::addDamage(int x, int y, int w, int h) // may be a damage event coming with size larger than the current window size r &= rect(); damage_region += r; + int damageArea = 0; + foreach (const QRect &r2, damage_region.rects()) + damageArea += r2.width()*r2.height(); + damageRatio = float(damageArea) / float(rect().width()*rect().height()); repaints_region += r; emit damaged(this, r); // discard lanczos texture @@ -707,6 +718,7 @@ void Toplevel::addDamageFull() return; damage_region = rect(); repaints_region = rect(); + damageRatio = 1.0; emit damaged(this, rect()); // discard lanczos texture if (effect_window) { @@ -724,6 +736,10 @@ void Toplevel::addDamageFull() void Toplevel::resetDamage(const QRect& r) { damage_region -= r; + int damageArea = 0; + foreach (const QRect &r2, damage_region.rects()) + damageArea += r2.width()*r2.height(); + damageRatio = float(damageArea) / float(rect().width()*rect().height()); } void Toplevel::addRepaint(const QRect& r) diff --git a/toplevel.h b/toplevel.h index 35f1bb57cb..d63d106386 100644 --- a/toplevel.h +++ b/toplevel.h @@ -209,6 +209,7 @@ private: Damage damage_handle; #endif QRegion damage_region; // damage is really damaged window (XDamage) and texture needs + float damageRatio; bool is_shape; EffectWindowImpl* effect_window; QByteArray resource_name;