scene: Fix SurfaceItem::bufferTransform()
The wayland spec is not quite clear about the transforms, but the buffer transform indicates a transform from wl_surface to wl_buffer or compositor global coordinate space to composited buffer. On the other hand, SurfaceItem assumes that the order is vice versa.
This commit is contained in:
parent
f8df72497f
commit
6510fe6e5d
16 changed files with 85 additions and 231 deletions
|
@ -289,7 +289,7 @@ void TestWaylandSurface::testDamage()
|
|||
{
|
||||
const QRegion surfaceDamage = QRegion(5, 8, 3, 6).united(QRect(10, 11, 6, 1));
|
||||
const QRegion expectedDamage = QRegion(10, 16, 6, 12).united(QRect(20, 22, 12, 2));
|
||||
QImage img(QSize(40, 35), QImage::Format_ARGB32_Premultiplied);
|
||||
QImage img(QSize(80, 70), QImage::Format_ARGB32_Premultiplied);
|
||||
img.fill(Qt::black);
|
||||
auto b = m_shm->createBuffer(img);
|
||||
s->attachBuffer(b);
|
||||
|
|
|
@ -143,7 +143,7 @@ void TestViewporterInterface::testCropScale()
|
|||
|
||||
QSignalSpy serverSurfaceMappedSpy(serverSurface, &SurfaceInterface::mapped);
|
||||
QSignalSpy serverSurfaceSizeChangedSpy(serverSurface, &SurfaceInterface::sizeChanged);
|
||||
QSignalSpy surfaceToBufferMatrixChangedSpy(serverSurface, &SurfaceInterface::surfaceToBufferMatrixChanged);
|
||||
QSignalSpy bufferSourceBoxChangedSpy(serverSurface, &SurfaceInterface::bufferSourceBoxChanged);
|
||||
|
||||
// Map the surface.
|
||||
QImage image(QSize(200, 100), QImage::Format_ARGB32_Premultiplied);
|
||||
|
@ -154,9 +154,9 @@ void TestViewporterInterface::testCropScale()
|
|||
clientSurface->damage(image.rect());
|
||||
clientSurface->commit(KWayland::Client::Surface::CommitFlag::None);
|
||||
QVERIFY(serverSurfaceMappedSpy.wait());
|
||||
QCOMPARE(surfaceToBufferMatrixChangedSpy.count(), 1);
|
||||
QCOMPARE(bufferSourceBoxChangedSpy.count(), 1);
|
||||
QCOMPARE(serverSurface->size(), QSize(100, 50));
|
||||
QCOMPARE(serverSurface->mapToBuffer(QPointF(0, 0)), QPointF(0, 0));
|
||||
QCOMPARE(serverSurface->bufferSourceBox(), QRectF(0, 0, 200, 100));
|
||||
|
||||
// Create a viewport for the surface.
|
||||
std::unique_ptr<Viewport> clientViewport(new Viewport);
|
||||
|
@ -166,25 +166,25 @@ void TestViewporterInterface::testCropScale()
|
|||
clientViewport->set_source(wl_fixed_from_double(10), wl_fixed_from_double(10), wl_fixed_from_double(30), wl_fixed_from_double(20));
|
||||
clientSurface->commit(KWayland::Client::Surface::CommitFlag::None);
|
||||
QVERIFY(serverSurfaceSizeChangedSpy.wait());
|
||||
QCOMPARE(surfaceToBufferMatrixChangedSpy.count(), 2);
|
||||
QCOMPARE(bufferSourceBoxChangedSpy.count(), 2);
|
||||
QCOMPARE(serverSurface->size(), QSize(30, 20));
|
||||
QCOMPARE(serverSurface->mapToBuffer(QPointF(0, 0)), QPointF(20, 20));
|
||||
QCOMPARE(serverSurface->bufferSourceBox(), QRectF(20, 20, 60, 40));
|
||||
|
||||
// Scale the surface.
|
||||
clientViewport->set_destination(500, 250);
|
||||
clientSurface->commit(KWayland::Client::Surface::CommitFlag::None);
|
||||
QVERIFY(serverSurfaceSizeChangedSpy.wait());
|
||||
QCOMPARE(surfaceToBufferMatrixChangedSpy.count(), 3);
|
||||
QCOMPARE(bufferSourceBoxChangedSpy.count(), 2);
|
||||
QCOMPARE(serverSurface->size(), QSize(500, 250));
|
||||
QCOMPARE(serverSurface->mapToBuffer(QPointF(0, 0)), QPointF(20, 20));
|
||||
QCOMPARE(serverSurface->bufferSourceBox(), QRectF(20, 20, 60, 40));
|
||||
|
||||
// If the viewport is destroyed, the crop and scale state will be unset on a next commit.
|
||||
clientViewport->destroy();
|
||||
clientSurface->commit(KWayland::Client::Surface::CommitFlag::None);
|
||||
QVERIFY(serverSurfaceSizeChangedSpy.wait());
|
||||
QCOMPARE(surfaceToBufferMatrixChangedSpy.count(), 4);
|
||||
QCOMPARE(bufferSourceBoxChangedSpy.count(), 3);
|
||||
QCOMPARE(serverSurface->size(), QSize(100, 50));
|
||||
QCOMPARE(serverSurface->mapToBuffer(QPointF(0, 0)), QPointF(0, 0));
|
||||
QCOMPARE(serverSurface->bufferSourceBox(), QRectF(0, 0, 200, 100));
|
||||
}
|
||||
|
||||
QTEST_GUILESS_MAIN(TestViewporterInterface)
|
||||
|
|
|
@ -139,7 +139,7 @@ void ItemRendererQPainter::renderSurfaceItem(QPainter *painter, SurfaceItem *sur
|
|||
}
|
||||
surfaceItem->resetDamage();
|
||||
|
||||
const OutputTransform surfaceToBufferTransform = surfaceItem->bufferTransform().inverted();
|
||||
const OutputTransform surfaceToBufferTransform = surfaceItem->bufferTransform();
|
||||
const QSizeF transformedSize = surfaceToBufferTransform.map(surfaceItem->size());
|
||||
|
||||
painter->save();
|
||||
|
@ -147,34 +147,34 @@ void ItemRendererQPainter::renderSurfaceItem(QPainter *painter, SurfaceItem *sur
|
|||
case OutputTransform::Normal:
|
||||
break;
|
||||
case OutputTransform::Rotate90:
|
||||
painter->translate(0, transformedSize.width());
|
||||
painter->rotate(-90);
|
||||
painter->translate(transformedSize.height(), 0);
|
||||
painter->rotate(90);
|
||||
break;
|
||||
case OutputTransform::Rotate180:
|
||||
painter->translate(transformedSize.width(), transformedSize.height());
|
||||
painter->rotate(-180);
|
||||
painter->rotate(180);
|
||||
break;
|
||||
case OutputTransform::Rotate270:
|
||||
painter->translate(transformedSize.height(), 0);
|
||||
painter->rotate(-270);
|
||||
painter->translate(0, transformedSize.width());
|
||||
painter->rotate(270);
|
||||
break;
|
||||
case OutputTransform::FlipX:
|
||||
painter->translate(transformedSize.width(), 0);
|
||||
painter->scale(-1, 1);
|
||||
break;
|
||||
case OutputTransform::FlipX90:
|
||||
painter->rotate(-90);
|
||||
painter->scale(-1, 1);
|
||||
painter->rotate(90);
|
||||
break;
|
||||
case OutputTransform::FlipX180:
|
||||
painter->translate(0, transformedSize.height());
|
||||
painter->rotate(-180);
|
||||
painter->scale(-1, 1);
|
||||
painter->rotate(180);
|
||||
break;
|
||||
case OutputTransform::FlipX270:
|
||||
painter->translate(transformedSize.height(), transformedSize.width());
|
||||
painter->rotate(-270);
|
||||
painter->scale(-1, 1);
|
||||
painter->rotate(270);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include "scene/surfaceitem.h"
|
||||
#include "core/pixelgrid.h"
|
||||
#include "scene/scene.h"
|
||||
|
||||
namespace KWin
|
||||
|
@ -15,17 +16,6 @@ SurfaceItem::SurfaceItem(Scene *scene, Item *parent)
|
|||
{
|
||||
}
|
||||
|
||||
QMatrix4x4 SurfaceItem::surfaceToBufferMatrix() const
|
||||
{
|
||||
return m_surfaceToBufferMatrix;
|
||||
}
|
||||
|
||||
void SurfaceItem::setSurfaceToBufferMatrix(const QMatrix4x4 &matrix)
|
||||
{
|
||||
m_surfaceToBufferMatrix = matrix;
|
||||
m_bufferToSurfaceMatrix = matrix.inverted();
|
||||
}
|
||||
|
||||
QRectF SurfaceItem::bufferSourceBox() const
|
||||
{
|
||||
return m_bufferSourceBox;
|
||||
|
@ -33,17 +23,24 @@ QRectF SurfaceItem::bufferSourceBox() const
|
|||
|
||||
void SurfaceItem::setBufferSourceBox(const QRectF &box)
|
||||
{
|
||||
m_bufferSourceBox = box;
|
||||
if (m_bufferSourceBox != box) {
|
||||
m_bufferSourceBox = box;
|
||||
discardQuads();
|
||||
}
|
||||
}
|
||||
|
||||
OutputTransform SurfaceItem::bufferTransform() const
|
||||
{
|
||||
return m_bufferTransform;
|
||||
return m_surfaceToBufferTransform;
|
||||
}
|
||||
|
||||
void SurfaceItem::setBufferTransform(OutputTransform transform)
|
||||
{
|
||||
m_bufferTransform = transform;
|
||||
if (m_surfaceToBufferTransform != transform) {
|
||||
m_surfaceToBufferTransform = transform;
|
||||
m_bufferToSurfaceTransform = transform.inverted();
|
||||
discardQuads();
|
||||
}
|
||||
}
|
||||
|
||||
QSize SurfaceItem::bufferSize() const
|
||||
|
@ -53,14 +50,23 @@ QSize SurfaceItem::bufferSize() const
|
|||
|
||||
void SurfaceItem::setBufferSize(const QSize &size)
|
||||
{
|
||||
m_bufferSize = size;
|
||||
if (m_bufferSize != size) {
|
||||
m_bufferSize = size;
|
||||
discardPixmap();
|
||||
discardQuads();
|
||||
}
|
||||
}
|
||||
|
||||
QRegion SurfaceItem::mapFromBuffer(const QRegion ®ion) const
|
||||
{
|
||||
const QRectF sourceBox = m_bufferToSurfaceTransform.map(m_bufferSourceBox, m_bufferSize);
|
||||
const qreal xScale = size().width() / sourceBox.width();
|
||||
const qreal yScale = size().height() / sourceBox.height();
|
||||
|
||||
QRegion result;
|
||||
for (const QRect &rect : region) {
|
||||
result += m_bufferToSurfaceMatrix.mapRect(QRectF(rect)).toAlignedRect();
|
||||
for (QRectF rect : region) {
|
||||
const QRectF r = m_bufferToSurfaceTransform.map(rect, m_bufferSize).translated(-sourceBox.topLeft());
|
||||
result += QRectF(r.x() * xScale, r.y() * yScale, r.width() * xScale, r.height() * yScale).toAlignedRect();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -93,7 +99,7 @@ void SurfaceItem::addDamage(const QRegion ®ion)
|
|||
m_lastDamage = std::chrono::steady_clock::now();
|
||||
m_damage += region;
|
||||
|
||||
const QRectF sourceBox = m_bufferTransform.map(m_bufferSourceBox, m_bufferSize);
|
||||
const QRectF sourceBox = m_bufferToSurfaceTransform.map(m_bufferSourceBox, m_bufferSize);
|
||||
const qreal xScale = sourceBox.width() / size().width();
|
||||
const qreal yScale = sourceBox.height() / size().height();
|
||||
const QRegion logicalDamage = mapFromBuffer(region);
|
||||
|
@ -204,27 +210,25 @@ WindowQuadList SurfaceItem::buildQuads() const
|
|||
}
|
||||
|
||||
const QList<QRectF> region = shape();
|
||||
const auto size = pixmap()->size();
|
||||
|
||||
WindowQuadList quads;
|
||||
quads.reserve(region.count());
|
||||
|
||||
const QRectF sourceBox = m_bufferToSurfaceTransform.map(m_bufferSourceBox, m_bufferSize);
|
||||
const qreal xScale = sourceBox.width() / size().width();
|
||||
const qreal yScale = sourceBox.height() / size().height();
|
||||
|
||||
for (const QRectF rect : region) {
|
||||
WindowQuad quad;
|
||||
|
||||
// Use toPoint to round the device position to match what we eventually
|
||||
// do for the geometry, otherwise we end up with mismatched UV
|
||||
// coordinates as the texture size is going to be in (rounded) device
|
||||
// coordinates as well.
|
||||
const QPointF bufferTopLeft = m_surfaceToBufferMatrix.map(rect.topLeft()).toPoint();
|
||||
const QPointF bufferTopRight = m_surfaceToBufferMatrix.map(rect.topRight()).toPoint();
|
||||
const QPointF bufferBottomRight = m_surfaceToBufferMatrix.map(rect.bottomRight()).toPoint();
|
||||
const QPointF bufferBottomLeft = m_surfaceToBufferMatrix.map(rect.bottomLeft()).toPoint();
|
||||
const QPointF bufferTopLeft = snapToPixelGridF(m_bufferSourceBox.topLeft() + m_surfaceToBufferTransform.map(QPointF(rect.left() * xScale, rect.top() * yScale), sourceBox.size()));
|
||||
const QPointF bufferTopRight = snapToPixelGridF(m_bufferSourceBox.topLeft() + m_surfaceToBufferTransform.map(QPointF(rect.right() * xScale, rect.top() * yScale), sourceBox.size()));
|
||||
const QPointF bufferBottomRight = snapToPixelGridF(m_bufferSourceBox.topLeft() + m_surfaceToBufferTransform.map(QPointF(rect.right() * xScale, rect.bottom() * yScale), sourceBox.size()));
|
||||
const QPointF bufferBottomLeft = snapToPixelGridF(m_bufferSourceBox.topLeft() + m_surfaceToBufferTransform.map(QPointF(rect.left() * xScale, rect.bottom() * yScale), sourceBox.size()));
|
||||
|
||||
quad[0] = WindowVertex(rect.topLeft(), QPointF{bufferTopLeft.x() / size.width(), bufferTopLeft.y() / size.height()});
|
||||
quad[1] = WindowVertex(rect.topRight(), QPointF{bufferTopRight.x() / size.width(), bufferTopRight.y() / size.height()});
|
||||
quad[2] = WindowVertex(rect.bottomRight(), QPointF{bufferBottomRight.x() / size.width(), bufferBottomRight.y() / size.height()});
|
||||
quad[3] = WindowVertex(rect.bottomLeft(), QPointF{bufferBottomLeft.x() / size.width(), bufferBottomLeft.y() / size.height()});
|
||||
quad[0] = WindowVertex(rect.topLeft(), QPointF{bufferTopLeft.x() / m_bufferSize.width(), bufferTopLeft.y() / m_bufferSize.height()});
|
||||
quad[1] = WindowVertex(rect.topRight(), QPointF{bufferTopRight.x() / m_bufferSize.width(), bufferTopRight.y() / m_bufferSize.height()});
|
||||
quad[2] = WindowVertex(rect.bottomRight(), QPointF{bufferBottomRight.x() / m_bufferSize.width(), bufferBottomRight.y() / m_bufferSize.height()});
|
||||
quad[3] = WindowVertex(rect.bottomLeft(), QPointF{bufferBottomLeft.x() / m_bufferSize.width(), bufferBottomLeft.y() / m_bufferSize.height()});
|
||||
|
||||
quads << quad;
|
||||
}
|
||||
|
|
|
@ -26,9 +26,6 @@ class KWIN_EXPORT SurfaceItem : public Item
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QMatrix4x4 surfaceToBufferMatrix() const;
|
||||
void setSurfaceToBufferMatrix(const QMatrix4x4 &matrix);
|
||||
|
||||
QRectF bufferSourceBox() const;
|
||||
void setBufferSourceBox(const QRectF &box);
|
||||
|
||||
|
@ -71,13 +68,12 @@ protected:
|
|||
WindowQuadList buildQuads() const override;
|
||||
|
||||
QRegion m_damage;
|
||||
OutputTransform m_bufferTransform;
|
||||
OutputTransform m_bufferToSurfaceTransform;
|
||||
OutputTransform m_surfaceToBufferTransform;
|
||||
QRectF m_bufferSourceBox;
|
||||
QSize m_bufferSize;
|
||||
std::unique_ptr<SurfacePixmap> m_pixmap;
|
||||
std::unique_ptr<SurfacePixmap> m_previousPixmap;
|
||||
QMatrix4x4 m_surfaceToBufferMatrix;
|
||||
QMatrix4x4 m_bufferToSurfaceMatrix;
|
||||
int m_referencePixmapCounter = 0;
|
||||
std::deque<std::chrono::nanoseconds> m_lastDamageTimeDiffs;
|
||||
std::optional<std::chrono::steady_clock::time_point> m_lastDamage;
|
||||
|
|
|
@ -20,13 +20,8 @@ SurfaceItemInternal::SurfaceItemInternal(InternalWindow *window, Scene *scene, I
|
|||
this, &SurfaceItemInternal::handleBufferGeometryChanged);
|
||||
|
||||
setSize(window->bufferGeometry().size());
|
||||
setBufferSourceBox(QRectF(QPointF(0, 0), window->bufferGeometry().size()));
|
||||
setBufferSourceBox(QRectF(QPointF(0, 0), window->bufferGeometry().size() * window->bufferScale()));
|
||||
setBufferSize((window->bufferGeometry().size() * window->bufferScale()).toSize());
|
||||
|
||||
// The device pixel ratio of the internal window is static.
|
||||
QMatrix4x4 surfaceToBufferMatrix;
|
||||
surfaceToBufferMatrix.scale(window->bufferScale());
|
||||
setSurfaceToBufferMatrix(surfaceToBufferMatrix);
|
||||
}
|
||||
|
||||
InternalWindow *SurfaceItemInternal::window() const
|
||||
|
@ -44,13 +39,10 @@ std::unique_ptr<SurfacePixmap> SurfaceItemInternal::createPixmap()
|
|||
return std::make_unique<SurfacePixmapInternal>(this);
|
||||
}
|
||||
|
||||
void SurfaceItemInternal::handleBufferGeometryChanged(const QRectF &old)
|
||||
void SurfaceItemInternal::handleBufferGeometryChanged()
|
||||
{
|
||||
if (m_window->bufferGeometry().size() != old.size()) {
|
||||
discardPixmap();
|
||||
}
|
||||
setSize(m_window->bufferGeometry().size());
|
||||
setBufferSourceBox(QRectF(QPointF(0, 0), m_window->bufferGeometry().size()));
|
||||
setBufferSourceBox(QRectF(QPointF(0, 0), m_window->bufferGeometry().size() * m_window->bufferScale()));
|
||||
setBufferSize((m_window->bufferGeometry().size() * m_window->bufferScale()).toSize());
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ public:
|
|||
QList<QRectF> shape() const override;
|
||||
|
||||
private Q_SLOTS:
|
||||
void handleBufferGeometryChanged(const QRectF &old);
|
||||
void handleBufferGeometryChanged();
|
||||
|
||||
protected:
|
||||
std::unique_ptr<SurfacePixmap> createPixmap() override;
|
||||
|
|
|
@ -20,9 +20,6 @@ SurfaceItemWayland::SurfaceItemWayland(SurfaceInterface *surface, Scene *scene,
|
|||
: SurfaceItem(scene, parent)
|
||||
, m_surface(surface)
|
||||
{
|
||||
connect(surface, &SurfaceInterface::surfaceToBufferMatrixChanged,
|
||||
this, &SurfaceItemWayland::handleSurfaceToBufferMatrixChanged);
|
||||
|
||||
connect(surface, &SurfaceInterface::sizeChanged,
|
||||
this, &SurfaceItemWayland::handleSurfaceSizeChanged);
|
||||
connect(surface, &SurfaceInterface::bufferSizeChanged,
|
||||
|
@ -62,7 +59,6 @@ SurfaceItemWayland::SurfaceItemWayland(SurfaceInterface *surface, Scene *scene,
|
|||
setBufferTransform(surface->bufferTransform());
|
||||
setBufferSourceBox(surface->bufferSourceBox());
|
||||
setBufferSize(surface->bufferSize());
|
||||
setSurfaceToBufferMatrix(surface->surfaceToBufferMatrix());
|
||||
setColorDescription(surface->colorDescription());
|
||||
}
|
||||
|
||||
|
@ -84,22 +80,15 @@ SurfaceInterface *SurfaceItemWayland::surface() const
|
|||
return m_surface;
|
||||
}
|
||||
|
||||
void SurfaceItemWayland::handleSurfaceToBufferMatrixChanged()
|
||||
{
|
||||
setSurfaceToBufferMatrix(m_surface->surfaceToBufferMatrix());
|
||||
discardQuads();
|
||||
discardPixmap();
|
||||
}
|
||||
|
||||
void SurfaceItemWayland::handleSurfaceSizeChanged()
|
||||
{
|
||||
setSize(m_surface->size());
|
||||
discardQuads();
|
||||
}
|
||||
|
||||
void SurfaceItemWayland::handleBufferSizeChanged()
|
||||
{
|
||||
setBufferSize(m_surface->bufferSize());
|
||||
discardPixmap();
|
||||
}
|
||||
|
||||
void SurfaceItemWayland::handleBufferSourceBoxChanged()
|
||||
|
|
|
@ -36,7 +36,6 @@ public:
|
|||
SurfaceInterface *surface() const;
|
||||
|
||||
private Q_SLOTS:
|
||||
void handleSurfaceToBufferMatrixChanged();
|
||||
void handleSurfaceCommitted();
|
||||
void handleSurfaceSizeChanged();
|
||||
void handleBufferSizeChanged();
|
||||
|
|
|
@ -140,11 +140,8 @@ void SurfaceItemX11::destroyDamage()
|
|||
}
|
||||
}
|
||||
|
||||
void SurfaceItemX11::handleBufferGeometryChanged(const QRectF &old)
|
||||
void SurfaceItemX11::handleBufferGeometryChanged()
|
||||
{
|
||||
if (m_window->bufferGeometry().size() != old.size()) {
|
||||
discardPixmap();
|
||||
}
|
||||
setSize(m_window->bufferGeometry().size());
|
||||
setBufferSourceBox(QRectF(QPointF(0, 0), m_window->bufferGeometry().size()));
|
||||
setBufferSize(m_window->bufferGeometry().size().toSize());
|
||||
|
|
|
@ -41,7 +41,7 @@ public:
|
|||
QRegion opaque() const override;
|
||||
|
||||
private Q_SLOTS:
|
||||
void handleBufferGeometryChanged(const QRectF &old);
|
||||
void handleBufferGeometryChanged();
|
||||
void handleShapeChanged();
|
||||
|
||||
protected:
|
||||
|
|
|
@ -33,8 +33,6 @@ void SubSurfaceMonitor::registerSubSurface(SubSurfaceInterface *subSurface)
|
|||
this, &SubSurfaceMonitor::subSurfaceMapped);
|
||||
connect(surface, &SurfaceInterface::unmapped,
|
||||
this, &SubSurfaceMonitor::subSurfaceUnmapped);
|
||||
connect(surface, &SurfaceInterface::surfaceToBufferMatrixChanged,
|
||||
this, &SubSurfaceMonitor::subSurfaceSurfaceToBufferMatrixChanged);
|
||||
connect(surface, &SurfaceInterface::bufferSizeChanged,
|
||||
this, &SubSurfaceMonitor::subSurfaceBufferSizeChanged);
|
||||
connect(surface, &SurfaceInterface::committed,
|
||||
|
|
|
@ -59,11 +59,6 @@ Q_SIGNALS:
|
|||
* This signal is emitted when a sub-surface is unmapped.
|
||||
*/
|
||||
void subSurfaceUnmapped();
|
||||
/**
|
||||
* This signal is emitted when the mapping between the surface-local coordinate space
|
||||
* and the buffer coordinate space for a sub-surface has changed.
|
||||
*/
|
||||
void subSurfaceSurfaceToBufferMatrixChanged();
|
||||
/**
|
||||
* This signal is emitted when the buffer size of a subsurface has changed.
|
||||
*/
|
||||
|
|
|
@ -482,73 +482,6 @@ bool SurfaceInterface::hasFrameCallbacks() const
|
|||
return !wl_list_empty(&d->current->frameCallbacks);
|
||||
}
|
||||
|
||||
QMatrix4x4 SurfaceInterfacePrivate::buildSurfaceToBufferMatrix()
|
||||
{
|
||||
// The order of transforms is reversed, i.e. the viewport transform is the first one.
|
||||
|
||||
QMatrix4x4 surfaceToBufferMatrix;
|
||||
|
||||
if (!current->buffer) {
|
||||
return surfaceToBufferMatrix;
|
||||
}
|
||||
|
||||
surfaceToBufferMatrix.scale(current->bufferScale, current->bufferScale);
|
||||
surfaceToBufferMatrix.scale(scaleOverride, scaleOverride);
|
||||
|
||||
switch (current->bufferTransform.kind()) {
|
||||
case OutputTransform::Normal:
|
||||
case OutputTransform::FlipX:
|
||||
break;
|
||||
case OutputTransform::Rotate90:
|
||||
case OutputTransform::FlipX90:
|
||||
surfaceToBufferMatrix.translate(0, bufferSize.height() / current->bufferScale);
|
||||
surfaceToBufferMatrix.rotate(-90, 0, 0, 1);
|
||||
break;
|
||||
case OutputTransform::Rotate180:
|
||||
case OutputTransform::FlipX180:
|
||||
surfaceToBufferMatrix.translate(bufferSize.width() / current->bufferScale, bufferSize.height() / current->bufferScale);
|
||||
surfaceToBufferMatrix.rotate(-180, 0, 0, 1);
|
||||
break;
|
||||
case OutputTransform::Rotate270:
|
||||
case OutputTransform::FlipX270:
|
||||
surfaceToBufferMatrix.translate(bufferSize.width() / current->bufferScale, 0);
|
||||
surfaceToBufferMatrix.rotate(-270, 0, 0, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (current->bufferTransform.kind()) {
|
||||
case OutputTransform::FlipX:
|
||||
case OutputTransform::FlipX180:
|
||||
surfaceToBufferMatrix.translate(bufferSize.width() / current->bufferScale, 0);
|
||||
surfaceToBufferMatrix.scale(-1, 1);
|
||||
break;
|
||||
case OutputTransform::FlipX90:
|
||||
case OutputTransform::FlipX270:
|
||||
surfaceToBufferMatrix.translate(bufferSize.height() / current->bufferScale, 0);
|
||||
surfaceToBufferMatrix.scale(-1, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (current->viewport.sourceGeometry.isValid()) {
|
||||
surfaceToBufferMatrix.translate(current->viewport.sourceGeometry.x(), current->viewport.sourceGeometry.y());
|
||||
}
|
||||
|
||||
QSizeF sourceSize;
|
||||
if (current->viewport.sourceGeometry.isValid()) {
|
||||
sourceSize = current->viewport.sourceGeometry.size();
|
||||
} else {
|
||||
sourceSize = implicitSurfaceSize;
|
||||
}
|
||||
|
||||
if (sourceSize != surfaceSize) {
|
||||
surfaceToBufferMatrix.scale(sourceSize.width() / surfaceSize.width(), sourceSize.height() / surfaceSize.height());
|
||||
}
|
||||
|
||||
return surfaceToBufferMatrix;
|
||||
}
|
||||
|
||||
QRectF SurfaceInterfacePrivate::computeBufferSourceBox() const
|
||||
{
|
||||
if (!current->viewport.sourceGeometry.isValid()) {
|
||||
|
@ -561,7 +494,7 @@ QRectF SurfaceInterfacePrivate::computeBufferSourceBox() const
|
|||
current->viewport.sourceGeometry.width() * current->bufferScale,
|
||||
current->viewport.sourceGeometry.height() * current->bufferScale);
|
||||
|
||||
return current->bufferTransform.inverted().map(box, bounds);
|
||||
return current->bufferTransform.map(box, bounds);
|
||||
}
|
||||
|
||||
SurfaceState::SurfaceState()
|
||||
|
@ -676,7 +609,6 @@ void SurfaceInterfacePrivate::applyState(SurfaceState *next)
|
|||
const QSizeF oldSurfaceSize = surfaceSize;
|
||||
const QSize oldBufferSize = bufferSize;
|
||||
const QRectF oldBufferSourceBox = bufferSourceBox;
|
||||
const QMatrix4x4 oldSurfaceToBufferMatrix = surfaceToBufferMatrix;
|
||||
const QRegion oldInputRegion = inputRegion;
|
||||
|
||||
if (!next->damage.isEmpty() || !next->bufferDamage.isEmpty()) {
|
||||
|
@ -689,14 +621,13 @@ void SurfaceInterfacePrivate::applyState(SurfaceState *next)
|
|||
if (current->buffer) {
|
||||
bufferSize = current->buffer->size();
|
||||
bufferSourceBox = computeBufferSourceBox();
|
||||
implicitSurfaceSize = current->bufferTransform.map(current->buffer->size() / current->bufferScale);
|
||||
|
||||
if (current->viewport.destinationSize.isValid()) {
|
||||
surfaceSize = current->viewport.destinationSize;
|
||||
} else if (current->viewport.sourceGeometry.isValid()) {
|
||||
surfaceSize = current->viewport.sourceGeometry.size();
|
||||
} else {
|
||||
surfaceSize = implicitSurfaceSize;
|
||||
surfaceSize = current->bufferTransform.map(current->buffer->size() / current->bufferScale);
|
||||
}
|
||||
|
||||
const QRectF surfaceRect(QPoint(0, 0), surfaceSize);
|
||||
|
@ -716,18 +647,14 @@ void SurfaceInterfacePrivate::applyState(SurfaceState *next)
|
|||
opaqueRegion = map_helper(scaleOverrideMatrix, opaqueRegion);
|
||||
inputRegion = map_helper(scaleOverrideMatrix, inputRegion);
|
||||
surfaceSize = surfaceSize / scaleOverride;
|
||||
implicitSurfaceSize = implicitSurfaceSize / scaleOverride;
|
||||
} else {
|
||||
surfaceSize = QSizeF(0, 0);
|
||||
implicitSurfaceSize = QSizeF(0, 0);
|
||||
bufferSize = QSize(0, 0);
|
||||
bufferSourceBox = QRectF();
|
||||
inputRegion = QRegion();
|
||||
opaqueRegion = QRegion();
|
||||
}
|
||||
|
||||
surfaceToBufferMatrix = buildSurfaceToBufferMatrix();
|
||||
|
||||
if (opaqueRegionChanged) {
|
||||
Q_EMIT q->opaqueChanged(opaqueRegion);
|
||||
}
|
||||
|
@ -740,9 +667,6 @@ void SurfaceInterfacePrivate::applyState(SurfaceState *next)
|
|||
if (visibilityChanged) {
|
||||
updateEffectiveMapped();
|
||||
}
|
||||
if (surfaceToBufferMatrix != oldSurfaceToBufferMatrix) {
|
||||
Q_EMIT q->surfaceToBufferMatrixChanged();
|
||||
}
|
||||
if (bufferSourceBox != oldBufferSourceBox) {
|
||||
Q_EMIT q->bufferSourceBoxChanged();
|
||||
}
|
||||
|
@ -778,7 +702,7 @@ void SurfaceInterfacePrivate::applyState(SurfaceState *next)
|
|||
if (current->buffer && (!current->damage.isEmpty() || !current->bufferDamage.isEmpty())) {
|
||||
const QRect bufferRect = QRect(QPoint(0, 0), current->buffer->size());
|
||||
bufferDamage = current->bufferDamage
|
||||
.united(q->mapToBuffer(current->damage))
|
||||
.united(mapToBuffer(current->damage))
|
||||
.intersected(bufferRect);
|
||||
Q_EMIT q->damaged(bufferDamage);
|
||||
}
|
||||
|
@ -846,6 +770,23 @@ bool SurfaceInterfacePrivate::inputContains(const QPointF &position) const
|
|||
return contains(position) && inputRegion.contains(QPoint(std::floor(position.x()), std::floor(position.y())));
|
||||
}
|
||||
|
||||
QRegion SurfaceInterfacePrivate::mapToBuffer(const QRegion ®ion) const
|
||||
{
|
||||
if (region.isEmpty()) {
|
||||
return QRegion();
|
||||
}
|
||||
|
||||
const QRectF sourceBox = current->bufferTransform.inverted().map(bufferSourceBox, bufferSize);
|
||||
const qreal xScale = sourceBox.width() / surfaceSize.width();
|
||||
const qreal yScale = sourceBox.height() / surfaceSize.height();
|
||||
|
||||
QRegion result;
|
||||
for (QRectF rect : region) {
|
||||
result += current->bufferTransform.map(QRectF(rect.x() * xScale, rect.y() * yScale, rect.width() * xScale, rect.height() * yScale), sourceBox.size()).translated(bufferSourceBox.topLeft()).toAlignedRect();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
QRegion SurfaceInterface::bufferDamage() const
|
||||
{
|
||||
return d->bufferDamage;
|
||||
|
@ -1101,21 +1042,6 @@ ContentType SurfaceInterface::contentType() const
|
|||
return d->current->contentType;
|
||||
}
|
||||
|
||||
QPointF SurfaceInterface::mapToBuffer(const QPointF &point) const
|
||||
{
|
||||
return d->surfaceToBufferMatrix.map(point);
|
||||
}
|
||||
|
||||
QRegion SurfaceInterface::mapToBuffer(const QRegion ®ion) const
|
||||
{
|
||||
return map_helper(d->surfaceToBufferMatrix, region);
|
||||
}
|
||||
|
||||
QMatrix4x4 SurfaceInterface::surfaceToBufferMatrix() const
|
||||
{
|
||||
return d->surfaceToBufferMatrix;
|
||||
}
|
||||
|
||||
QPointF SurfaceInterface::mapToChild(SurfaceInterface *child, const QPointF &point) const
|
||||
{
|
||||
QPointF local = point;
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "core/output.h"
|
||||
#include "core/renderbackend.h"
|
||||
|
||||
#include <QMatrix4x4>
|
||||
#include <QObject>
|
||||
#include <QRegion>
|
||||
|
||||
|
@ -118,37 +117,6 @@ public:
|
|||
SurfaceRole *role() const;
|
||||
void setRole(SurfaceRole *role);
|
||||
|
||||
/**
|
||||
* Maps the specified @a point from the surface-local coordinates to buffer pixel coordinates.
|
||||
*
|
||||
* Note that there is no direct connection between points in the surface-local coordinates
|
||||
* and points in the buffer pixel coordinates. In order to map points between the two spaces,
|
||||
* one has to use mapToBuffer() and mapFromBuffer().
|
||||
*
|
||||
* The returned value will become invalid when the surfaceToBufferMatrixChanged() signal is emitted.
|
||||
*
|
||||
* @see surfaceToBufferMatrix(), surfaceToBufferMatrixChanged()
|
||||
*/
|
||||
QPointF mapToBuffer(const QPointF &point) const;
|
||||
/**
|
||||
* Maps the specified @a region from the surface-local coordinates to buffer pixel coordinates.
|
||||
*
|
||||
* Note that there is no direct connection between regions in the surface-local coordinates
|
||||
* and regions in the buffer pixel coordinates. In order to map regions between the two spaces,
|
||||
* one has to use mapToBuffer() and mapFromBuffer().
|
||||
*
|
||||
* The returned value will become invalid when the surfaceToBufferMatrixChanged() signal is emitted.
|
||||
*
|
||||
* @see surfaceToBufferMatrix(), surfaceToBufferMatrixChanged()
|
||||
*/
|
||||
QRegion mapToBuffer(const QRegion ®ion) const;
|
||||
/**
|
||||
* Returns the projection matrix from the surface-local coordinates to buffer coordinates.
|
||||
*
|
||||
* @see surfaceToBufferMatrixChanged()
|
||||
*/
|
||||
QMatrix4x4 surfaceToBufferMatrix() const;
|
||||
|
||||
/**
|
||||
* Maps the specified @a point in this surface's coordinate system to the equivalent point
|
||||
* within the @a child's coordinate system, and returns the mapped point.
|
||||
|
@ -390,14 +358,6 @@ Q_SIGNALS:
|
|||
* signal is emitted.
|
||||
*/
|
||||
void aboutToBeDestroyed();
|
||||
/**
|
||||
* This signal is emitted when the projection matrix from the surface-local coordinate space
|
||||
* to the buffer coordinate space has been changed.
|
||||
*
|
||||
* Note that the compositor will most likely need to re-compute the texture coordinates after
|
||||
* the surface-to-buffer matrix has been changed.
|
||||
*/
|
||||
void surfaceToBufferMatrixChanged();
|
||||
/**
|
||||
* Emitted whenever the SurfaceInterface got damaged.
|
||||
* The signal is only emitted during the commit of state.
|
||||
|
|
|
@ -114,7 +114,6 @@ public:
|
|||
void installPointerConstraint(ConfinedPointerV1Interface *confinement);
|
||||
void installIdleInhibitor(IdleInhibitorV1Interface *inhibitor);
|
||||
|
||||
QMatrix4x4 buildSurfaceToBufferMatrix();
|
||||
QRectF computeBufferSourceBox() const;
|
||||
void applyState(SurfaceState *next);
|
||||
|
||||
|
@ -127,16 +126,15 @@ public:
|
|||
*/
|
||||
bool contains(const QPointF &position) const;
|
||||
bool inputContains(const QPointF &position) const;
|
||||
QRegion mapToBuffer(const QRegion ®ion) const;
|
||||
|
||||
CompositorInterface *compositor;
|
||||
SurfaceInterface *q;
|
||||
SurfaceRole *role = nullptr;
|
||||
std::unique_ptr<SurfaceState> current;
|
||||
std::unique_ptr<SurfaceState> pending;
|
||||
QMatrix4x4 surfaceToBufferMatrix;
|
||||
QSize bufferSize = QSize(0, 0);
|
||||
QRectF bufferSourceBox;
|
||||
QSizeF implicitSurfaceSize = QSizeF(0, 0);
|
||||
QSizeF surfaceSize = QSizeF(0, 0);
|
||||
|
||||
QRegion inputRegion;
|
||||
|
|
Loading…
Reference in a new issue