Fix decoration rendering with scale factor < 1
QPainter won't let paint with a device pixel ratio less than 1. There are used to be workarounds to force a device pixel ratio of 1, but they were removed with fractional scaling corner fix. This change makes sure that the decoration renderer forces a device pixel ratio of 1 if the output's scale factor is less than 1 so calculated texture coordinates match where window borders are rendered in the texture atlas. BUG: 449681
This commit is contained in:
parent
a428630ea4
commit
bb935aa5de
7 changed files with 28 additions and 33 deletions
|
@ -68,6 +68,12 @@ void DecorationRenderer::resetDamage()
|
|||
m_damage = QRegion();
|
||||
}
|
||||
|
||||
qreal DecorationRenderer::effectiveDevicePixelRatio() const
|
||||
{
|
||||
// QPainter won't let paint with a device pixel ratio less than 1.
|
||||
return std::max(qreal(1.0), devicePixelRatio());
|
||||
}
|
||||
|
||||
qreal DecorationRenderer::devicePixelRatio() const
|
||||
{
|
||||
return m_devicePixelRatio;
|
||||
|
@ -107,7 +113,7 @@ QImage DecorationRenderer::renderToImage(const QRect &geo)
|
|||
image.fill(Qt::transparent);
|
||||
QPainter p(&image);
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
p.setWindow(QRect(geo.topLeft(), geo.size() * qPainterEffectiveDevicePixelRatio(&p)));
|
||||
p.setWindow(QRect(geo.topLeft(), geo.size() * effectiveDevicePixelRatio()));
|
||||
p.setClipRect(geo);
|
||||
renderToPainter(&p, geo);
|
||||
return image;
|
||||
|
@ -230,7 +236,7 @@ WindowQuadList DecorationItem::buildQuads() const
|
|||
}
|
||||
|
||||
QRect left, top, right, bottom;
|
||||
const qreal devicePixelRatio = m_renderer->devicePixelRatio();
|
||||
const qreal devicePixelRatio = m_renderer->effectiveDevicePixelRatio();
|
||||
const int texturePad = DecorationRenderer::TexturePad;
|
||||
|
||||
if (const AbstractClient *client = qobject_cast<const AbstractClient *>(m_window)) {
|
||||
|
|
|
@ -38,6 +38,7 @@ public:
|
|||
void addDamage(const QRegion ®ion);
|
||||
void resetDamage();
|
||||
|
||||
qreal effectiveDevicePixelRatio() const;
|
||||
qreal devicePixelRatio() const;
|
||||
void setDevicePixelRatio(qreal dpr);
|
||||
|
||||
|
|
|
@ -1536,9 +1536,10 @@ void SceneOpenGLDecorationRenderer::render(const QRegion ®ion)
|
|||
QRect left, top, right, bottom;
|
||||
client()->client()->layoutDecorationRects(left, top, right, bottom);
|
||||
|
||||
const int topHeight = std::ceil(top.height() * devicePixelRatio());
|
||||
const int bottomHeight = std::ceil(bottom.height() * devicePixelRatio());
|
||||
const int leftWidth = std::ceil(left.width() * devicePixelRatio());
|
||||
const qreal devicePixelRatio = effectiveDevicePixelRatio();
|
||||
const int topHeight = std::ceil(top.height() * devicePixelRatio);
|
||||
const int bottomHeight = std::ceil(bottom.height() * devicePixelRatio);
|
||||
const int leftWidth = std::ceil(left.width() * devicePixelRatio);
|
||||
|
||||
const QPoint topPosition(0, 0);
|
||||
const QPoint bottomPosition(0, topPosition.y() + topHeight + (2 * TexturePad));
|
||||
|
@ -1547,14 +1548,15 @@ void SceneOpenGLDecorationRenderer::render(const QRegion ®ion)
|
|||
|
||||
const QRect dirtyRect = region.boundingRect();
|
||||
|
||||
renderPart(top.intersected(dirtyRect), top, topPosition);
|
||||
renderPart(bottom.intersected(dirtyRect), bottom, bottomPosition);
|
||||
renderPart(left.intersected(dirtyRect), left, leftPosition, true);
|
||||
renderPart(right.intersected(dirtyRect), right, rightPosition, true);
|
||||
renderPart(top.intersected(dirtyRect), top, topPosition, devicePixelRatio);
|
||||
renderPart(bottom.intersected(dirtyRect), bottom, bottomPosition, devicePixelRatio);
|
||||
renderPart(left.intersected(dirtyRect), left, leftPosition, devicePixelRatio, true);
|
||||
renderPart(right.intersected(dirtyRect), right, rightPosition, devicePixelRatio, true);
|
||||
}
|
||||
|
||||
void SceneOpenGLDecorationRenderer::renderPart(const QRect &rect, const QRect &partRect,
|
||||
const QPoint &textureOffset, bool rotated)
|
||||
const QPoint &textureOffset,
|
||||
qreal devicePixelRatio, bool rotated)
|
||||
{
|
||||
if (!rect.isValid()) {
|
||||
return;
|
||||
|
@ -1567,7 +1569,7 @@ void SceneOpenGLDecorationRenderer::renderPart(const QRect &rect, const QRect &p
|
|||
int verticalPadding = padding.top() + padding.bottom();
|
||||
int horizontalPadding = padding.left() + padding.right();
|
||||
|
||||
QSize imageSize = rect.size() * devicePixelRatio();
|
||||
QSize imageSize = rect.size() * devicePixelRatio;
|
||||
if (rotated) {
|
||||
imageSize = QSize(imageSize.height(), imageSize.width());
|
||||
}
|
||||
|
@ -1575,12 +1577,12 @@ void SceneOpenGLDecorationRenderer::renderPart(const QRect &rect, const QRect &p
|
|||
paddedImageSize.rheight() += verticalPadding;
|
||||
paddedImageSize.rwidth() += horizontalPadding;
|
||||
QImage image(paddedImageSize, QImage::Format_ARGB32_Premultiplied);
|
||||
image.setDevicePixelRatio(devicePixelRatio());
|
||||
image.setDevicePixelRatio(devicePixelRatio);
|
||||
image.fill(Qt::transparent);
|
||||
|
||||
QRect padClip = QRect(padding.left(), padding.top(), imageSize.width(), imageSize.height());
|
||||
QPainter painter(&image);
|
||||
const qreal inverseScale = 1.0 / devicePixelRatio();
|
||||
const qreal inverseScale = 1.0 / devicePixelRatio;
|
||||
painter.scale(inverseScale, inverseScale);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.setClipRect(padClip);
|
||||
|
@ -1589,7 +1591,7 @@ void SceneOpenGLDecorationRenderer::renderPart(const QRect &rect, const QRect &p
|
|||
painter.translate(0, imageSize.height());
|
||||
painter.rotate(-90);
|
||||
}
|
||||
painter.scale(devicePixelRatio(), devicePixelRatio());
|
||||
painter.scale(devicePixelRatio, devicePixelRatio);
|
||||
painter.translate(-rect.topLeft());
|
||||
renderToPainter(&painter, rect);
|
||||
painter.end();
|
||||
|
@ -1597,7 +1599,7 @@ void SceneOpenGLDecorationRenderer::renderPart(const QRect &rect, const QRect &p
|
|||
// fill padding pixels by copying from the neighbour row
|
||||
clamp(image, padClip);
|
||||
|
||||
QPoint dirtyOffset = (rect.topLeft() - partRect.topLeft()) * devicePixelRatio();
|
||||
QPoint dirtyOffset = (rect.topLeft() - partRect.topLeft()) * devicePixelRatio;
|
||||
if (padding.top() == 0) {
|
||||
dirtyOffset.ry() += TexturePad;
|
||||
}
|
||||
|
@ -1641,7 +1643,7 @@ void SceneOpenGLDecorationRenderer::resizeTexture()
|
|||
qMax(left.height(), right.height()));
|
||||
size.rheight() = top.height() + bottom.height() +
|
||||
left.width() + right.width();
|
||||
size *= devicePixelRatio();
|
||||
size *= effectiveDevicePixelRatio();
|
||||
|
||||
size.rheight() += 4 * (2 * TexturePad);
|
||||
size.rwidth() += 2 * TexturePad;
|
||||
|
|
|
@ -213,7 +213,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
void renderPart(const QRect &rect, const QRect &partRect, const QPoint &textureOffset, bool rotated = false);
|
||||
void renderPart(const QRect &rect, const QRect &partRect, const QPoint &textureOffset, qreal devicePixelRatio, bool rotated = false);
|
||||
static const QMargins texturePadForPart(const QRect &rect, const QRect &partRect);
|
||||
void resizeTexture();
|
||||
QScopedPointer<GLTexture> m_texture;
|
||||
|
|
|
@ -444,7 +444,7 @@ void SceneQPainterDecorationRenderer::render(const QRegion ®ion)
|
|||
}
|
||||
QPainter painter(&m_images[index]);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
painter.setWindow(QRect(partRect.topLeft(), partRect.size() * qPainterEffectiveDevicePixelRatio(&painter)));
|
||||
painter.setWindow(QRect(partRect.topLeft(), partRect.size() * effectiveDevicePixelRatio()));
|
||||
painter.setClipRect(rect);
|
||||
painter.save();
|
||||
// clear existing part
|
||||
|
@ -466,7 +466,7 @@ void SceneQPainterDecorationRenderer::resizeImages()
|
|||
client()->client()->layoutDecorationRects(left, top, right, bottom);
|
||||
|
||||
auto checkAndCreate = [this](int index, const QSize &size) {
|
||||
auto dpr = devicePixelRatio();
|
||||
auto dpr = effectiveDevicePixelRatio();
|
||||
if (m_images[index].size() != size * dpr ||
|
||||
m_images[index].devicePixelRatio() != dpr)
|
||||
{
|
||||
|
|
|
@ -181,11 +181,6 @@ Qt::KeyboardModifiers x11ToQtKeyboardModifiers(int state)
|
|||
return ret;
|
||||
}
|
||||
|
||||
qreal qPainterEffectiveDevicePixelRatio(const QPainter *painter)
|
||||
{
|
||||
return std::max(qreal(1), painter->device()->devicePixelRatioF());
|
||||
}
|
||||
|
||||
QPoint popupOffset(const QRect &anchorRect, const Qt::Edges anchorEdge, const Qt::Edges gravity, const QSize popupSize)
|
||||
{
|
||||
QPoint anchorPoint;
|
||||
|
|
|
@ -123,15 +123,6 @@ void KWIN_EXPORT ungrabXServer();
|
|||
bool KWIN_EXPORT grabXKeyboard(xcb_window_t w = XCB_WINDOW_NONE);
|
||||
void KWIN_EXPORT ungrabXKeyboard();
|
||||
|
||||
/**
|
||||
* QPainter::setWindow() doesn't work as expected when the device pixel ratio of the paint
|
||||
* device is less than 1.
|
||||
*
|
||||
* QPainter simply doesn't allow the effective scale factor to be less than 1. Use this function
|
||||
* to determine the effective device pixel ratio by which the window rect has to be scaled.
|
||||
*/
|
||||
qreal KWIN_EXPORT qPainterEffectiveDevicePixelRatio(const QPainter *painter);
|
||||
|
||||
static inline QRegion mapRegion(const QMatrix4x4 &matrix, const QRegion ®ion)
|
||||
{
|
||||
QRegion result;
|
||||
|
|
Loading…
Reference in a new issue