scene: Pad damage if scale factor is fractional

Floating point arithmetic and/or the use of GL_LINEAR in the pipeline,
may result in visual glitches due to rounding (errors). As a short-term
fix until a proper (more involved) solution is in place for Plasma 6,
pad the damage slightly in all directions to alleviate those effects.
This commit is contained in:
Matthias Dahl 2023-05-09 14:56:21 +02:00
parent 9ac6f71662
commit 56f6bab0c3

View file

@ -241,14 +241,29 @@ static void resetRepaintsHelper(Item *item, SceneDelegate *delegate)
}
}
static void accumulateRepaints(Item *item, SceneDelegate *delegate, QRegion *repaints)
static void accumulateRepaints(Item *item, SceneDelegate *delegate, QRegion *repaints, const bool padDamage)
{
*repaints += item->repaints(delegate);
if (!padDamage) {
*repaints += item->repaints(delegate);
} else {
const auto padding = 1;
for (const QRect region : item->repaints(delegate)) {
if (region.isEmpty() || region == infiniteRegion()) {
*repaints += region;
continue;
}
*repaints += QRect{region.x() - padding, region.y() - padding,
region.width() + 2 * padding, region.height() + 2 * padding};
}
}
item->resetRepaints(delegate);
const auto childItems = item->childItems();
for (Item *childItem : childItems) {
accumulateRepaints(childItem, delegate, repaints);
accumulateRepaints(childItem, delegate, repaints, padDamage);
}
}
@ -275,11 +290,17 @@ void WorkspaceScene::preparePaintGenericScreen()
void WorkspaceScene::preparePaintSimpleScreen()
{
// if a fractional scale factor is used, pad the damage to avoid visual
// glitches due to rounding errors (floating point arithmetic) and/or the
// use of GL_LINEAR in the pipeline
const auto scale = painted_screen->scale();
const bool padDamage = std::trunc(scale) != scale;
for (WindowItem *windowItem : std::as_const(stacking_order)) {
Window *window = windowItem->window();
WindowPrePaintData data;
data.mask = m_paintContext.mask;
accumulateRepaints(windowItem, painted_delegate, &data.paint);
accumulateRepaints(windowItem, painted_delegate, &data.paint, padDamage);
// Clip out the decoration for opaque windows; the decoration is drawn in the second pass.
if (window->opacity() == 1.0) {
@ -314,7 +335,7 @@ void WorkspaceScene::preparePaintSimpleScreen()
}
if (m_dndIcon) {
accumulateRepaints(m_dndIcon.get(), painted_delegate, &m_paintContext.damage);
accumulateRepaints(m_dndIcon.get(), painted_delegate, &m_paintContext.damage, padDamage);
}
}