Provide SurfaceItem::shape as a floating vector
Our logical co-ordinates for shape can be floating. The shape is used to determine final vertices on screen. The commit appears to introduce some new loops but they're mostly what QRegion would be doing internally so it shouldn't impact performance. For most cases we just have a single rectangle in our shape anyway. opaqueRegion is unchanged for now.
This commit is contained in:
parent
482741499d
commit
bcd9f1e958
15 changed files with 71 additions and 42 deletions
|
@ -148,16 +148,21 @@ DecorationItem::DecorationItem(KDecoration2::Decoration *decoration, Window *win
|
|||
handleOutputChanged();
|
||||
}
|
||||
|
||||
QRegion DecorationItem::shape() const
|
||||
QVector<QRectF> DecorationItem::shape() const
|
||||
{
|
||||
QRectF left, top, right, bottom;
|
||||
m_window->layoutDecorationRects(left, top, right, bottom);
|
||||
return QRegion(left.toRect()).united(top.toRect()).united(right.toRect()).united(bottom.toRect());
|
||||
return {left, top, right, bottom};
|
||||
}
|
||||
|
||||
QRegion DecorationItem::opaque() const
|
||||
{
|
||||
return m_window->decorationHasAlpha() ? QRegion() : shape();
|
||||
if (m_window->decorationHasAlpha()) {
|
||||
return QRegion();
|
||||
}
|
||||
QRectF left, top, right, bottom;
|
||||
m_window->layoutDecorationRects(left, top, right, bottom);
|
||||
return QRegion(left.toRect()).united(top.toRect()).united(right.toRect()).united(bottom.toRect());
|
||||
}
|
||||
|
||||
void DecorationItem::preprocess()
|
||||
|
|
|
@ -83,7 +83,7 @@ public:
|
|||
DecorationRenderer *renderer() const;
|
||||
Window *window() const;
|
||||
|
||||
QRegion shape() const override final;
|
||||
QVector<QRectF> shape() const override final;
|
||||
QRegion opaque() const override final;
|
||||
|
||||
private Q_SLOTS:
|
||||
|
|
|
@ -169,9 +169,9 @@ void Item::updateBoundingRect()
|
|||
}
|
||||
}
|
||||
|
||||
QRegion Item::shape() const
|
||||
QVector<QRectF> Item::shape() const
|
||||
{
|
||||
return rect().toAlignedRect();
|
||||
return QVector<QRectF>();
|
||||
}
|
||||
|
||||
QRegion Item::opaque() const
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <QMatrix4x4>
|
||||
#include <QObject>
|
||||
#include <QVector>
|
||||
|
||||
#include <optional>
|
||||
|
||||
|
@ -51,7 +52,7 @@ public:
|
|||
*/
|
||||
QRectF boundingRect() const;
|
||||
|
||||
virtual QRegion shape() const;
|
||||
virtual QVector<QRectF> shape() const;
|
||||
virtual QRegion opaque() const;
|
||||
|
||||
/**
|
||||
|
|
|
@ -386,8 +386,18 @@ void SceneOpenGL::createRenderNode(Item *item, RenderContext *context)
|
|||
SurfacePixmap *pixmap = surfaceItem->pixmap();
|
||||
if (pixmap) {
|
||||
if (!geometry.isEmpty()) {
|
||||
bool hasAlpha = pixmap->hasAlphaChannel();
|
||||
bool isCompletelyOpaque = true;
|
||||
// Don't bother with blending if the entire surface is opaque
|
||||
bool hasAlpha = pixmap->hasAlphaChannel() && !surfaceItem->shape().subtracted(surfaceItem->opaque()).isEmpty();
|
||||
const QVector<QRectF> shape = surfaceItem->shape();
|
||||
for (const QRectF &shapePart : shape) {
|
||||
if (!item->opaque().contains(shapePart.toRect())) {
|
||||
isCompletelyOpaque = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
hasAlpha &= !isCompletelyOpaque;
|
||||
|
||||
context->renderNodes.append(RenderNode{
|
||||
.texture = bindSurfaceTexture(surfaceItem),
|
||||
.geometry = geometry,
|
||||
|
|
|
@ -167,7 +167,7 @@ void SceneQPainter::renderSurfaceItem(QPainter *painter, SurfaceItem *surfaceIte
|
|||
}
|
||||
surfaceItem->resetDamage();
|
||||
|
||||
const QRegion shape = surfaceItem->shape();
|
||||
const QVector<QRectF> shape = surfaceItem->shape();
|
||||
for (const QRectF rect : shape) {
|
||||
const QMatrix4x4 matrix = surfaceItem->surfaceToBufferMatrix();
|
||||
const QPointF bufferTopLeft = matrix.map(rect.topLeft());
|
||||
|
|
|
@ -130,11 +130,11 @@ WindowQuadList SurfaceItem::buildQuads() const
|
|||
return {};
|
||||
}
|
||||
|
||||
const QRegion region = shape();
|
||||
const QVector<QRectF> region = shape();
|
||||
const auto size = pixmap()->size();
|
||||
|
||||
WindowQuadList quads;
|
||||
quads.reserve(region.rectCount());
|
||||
quads.reserve(region.count());
|
||||
|
||||
for (const QRectF rect : region) {
|
||||
WindowQuad quad;
|
||||
|
|
|
@ -28,9 +28,9 @@ SurfaceItemInternal::SurfaceItemInternal(InternalWindow *window, Item *parent)
|
|||
setSurfaceToBufferMatrix(surfaceToBufferMatrix);
|
||||
}
|
||||
|
||||
QRegion SurfaceItemInternal::shape() const
|
||||
QVector<QRectF> SurfaceItemInternal::shape() const
|
||||
{
|
||||
return QRegion(rect().toAlignedRect());
|
||||
return {rect()};
|
||||
}
|
||||
|
||||
std::unique_ptr<SurfacePixmap> SurfaceItemInternal::createPixmap()
|
||||
|
|
|
@ -25,7 +25,7 @@ class KWIN_EXPORT SurfaceItemInternal : public SurfaceItem
|
|||
public:
|
||||
explicit SurfaceItemInternal(InternalWindow *window, Item *parent = nullptr);
|
||||
|
||||
QRegion shape() const override;
|
||||
QVector<QRectF> shape() const override;
|
||||
|
||||
private Q_SLOTS:
|
||||
void handleBufferGeometryChanged(Window *window, const QRectF &old);
|
||||
|
|
|
@ -53,9 +53,9 @@ SurfaceItemWayland::SurfaceItemWayland(KWaylandServer::SurfaceInterface *surface
|
|||
setSurfaceToBufferMatrix(surface->surfaceToBufferMatrix());
|
||||
}
|
||||
|
||||
QRegion SurfaceItemWayland::shape() const
|
||||
QVector<QRectF> SurfaceItemWayland::shape() const
|
||||
{
|
||||
return QRegion(rect().toAlignedRect());
|
||||
return {rect()};
|
||||
}
|
||||
|
||||
QRegion SurfaceItemWayland::opaque() const
|
||||
|
@ -208,12 +208,16 @@ SurfaceItemXwayland::SurfaceItemXwayland(Window *window, Item *parent)
|
|||
connect(window, &Window::geometryShapeChanged, this, &SurfaceItemXwayland::discardQuads);
|
||||
}
|
||||
|
||||
QRegion SurfaceItemXwayland::shape() const
|
||||
QVector<QRectF> SurfaceItemXwayland::shape() const
|
||||
{
|
||||
const QRectF clipRect = rect() & window()->clientGeometry().translated(-window()->bufferGeometry().topLeft());
|
||||
const QRegion shape = window()->shapeRegion();
|
||||
QVector<QRectF> shape = window()->shapeRegion();
|
||||
|
||||
return shape & clipRect.toRect();
|
||||
// bounded to clipRect
|
||||
for (QRectF &shapePart : shape) {
|
||||
shapePart = shapePart.intersected(clipRect);
|
||||
}
|
||||
return shape;
|
||||
}
|
||||
|
||||
} // namespace KWin
|
||||
|
|
|
@ -29,7 +29,7 @@ public:
|
|||
explicit SurfaceItemWayland(KWaylandServer::SurfaceInterface *surface,
|
||||
Window *window, Item *parent = nullptr);
|
||||
|
||||
QRegion shape() const override;
|
||||
QVector<QRectF> shape() const override;
|
||||
QRegion opaque() const override;
|
||||
ContentType contentType() const override;
|
||||
|
||||
|
@ -88,7 +88,7 @@ class KWIN_EXPORT SurfaceItemXwayland : public SurfaceItemWayland
|
|||
public:
|
||||
explicit SurfaceItemXwayland(Window *window, Item *parent = nullptr);
|
||||
|
||||
QRegion shape() const override;
|
||||
QVector<QRectF> shape() const override;
|
||||
};
|
||||
|
||||
} // namespace KWin
|
||||
|
|
|
@ -138,21 +138,29 @@ void SurfaceItemX11::handleGeometryShapeChanged()
|
|||
discardQuads();
|
||||
}
|
||||
|
||||
QRegion SurfaceItemX11::shape() const
|
||||
QVector<QRectF> SurfaceItemX11::shape() const
|
||||
{
|
||||
const QRectF clipRect = window()->clientGeometry().translated(-window()->bufferGeometry().topLeft());
|
||||
const QRegion shape = window()->shapeRegion();
|
||||
|
||||
return shape & clipRect.toAlignedRect();
|
||||
QVector<QRectF> shape = window()->shapeRegion();
|
||||
// bounded to clipRect
|
||||
for (QRectF &shapePart : shape) {
|
||||
shapePart = shapePart.intersected(clipRect);
|
||||
}
|
||||
return shape;
|
||||
}
|
||||
|
||||
QRegion SurfaceItemX11::opaque() const
|
||||
{
|
||||
if (!window()->hasAlpha()) {
|
||||
return shape();
|
||||
} else {
|
||||
return window()->opaqueRegion() & shape();
|
||||
QRegion shapeRegion;
|
||||
for (const QRectF &shapePart : shape()) {
|
||||
shapeRegion |= shapePart.toRect();
|
||||
}
|
||||
if (!window()->hasAlpha()) {
|
||||
return shapeRegion;
|
||||
} else {
|
||||
return window()->opaqueRegion() & shapeRegion;
|
||||
}
|
||||
return QRegion();
|
||||
}
|
||||
|
||||
std::unique_ptr<SurfacePixmap> SurfaceItemX11::createPixmap()
|
||||
|
|
|
@ -32,7 +32,7 @@ public:
|
|||
void waitForDamage();
|
||||
void destroyDamage();
|
||||
|
||||
QRegion shape() const override;
|
||||
QVector<QRectF> shape() const override;
|
||||
QRegion opaque() const override;
|
||||
|
||||
private Q_SLOTS:
|
||||
|
|
|
@ -483,13 +483,12 @@ void Window::getWmOpaqueRegion()
|
|||
const auto rects = info->opaqueRegion();
|
||||
QRegion new_opaque_region;
|
||||
for (const auto &r : rects) {
|
||||
new_opaque_region += Xcb::fromXNative(QRect(r.pos.x, r.pos.y, r.size.width, r.size.height)).toAlignedRect();
|
||||
new_opaque_region |= Xcb::fromXNative(QRect(r.pos.x, r.pos.y, r.size.width, r.size.height)).toRect();
|
||||
}
|
||||
|
||||
opaque_region = new_opaque_region;
|
||||
}
|
||||
|
||||
QRegion Window::shapeRegion() const
|
||||
QVector<QRectF> Window::shapeRegion() const
|
||||
{
|
||||
if (m_shapeRegionIsValid) {
|
||||
return m_shapeRegion;
|
||||
|
@ -501,19 +500,21 @@ QRegion Window::shapeRegion() const
|
|||
auto cookie = xcb_shape_get_rectangles_unchecked(kwinApp()->x11Connection(), frameId(), XCB_SHAPE_SK_BOUNDING);
|
||||
UniqueCPtr<xcb_shape_get_rectangles_reply_t> reply(xcb_shape_get_rectangles_reply(kwinApp()->x11Connection(), cookie, nullptr));
|
||||
if (reply) {
|
||||
m_shapeRegion = QRegion();
|
||||
m_shapeRegion.clear();
|
||||
const xcb_rectangle_t *rects = xcb_shape_get_rectangles_rectangles(reply.get());
|
||||
const int rectCount = xcb_shape_get_rectangles_rectangles_length(reply.get());
|
||||
for (int i = 0; i < rectCount; ++i) {
|
||||
m_shapeRegion += Xcb::fromXNative(QRect(rects[i].x, rects[i].y, rects[i].width, rects[i].height)).toAlignedRect();
|
||||
QRectF region = Xcb::fromXNative(QRect(rects[i].x, rects[i].y, rects[i].width, rects[i].height)).toAlignedRect();
|
||||
// make sure the shape is sane (X is async, maybe even XShape is broken)
|
||||
region = region.intersected(QRectF(QPointF(0, 0), bufferGeometry.size()));
|
||||
|
||||
m_shapeRegion += region;
|
||||
}
|
||||
// make sure the shape is sane (X is async, maybe even XShape is broken)
|
||||
m_shapeRegion &= QRegion(0, 0, bufferGeometry.width(), bufferGeometry.height());
|
||||
} else {
|
||||
m_shapeRegion = QRegion();
|
||||
m_shapeRegion.clear();
|
||||
}
|
||||
} else {
|
||||
m_shapeRegion = QRegion(0, 0, bufferGeometry.width(), bufferGeometry.height());
|
||||
m_shapeRegion = {QRectF(0, 0, bufferGeometry.width(), bufferGeometry.height())};
|
||||
}
|
||||
|
||||
m_shapeRegionIsValid = true;
|
||||
|
@ -523,7 +524,7 @@ QRegion Window::shapeRegion() const
|
|||
void Window::discardShapeRegion()
|
||||
{
|
||||
m_shapeRegionIsValid = false;
|
||||
m_shapeRegion = QRegion();
|
||||
m_shapeRegion.clear();
|
||||
}
|
||||
|
||||
bool Window::isClient() const
|
||||
|
|
|
@ -773,7 +773,7 @@ public:
|
|||
* @see hasAlpha
|
||||
*/
|
||||
const QRegion &opaqueRegion() const;
|
||||
QRegion shapeRegion() const;
|
||||
QVector<QRectF> shapeRegion() const;
|
||||
|
||||
bool skipsCloseAnimation() const;
|
||||
void setSkipCloseAnimation(bool set);
|
||||
|
@ -1925,7 +1925,7 @@ private:
|
|||
ClientMachine *m_clientMachine;
|
||||
xcb_window_t m_wmClientLeader;
|
||||
QRegion opaque_region;
|
||||
mutable QRegion m_shapeRegion;
|
||||
mutable QVector<QRectF> m_shapeRegion;
|
||||
mutable bool m_shapeRegionIsValid = false;
|
||||
bool m_skipCloseAnimation;
|
||||
quint32 m_pendingSurfaceId = 0;
|
||||
|
|
Loading…
Reference in a new issue