Commit fa78de62 authored by Vlad Zahorodnii's avatar Vlad Zahorodnii
Browse files

kwineffects: Strip ScreenPaintData of transforms

ScreenPaintData provides a way to transform the painted screen, e.g.
scale or translate. From API point of view, it's great. It allows
fullscreen effects to transform the workspace in various ways.

On the other hand, such effects end up fighting the default scene
painting algorithm. For example, just have a look at the slide effect!
With fullscreen effects, it's better to leave to them the decision how
the screen should be painted. For example, such approach is taken in
some wayland compositors, e.g. wayfire, and our qtquick effects already
operate in similar fashion.

Given that, strip the ScreenPaintData of all available transforms. The
main motivation behind this change is to improve encapsulation of item
painting code and simplify model-view-projection code in kwin. It will
also make the job of extracting item code for sharing purposes easier.
parent 53d25c72
Pipeline #200481 failed with stage
in 35 minutes and 6 seconds
......@@ -5,15 +5,6 @@ add_subdirectory(integration)
add_subdirectory(libinput)
add_subdirectory(tabbox)
########################################################
# Test ScreenPaintData
########################################################
set(testScreenPaintData_SRCS test_screen_paint_data.cpp)
add_executable(testScreenPaintData ${testScreenPaintData_SRCS})
target_link_libraries(testScreenPaintData kwineffects Qt::Test Qt::Widgets KF5::WindowSystem)
add_test(NAME kwin-testScreenPaintData COMMAND testScreenPaintData)
ecm_mark_as_test(testScreenPaintData)
########################################################
# Test WindowPaintData
########################################################
......
/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2012 Martin Gräßlin <mgraesslin@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <kwineffects.h>
#include <QMatrix4x4>
#include <QVector2D>
#include <QVector3D>
#include <QtTest>
using namespace KWin;
class TestScreenPaintData : public QObject
{
Q_OBJECT
private Q_SLOTS:
void testCtor();
void testCopyCtor();
void testAssignmentOperator();
void testSetScale();
void testOperatorMultiplyAssign();
void testSetTranslate();
void testOperatorPlus();
void testSetAngle();
void testSetRotationOrigin();
void testSetRotationAxis();
};
void TestScreenPaintData::testCtor()
{
ScreenPaintData data;
QCOMPARE(data.xScale(), 1.0);
QCOMPARE(data.yScale(), 1.0);
QCOMPARE(data.zScale(), 1.0);
QCOMPARE(data.xTranslation(), 0.0);
QCOMPARE(data.yTranslation(), 0.0);
QCOMPARE(data.zTranslation(), 0.0);
QCOMPARE(data.translation(), QVector3D());
QCOMPARE(data.rotationAngle(), 0.0);
QCOMPARE(data.rotationOrigin(), QVector3D());
QCOMPARE(data.rotationAxis(), QVector3D(0.0, 0.0, 1.0));
QCOMPARE(data.screen(), nullptr);
}
void TestScreenPaintData::testCopyCtor()
{
ScreenPaintData data;
ScreenPaintData data2(data);
// no value had been changed
QCOMPARE(data2.xScale(), 1.0);
QCOMPARE(data2.yScale(), 1.0);
QCOMPARE(data2.zScale(), 1.0);
QCOMPARE(data2.xTranslation(), 0.0);
QCOMPARE(data2.yTranslation(), 0.0);
QCOMPARE(data2.zTranslation(), 0.0);
QCOMPARE(data2.translation(), QVector3D());
QCOMPARE(data2.rotationAngle(), 0.0);
QCOMPARE(data2.rotationOrigin(), QVector3D());
QCOMPARE(data2.rotationAxis(), QVector3D(0.0, 0.0, 1.0));
data2.setScale(QVector3D(0.5, 2.0, 3.0));
data2.translate(0.5, 2.0, 3.0);
data2.setRotationAngle(45.0);
data2.setRotationOrigin(QVector3D(1.0, 2.0, 3.0));
data2.setRotationAxis(QVector3D(1.0, 1.0, 0.0));
ScreenPaintData data3(data2);
QCOMPARE(data3.xScale(), 0.5);
QCOMPARE(data3.yScale(), 2.0);
QCOMPARE(data3.zScale(), 3.0);
QCOMPARE(data3.xTranslation(), 0.5);
QCOMPARE(data3.yTranslation(), 2.0);
QCOMPARE(data3.zTranslation(), 3.0);
QCOMPARE(data3.translation(), QVector3D(0.5, 2.0, 3.0));
QCOMPARE(data3.rotationAngle(), 45.0);
QCOMPARE(data3.rotationOrigin(), QVector3D(1.0, 2.0, 3.0));
QCOMPARE(data3.rotationAxis(), QVector3D(1.0, 1.0, 0.0));
}
void TestScreenPaintData::testAssignmentOperator()
{
ScreenPaintData data;
ScreenPaintData data2;
data2.setScale(QVector3D(0.5, 2.0, 3.0));
data2.translate(0.5, 2.0, 3.0);
data2.setRotationAngle(45.0);
data2.setRotationOrigin(QVector3D(1.0, 2.0, 3.0));
data2.setRotationAxis(QVector3D(1.0, 1.0, 0.0));
data = data2;
// data and data2 should be the same
QCOMPARE(data.xScale(), 0.5);
QCOMPARE(data.yScale(), 2.0);
QCOMPARE(data.zScale(), 3.0);
QCOMPARE(data.xTranslation(), 0.5);
QCOMPARE(data.yTranslation(), 2.0);
QCOMPARE(data.zTranslation(), 3.0);
QCOMPARE(data.translation(), QVector3D(0.5, 2.0, 3.0));
QCOMPARE(data.rotationAngle(), 45.0);
QCOMPARE(data.rotationOrigin(), QVector3D(1.0, 2.0, 3.0));
QCOMPARE(data.rotationAxis(), QVector3D(1.0, 1.0, 0.0));
// data 2
QCOMPARE(data2.xScale(), 0.5);
QCOMPARE(data2.yScale(), 2.0);
QCOMPARE(data2.zScale(), 3.0);
QCOMPARE(data2.xTranslation(), 0.5);
QCOMPARE(data2.yTranslation(), 2.0);
QCOMPARE(data2.zTranslation(), 3.0);
QCOMPARE(data2.translation(), QVector3D(0.5, 2.0, 3.0));
QCOMPARE(data2.rotationAngle(), 45.0);
QCOMPARE(data2.rotationOrigin(), QVector3D(1.0, 2.0, 3.0));
QCOMPARE(data2.rotationAxis(), QVector3D(1.0, 1.0, 0.0));
}
void TestScreenPaintData::testSetScale()
{
ScreenPaintData data;
// without anything set, it's 1.0 on all axis
QCOMPARE(data.xScale(), 1.0);
QCOMPARE(data.yScale(), 1.0);
QCOMPARE(data.zScale(), 1.0);
// changing xScale should not affect y and z
data.setXScale(2.0);
QCOMPARE(data.xScale(), 2.0);
QCOMPARE(data.yScale(), 1.0);
QCOMPARE(data.zScale(), 1.0);
// changing yScale should not affect x and z
data.setYScale(3.0);
QCOMPARE(data.xScale(), 2.0);
QCOMPARE(data.yScale(), 3.0);
QCOMPARE(data.zScale(), 1.0);
// changing zScale should not affect x and y
data.setZScale(4.0);
QCOMPARE(data.xScale(), 2.0);
QCOMPARE(data.yScale(), 3.0);
QCOMPARE(data.zScale(), 4.0);
// setting a vector2d should affect x and y components
data.setScale(QVector2D(0.5, 2.0));
QCOMPARE(data.xScale(), 0.5);
QCOMPARE(data.yScale(), 2.0);
QCOMPARE(data.zScale(), 4.0);
// setting a vector3d should affect all components
data.setScale(QVector3D(1.5, 2.5, 3.5));
QCOMPARE(data.xScale(), 1.5);
QCOMPARE(data.yScale(), 2.5);
QCOMPARE(data.zScale(), 3.5);
}
void TestScreenPaintData::testOperatorMultiplyAssign()
{
ScreenPaintData data;
// without anything set, it's 1.0 on all axis
QCOMPARE(data.xScale(), 1.0);
QCOMPARE(data.yScale(), 1.0);
QCOMPARE(data.zScale(), 1.0);
// multiplying by a factor should set all components
data *= 2.0;
QCOMPARE(data.xScale(), 2.0);
QCOMPARE(data.yScale(), 2.0);
QCOMPARE(data.zScale(), 2.0);
// multiplying by a vector2D should set x and y components
data *= QVector2D(2.0, 3.0);
QCOMPARE(data.xScale(), 4.0);
QCOMPARE(data.yScale(), 6.0);
QCOMPARE(data.zScale(), 2.0);
// multiplying by a vector3d should set all components
data *= QVector3D(0.5, 1.5, 2.0);
QCOMPARE(data.xScale(), 2.0);
QCOMPARE(data.yScale(), 9.0);
QCOMPARE(data.zScale(), 4.0);
}
void TestScreenPaintData::testSetTranslate()
{
ScreenPaintData data;
QCOMPARE(data.xTranslation(), 0.0);
QCOMPARE(data.yTranslation(), 0.0);
QCOMPARE(data.zTranslation(), 0.0);
QCOMPARE(data.translation(), QVector3D());
// set x translate, should not affect y and z
data.setXTranslation(1.0);
QCOMPARE(data.xTranslation(), 1.0);
QCOMPARE(data.yTranslation(), 0.0);
QCOMPARE(data.zTranslation(), 0.0);
QCOMPARE(data.translation(), QVector3D(1.0, 0.0, 0.0));
// set y translate, should not affect x and z
data.setYTranslation(2.0);
QCOMPARE(data.xTranslation(), 1.0);
QCOMPARE(data.yTranslation(), 2.0);
QCOMPARE(data.zTranslation(), 0.0);
QCOMPARE(data.translation(), QVector3D(1.0, 2.0, 0.0));
// set z translate, should not affect x and y
data.setZTranslation(3.0);
QCOMPARE(data.xTranslation(), 1.0);
QCOMPARE(data.yTranslation(), 2.0);
QCOMPARE(data.zTranslation(), 3.0);
QCOMPARE(data.translation(), QVector3D(1.0, 2.0, 3.0));
// translate in x
data.translate(0.5);
QCOMPARE(data.translation(), QVector3D(1.5, 2.0, 3.0));
// translate in x and y
data.translate(0.5, 0.75);
QCOMPARE(data.translation(), QVector3D(2.0, 2.75, 3.0));
// translate in x, y and z
data.translate(1.0, 2.0, 3.0);
QCOMPARE(data.translation(), QVector3D(3.0, 4.75, 6.0));
// translate using vector
data.translate(QVector3D(2.0, 1.0, 0.5));
QCOMPARE(data.translation(), QVector3D(5.0, 5.75, 6.5));
}
void TestScreenPaintData::testOperatorPlus()
{
ScreenPaintData data;
QCOMPARE(data.xTranslation(), 0.0);
QCOMPARE(data.yTranslation(), 0.0);
QCOMPARE(data.zTranslation(), 0.0);
QCOMPARE(data.translation(), QVector3D());
// test with point
data += QPoint(1, 2);
QCOMPARE(data.translation(), QVector3D(1.0, 2.0, 0.0));
// test with pointf
data += QPointF(0.5, 0.75);
QCOMPARE(data.translation(), QVector3D(1.5, 2.75, 0.0));
// test with QVector2D
data += QVector2D(0.25, 1.5);
QCOMPARE(data.translation(), QVector3D(1.75, 4.25, 0.0));
// test with QVector3D
data += QVector3D(1.0, 2.0, 3.5);
QCOMPARE(data.translation(), QVector3D(2.75, 6.25, 3.5));
}
void TestScreenPaintData::testSetAngle()
{
ScreenPaintData data;
QCOMPARE(data.rotationAngle(), 0.0);
data.setRotationAngle(20.0);
QCOMPARE(data.rotationAngle(), 20.0);
}
void TestScreenPaintData::testSetRotationOrigin()
{
ScreenPaintData data;
QCOMPARE(data.rotationOrigin(), QVector3D());
data.setRotationOrigin(QVector3D(1.0, 2.0, 3.0));
QCOMPARE(data.rotationOrigin(), QVector3D(1.0, 2.0, 3.0));
}
void TestScreenPaintData::testSetRotationAxis()
{
ScreenPaintData data;
QCOMPARE(data.rotationAxis(), QVector3D(0.0, 0.0, 1.0));
data.setRotationAxis(Qt::XAxis);
QCOMPARE(data.rotationAxis(), QVector3D(1.0, 0.0, 0.0));
data.setRotationAxis(Qt::YAxis);
QCOMPARE(data.rotationAxis(), QVector3D(0.0, 1.0, 0.0));
data.setRotationAxis(Qt::ZAxis);
QCOMPARE(data.rotationAxis(), QVector3D(0.0, 0.0, 1.0));
data.setRotationAxis(QVector3D(1.0, 1.0, 0.0));
QCOMPARE(data.rotationAxis(), QVector3D(1.0, 1.0, 0.0));
}
QTEST_MAIN(TestScreenPaintData)
#include "test_screen_paint_data.moc"
......@@ -112,8 +112,8 @@ void TrackMouseEffect::paintScreen(int mask, const QRegion &region, ScreenPaintD
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
QMatrix4x4 matrix(data.projectionMatrix());
const QPointF p = m_lastRect[0].topLeft() + QPoint(m_lastRect[0].width() / 2.0, m_lastRect[0].height() / 2.0);
const float x = p.x() * data.xScale() + data.xTranslation();
const float y = p.y() * data.yScale() + data.yTranslation();
const float x = p.x();
const float y = p.y();
for (int i = 0; i < 2; ++i) {
matrix.translate(x, y, 0.0);
matrix.rotate(i ? -2 * m_angle : m_angle, 0, 0, 1.0);
......
......@@ -312,22 +312,23 @@ void ZoomEffect::paintScreen(int mask, const QRegion &region, ScreenPaintData &d
effects->paintScreen(mask, region, data);
GLFramebuffer::popFramebuffer();
data *= QVector2D(zoom, zoom);
const QSize screenSize = effects->virtualScreenSize();
// mouse-tracking allows navigation of the zoom-area using the mouse.
qreal xTranslation = 0;
qreal yTranslation = 0;
switch (mouseTracking) {
case MouseTrackingProportional:
data.setXTranslation(-int(cursorPoint.x() * (zoom - 1.0)));
data.setYTranslation(-int(cursorPoint.y() * (zoom - 1.0)));
xTranslation = -int(cursorPoint.x() * (zoom - 1.0));
yTranslation = -int(cursorPoint.y() * (zoom - 1.0));
prevPoint = cursorPoint;
break;
case MouseTrackingCentred:
prevPoint = cursorPoint;
// fall through
case MouseTrackingDisabled:
data.setXTranslation(qMin(0, qMax(int(screenSize.width() - screenSize.width() * zoom), int(screenSize.width() / 2 - prevPoint.x() * zoom))));
data.setYTranslation(qMin(0, qMax(int(screenSize.height() - screenSize.height() * zoom), int(screenSize.height() / 2 - prevPoint.y() * zoom))));
xTranslation = qMin(0, qMax(int(screenSize.width() - screenSize.width() * zoom), int(screenSize.width() / 2 - prevPoint.x() * zoom)));
yTranslation = qMin(0, qMax(int(screenSize.height() - screenSize.height() * zoom), int(screenSize.height() / 2 - prevPoint.y() * zoom)));
break;
case MouseTrackingPush: {
// touching an edge of the screen moves the zoom-area in that direction.
......@@ -351,8 +352,8 @@ void ZoomEffect::paintScreen(int mask, const QRegion &region, ScreenPaintData &d
if (yMove) {
prevPoint.setY(qMax(0, qMin(screenSize.height(), prevPoint.y() + yMove)));
}
data.setXTranslation(-int(prevPoint.x() * (zoom - 1.0)));
data.setYTranslation(-int(prevPoint.y() * (zoom - 1.0)));
xTranslation = -int(prevPoint.x() * (zoom - 1.0));
yTranslation = -int(prevPoint.y() * (zoom - 1.0));
break;
}
}
......@@ -367,8 +368,8 @@ void ZoomEffect::paintScreen(int mask, const QRegion &region, ScreenPaintData &d
acceptFocus = msecs > focusDelay;
}
if (acceptFocus) {
data.setXTranslation(-int(focusPoint.x() * (zoom - 1.0)));
data.setYTranslation(-int(focusPoint.y() * (zoom - 1.0)));
xTranslation = -int(focusPoint.x() * (zoom - 1.0));
yTranslation = -int(focusPoint.y() * (zoom - 1.0));
prevPoint = focusPoint;
}
}
......@@ -378,8 +379,8 @@ void ZoomEffect::paintScreen(int mask, const QRegion &region, ScreenPaintData &d
glClear(GL_COLOR_BUFFER_BIT);
QMatrix4x4 matrix;
matrix.translate(data.translation());
matrix.scale(data.scale());
matrix.translate(xTranslation, yTranslation);
matrix.scale(zoom, zoom);
auto shader = ShaderManager::instance()->pushShader(ShaderTrait::MapTexture);
shader->setUniform(GLShader::ModelViewProjectionMatrix, data.projectionMatrix() * matrix);
......@@ -404,7 +405,7 @@ void ZoomEffect::paintScreen(int mask, const QRegion &region, ScreenPaintData &d
}
const QPoint p = effects->cursorPos() - cursor.hotSpot();
QRect rect(p * zoom + QPoint(data.xTranslation(), data.yTranslation()), cursorSize);
QRect rect(p * zoom + QPoint(xTranslation, yTranslation), cursorSize);
cursorTexture->bind();
glEnable(GL_BLEND);
......
......@@ -404,14 +404,12 @@ public:
};
ScreenPaintData::ScreenPaintData()
: PaintData()
, d(new Private())
: d(new Private())
{
}
ScreenPaintData::ScreenPaintData(const QMatrix4x4 &projectionMatrix, EffectScreen *screen)
: PaintData()
, d(new Private())
: d(new Private())
{
d->projectionMatrix = projectionMatrix;
d->screen = screen;
......@@ -420,80 +418,19 @@ ScreenPaintData::ScreenPaintData(const QMatrix4x4 &projectionMatrix, EffectScree
ScreenPaintData::~ScreenPaintData() = default;
ScreenPaintData::ScreenPaintData(const ScreenPaintData &other)
: PaintData()
, d(new Private())
: d(new Private())
{
translate(other.translation());
setXScale(other.xScale());
setYScale(other.yScale());
setZScale(other.zScale());
setRotationOrigin(other.rotationOrigin());
setRotationAxis(other.rotationAxis());
setRotationAngle(other.rotationAngle());
d->projectionMatrix = other.d->projectionMatrix;
d->screen = other.d->screen;
}
ScreenPaintData &ScreenPaintData::operator=(const ScreenPaintData &rhs)
{
setXScale(rhs.xScale());
setYScale(rhs.yScale());
setZScale(rhs.zScale());
setXTranslation(rhs.xTranslation());
setYTranslation(rhs.yTranslation());
setZTranslation(rhs.zTranslation());
setRotationOrigin(rhs.rotationOrigin());
setRotationAxis(rhs.rotationAxis());
setRotationAngle(rhs.rotationAngle());
d->projectionMatrix = rhs.d->projectionMatrix;
d->screen = rhs.d->screen;
return *this;
}
ScreenPaintData &ScreenPaintData::operator*=(qreal scale)
{
setXScale(this->xScale() * scale);
setYScale(this->yScale() * scale);
setZScale(this->zScale() * scale);
return *this;
}
ScreenPaintData &ScreenPaintData::operator*=(const QVector2D &scale)
{
setXScale(this->xScale() * scale.x());
setYScale(this->yScale() * scale.y());
return *this;
}
ScreenPaintData &ScreenPaintData::operator*=(const QVector3D &scale)
{
setXScale(this->xScale() * scale.x());
setYScale(this->yScale() * scale.y());
setZScale(this->zScale() * scale.z());
return *this;
}
ScreenPaintData &ScreenPaintData::operator+=(const QPointF &translation)
{
return this->operator+=(QVector3D(translation));
}
ScreenPaintData &ScreenPaintData::operator+=(const QPoint &translation)
{
return this->operator+=(QVector3D(translation));
}
ScreenPaintData &ScreenPaintData::operator+=(const QVector2D &translation)
{
return this->operator+=(QVector3D(translation));
}
ScreenPaintData &ScreenPaintData::operator+=(const QVector3D &translation)
{
translate(translation);
return *this;
}
QMatrix4x4 ScreenPaintData::projectionMatrix() const
{
return d->projectionMatrix;
......
......@@ -3292,54 +3292,14 @@ private:
WindowPaintDataPrivate *const d;
};
class KWINEFFECTS_EXPORT ScreenPaintData : public PaintData
class KWINEFFECTS_EXPORT ScreenPaintData
{
public:
ScreenPaintData();
ScreenPaintData(const QMatrix4x4 &projectionMatrix, EffectScreen *screen = nullptr);
ScreenPaintData(const ScreenPaintData &other);
~ScreenPaintData() override;
/**
* Scales the screen by @p scale factor.
* Multiplies all three components by the given factor.
* @since 4.10
*/
ScreenPaintData &operator*=(qreal scale);
/**
* Scales the screen by @p scale factor.
* Performs a component wise multiplication on x and y components.
* @since 4.10
*/
ScreenPaintData &operator*=(const QVector2D &scale);
/**
* Scales the screen by @p scale factor.
* Performs a component wise multiplication.
* @since 4.10
*/
ScreenPaintData &operator*=(const QVector3D &scale);
/**
* Translates the screen by the given @p translation and returns a reference to the ScreenPaintData.
* @since 4.10
*/
ScreenPaintData &operator+=(const QPointF &translation);
/**
* Translates the screen by the given @p translation and returns a reference to the ScreenPaintData.
* Overloaded method for convenience.
* @since 4.10
*/
ScreenPaintData &operator+=(const QPoint &translation);
/**
* Translates the screen by the given @p translation and returns a reference to the ScreenPaintData.
* Overloaded method for convenience.
* @since 4.10
*/
ScreenPaintData &operator+=(const QVector2D &translation);
/**
* Translates the screen by the given @p translation and returns a reference to the ScreenPaintData.
* Overloaded method for convenience.
* @since 4.10
*/
ScreenPaintData &operator+=(const QVector3D &translation);
~ScreenPaintData();
ScreenPaintData &operator=(const ScreenPaintData &rhs);
/**
......
......@@ -580,7 +580,7 @@ void Scene::paintWindow(WindowItem *item, int mask, const QRegion &region)
return;
}
WindowPaintData data(screenProjectionMatrix());
WindowPaintData data(renderTargetProjectionMatrix());
effects->paintWindow(item->window()->effectWindow(), mask, region, data);
}
......@@ -610,11 +610,6 @@ bool Scene::supportsNativeFence() const
return false;
}
QMatrix4x4 Scene::screenProjectionMatrix() const
{
return QMatrix4x4();
}
QPainter *Scene::scenePainter() const
{
return nullptr;
......
......@@ -132,8 +132,6 @@ public:
virtual void doneOpenGLContextCurrent();
virtual bool supportsNativeFence() const;
virtual QMatrix4x4 screenProjectionMatrix() const;
virtual DecorationRenderer *createDecorationRenderer(Decoration::DecoratedClientImpl *) = 0;
/**
......@@ -193,10 +191,10 @@ protected:
// shared implementation of painting the screen in the generic
// (unoptimized) way
void preparePaintGenericScreen();
virtual void paintGenericScreen(int mask, const ScreenPaintData &data);
void paintGenericScreen(int mask, const ScreenPaintData &data);
// shared implementation of painting the screen in an optimized way
void preparePaintSimpleScreen();
virtual void paintSimpleScreen(int mask, const QRegion &region);
void paintSimpleScreen(int mask, const QRegion &region);
// paint the background (not the desktop background - the whole background)
virtual void paintBackground(const QRegion &region) = 0;
// called after all effects had their paintWindow() called
......
......@@ -99,32 +99,6 @@ void SceneOpenGL::paint(RenderTarget *renderTarget, const QRegion &region)
GLVertexBuffer::streamingBuffer()->endOfFrame();
}
QMatrix4x4 SceneOpenGL::transformation(int mask, const ScreenPaintData &data) const
{
QMatrix4x4 matrix;
if (!(mask & PAINT_SCREEN_TRANSFORMED)) {
return matrix;
}
matrix.translate(data.translation());
const QVector3D scale = data.scale();
matrix.scale(scale.x(), scale.y(), scale.z());
if (data.rotationAngle() == 0.0) {