kwin: Avoid painting damaged areas which are occluded by another opaque window.
So far we have not used the information that damage events are window-specific, resulting in the behavior that we repainted the damaged area although it might be hidden behind another window. E.g. the CPU-Monitor plasmoid is almost all day occluded by a browser etc. and before this patch we have been repainting the appropiate area every time the plasmoid has been updated. Thx to Thomas Lübking for optimizing the patch. REVIEW: 101846
This commit is contained in:
parent
b4de899b2c
commit
85c5181a81
3 changed files with 100 additions and 42 deletions
|
@ -404,16 +404,6 @@ void Workspace::performCompositing()
|
|||
if (c->readyForPainting())
|
||||
windows.append(c);
|
||||
#endif
|
||||
foreach (Toplevel * c, windows) {
|
||||
// This could be possibly optimized WRT obscuring, but that'd need being already
|
||||
// past prePaint() phase - probably not worth it.
|
||||
repaints_region |= c->repaints().translated(c->pos());
|
||||
repaints_region |= c->decorationPendingRegion();
|
||||
c->resetRepaints(c->decorationRect());
|
||||
if (c->hasShadow()) {
|
||||
c->resetRepaints(c->shadow()->shadowRegion().boundingRect());
|
||||
}
|
||||
}
|
||||
QRegion repaints = repaints_region;
|
||||
// clear all repaints, so that post-pass can add repaints for the next repaint
|
||||
repaints_region = QRegion();
|
||||
|
|
131
scene.cpp
131
scene.cpp
|
@ -114,12 +114,26 @@ void Scene::paintScreen(int* mask, QRegion* region)
|
|||
updateTimeDiff();
|
||||
// preparation step
|
||||
static_cast<EffectsHandlerImpl*>(effects)->startPaint();
|
||||
|
||||
ScreenPrePaintData pdata;
|
||||
pdata.mask = *mask;
|
||||
pdata.paint = *region;
|
||||
|
||||
// region only includes all workspace-specific repaints but some effect (e.g. blur)
|
||||
// rely on the full damaged area
|
||||
QRegion dirtyArea;
|
||||
foreach (Window * w, stacking_order) { // bottom to top
|
||||
Toplevel* topw = w->window();
|
||||
dirtyArea |= topw->repaints().translated(topw->pos());
|
||||
dirtyArea |= topw->decorationPendingRegion();
|
||||
}
|
||||
pdata.paint |= dirtyArea;
|
||||
|
||||
effects->prePaintScreen(pdata, time_diff);
|
||||
*mask = pdata.mask;
|
||||
*region = pdata.paint;
|
||||
// Subtract the dirty region and let finalPaintScreen decide which areas have to be drawn
|
||||
*region |= pdata.paint - dirtyArea;
|
||||
|
||||
if (*mask & (PAINT_SCREEN_TRANSFORMED | PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS)) {
|
||||
// Region painting is not possible with transformations,
|
||||
// because screen damage doesn't match transformed positions.
|
||||
|
@ -188,6 +202,18 @@ void Scene::paintGenericScreen(int orig_mask, ScreenPaintData)
|
|||
paintBackground(infiniteRegion());
|
||||
QList< Phase2Data > phase2;
|
||||
foreach (Window * w, stacking_order) { // bottom to top
|
||||
Toplevel* topw = w->window();
|
||||
painted_region |= topw->repaints().translated(topw->pos());
|
||||
painted_region |= topw->decorationPendingRegion();
|
||||
|
||||
// Reset the repaint_region.
|
||||
// This has to be done here because many effects schedule a repaint for
|
||||
// the next frame within Effects::prePaintWindow.
|
||||
topw->resetRepaints(topw->decorationRect());
|
||||
if (topw->hasShadow()) {
|
||||
topw->resetRepaints(topw->shadow()->shadowRegion().boundingRect());
|
||||
}
|
||||
|
||||
WindowPrePaintData data;
|
||||
data.mask = orig_mask | (w->isOpaque() ? PAINT_WINDOW_OPAQUE : PAINT_WINDOW_TRANSLUCENT);
|
||||
w->resetPaintingEnabled();
|
||||
|
@ -225,16 +251,28 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region)
|
|||
| PAINT_SCREEN_WITH_TRANSFORMED_WINDOWS_WITHOUT_FULL_REPAINTS
|
||||
| PAINT_WINDOW_TRANSLUCENT | PAINT_WINDOW_OPAQUE)) == 0);
|
||||
QHash< Window*, Phase2Data > phase2data;
|
||||
// Draw each opaque window top to bottom, subtracting the bounding rect of
|
||||
// each window from the clip region after it's been drawn.
|
||||
for (int i = stacking_order.count() - 1; // top to bottom
|
||||
i >= 0;
|
||||
--i) {
|
||||
|
||||
QRegion dirtyArea = region;
|
||||
for (int i = 0; // do prePaintWindow bottom to top
|
||||
i < stacking_order.count();
|
||||
++i) {
|
||||
Window* w = stacking_order[ i ];
|
||||
Toplevel* topw = w->window();
|
||||
WindowPrePaintData data;
|
||||
data.mask = orig_mask | (w->isOpaque() ? PAINT_WINDOW_OPAQUE : PAINT_WINDOW_TRANSLUCENT);
|
||||
w->resetPaintingEnabled();
|
||||
data.paint = region;
|
||||
data.paint |= topw->repaints().translated(topw->pos());
|
||||
data.paint |= topw->decorationPendingRegion();
|
||||
dirtyArea |= data.paint;
|
||||
|
||||
// Reset the repaint_region.
|
||||
// This has to be done here because many effects schedule a repaint for
|
||||
// the next frame within Effects::prePaintWindow.
|
||||
topw->resetRepaints(topw->decorationRect());
|
||||
if (topw->hasShadow()) {
|
||||
topw->resetRepaints(topw->shadow()->shadowRegion().boundingRect());
|
||||
}
|
||||
// Clip out the decoration for opaque windows; the decoration is drawn in the second pass
|
||||
data.clip = w->isOpaque() ? w->clientShape().translated(w->x(), w->y()) : QRegion();
|
||||
data.quads = w->buildQuads();
|
||||
|
@ -251,8 +289,6 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region)
|
|||
w->suspendUnredirect(true);
|
||||
continue;
|
||||
}
|
||||
if (data.paint != region) // prepaint added area to draw
|
||||
painted_region |= data.paint; // make sure it makes it to the screen
|
||||
// Schedule the window for painting
|
||||
phase2data[w] = Phase2Data(w, data.paint, data.clip, data.mask, data.quads);
|
||||
// no transformations, but translucency requires window pixmap
|
||||
|
@ -262,39 +298,70 @@ void Scene::paintSimpleScreen(int orig_mask, QRegion region)
|
|||
// First opaque windows, top to bottom
|
||||
// This also calculates correct paint regions for windows, also taking
|
||||
// care of clipping
|
||||
QRegion allclips;
|
||||
QRegion allclips, upperTranslucentDamage;
|
||||
for (int i = stacking_order.count() - 1; i >= 0; --i) {
|
||||
Window* w = stacking_order[ i ];
|
||||
if (!phase2data.contains(w))
|
||||
QHash< Window*, Phase2Data >::iterator data = phase2data.find(stacking_order[ i ]);
|
||||
if (data == phase2data.end())
|
||||
continue;
|
||||
Phase2Data d = phase2data[w];
|
||||
// Calculate correct paint region and take the clip region into account
|
||||
d.region = painted_region - allclips;
|
||||
allclips |= d.clip;
|
||||
if (d.mask & PAINT_WINDOW_TRANSLUCENT) {
|
||||
// For translucent windows, the paint region must contain the
|
||||
// entire painted area, except areas clipped by opaque windows
|
||||
// above the translucent window
|
||||
phase2data[w].region = d.region;
|
||||
} else {
|
||||
|
||||
Toplevel *tlw = data.key()->window();
|
||||
// In case there is a window with a higher stackposition which has translucent regions
|
||||
// (e.g. decorations) that still have to be drawn, we also have to repaint the current window
|
||||
// in these particular regions
|
||||
data->region |= (upperTranslucentDamage & tlw->decorationRect().translated(tlw->pos()));
|
||||
|
||||
// subtract the parts which have possibly been drawn already as part of
|
||||
// a higher opaque window
|
||||
data->region -= allclips;
|
||||
|
||||
if (!(data->mask & PAINT_WINDOW_TRANSLUCENT)) {
|
||||
// clip away this region for all windows below this one
|
||||
allclips |= data->clip;
|
||||
// Paint the opaque window
|
||||
paintWindow(d.window, d.mask, d.region, d.quads);
|
||||
// Clip out the client area, so we only draw the decoration in the next pass
|
||||
phase2data[w].region = d.region - d.clip;
|
||||
phase2data[w].mask |= PAINT_DECORATION_ONLY;
|
||||
data->painted_1stpass = data->clip & data->region;
|
||||
paintWindow(data->window, data->mask, data->painted_1stpass, data->quads);
|
||||
painted_region |= data->painted_1stpass;
|
||||
|
||||
// Clip out the client area, so we only draw the rest in the next pass
|
||||
data->region -= data->clip;
|
||||
// if prePaintWindow didnt change the clipping area we only have to paint
|
||||
// the decoration
|
||||
if (data-> clip == data.key()->clientShape().translated(data.key()->x(), data.key()->y())) {
|
||||
data->mask |= PAINT_DECORATION_ONLY;
|
||||
}
|
||||
}
|
||||
// extend the translucent damage for windows below this by remaining (translucent) regions
|
||||
upperTranslucentDamage |= data->region;
|
||||
}
|
||||
// Fill any areas of the root window not covered by windows
|
||||
if (!(orig_mask & PAINT_SCREEN_BACKGROUND_FIRST))
|
||||
paintBackground(painted_region - allclips);
|
||||
|
||||
QRegion painted_2ndpass;
|
||||
// Fill any areas of the root window not covered by opaque windows
|
||||
if (!(orig_mask & PAINT_SCREEN_BACKGROUND_FIRST)) {
|
||||
painted_2ndpass = dirtyArea - allclips;
|
||||
paintBackground(painted_2ndpass);
|
||||
}
|
||||
|
||||
// Now walk the list bottom to top, drawing translucent windows.
|
||||
QRegion lowerOpaqueDamage;
|
||||
for (int i = 0; i < stacking_order.count(); i++) {
|
||||
Window* w = stacking_order[ i ];
|
||||
if (!phase2data.contains(w))
|
||||
QHash< Window*, Phase2Data >::iterator data = phase2data.find(stacking_order[ i ]);
|
||||
if (data == phase2data.end())
|
||||
continue;
|
||||
Phase2Data d = phase2data[w];
|
||||
paintWindow(d.window, d.mask, d.region, d.quads);
|
||||
|
||||
Toplevel *tlw = data.key()->window();
|
||||
|
||||
// add all regions of the lower windows which have already be drawn in the 1st pass
|
||||
data->region |= (lowerOpaqueDamage & tlw->decorationRect().translated(tlw->pos()));
|
||||
// and extend that region by opaque parts of ourself
|
||||
lowerOpaqueDamage |= data->painted_1stpass;
|
||||
|
||||
// add all regions which have been drawn so far in the 2nd pass
|
||||
painted_2ndpass |= data->region;
|
||||
data->region = painted_2ndpass;
|
||||
|
||||
paintWindow(data->window, data->mask, data->region, data->quads);
|
||||
}
|
||||
painted_region |= painted_2ndpass;
|
||||
}
|
||||
|
||||
void Scene::paintWindow(Window* w, int mask, QRegion region, WindowQuadList quads)
|
||||
|
|
1
scene.h
1
scene.h
|
@ -136,6 +136,7 @@ protected:
|
|||
Window* window;
|
||||
QRegion region;
|
||||
QRegion clip;
|
||||
QRegion painted_1stpass;
|
||||
int mask;
|
||||
WindowQuadList quads;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue