diff --git a/abstract_output.h b/abstract_output.h --- a/abstract_output.h +++ b/abstract_output.h @@ -117,6 +117,8 @@ return false; } + QSize orientateSize(const QSize &size) const; + Q_SIGNALS: void modeChanged(); @@ -171,8 +173,6 @@ void setWaylandMode(const QSize &size, int refreshRate); - QSize orientateSize(const QSize &size) const; - private: QPointer m_waylandOutput; QPointer m_xdgOutput; diff --git a/abstract_output.cpp b/abstract_output.cpp --- a/abstract_output.cpp +++ b/abstract_output.cpp @@ -54,7 +54,7 @@ QRect AbstractOutput::geometry() const { - return QRect(m_globalPos, pixelSize() / scale()); + return QRect(m_globalPos, orientateSize(pixelSize()) / scale()); } QSize AbstractOutput::physicalSize() const @@ -101,7 +101,7 @@ m_waylandOutputDevice->setScaleF(scale); } if (m_xdgOutput) { - m_xdgOutput->setLogicalSize(pixelSize() / m_scale); + m_xdgOutput->setLogicalSize(orientateSize(pixelSize()) / m_scale); m_xdgOutput->done(); } emit modeChanged(); @@ -160,7 +160,7 @@ } m_waylandOutput->setCurrentMode(size, refreshRate); if (m_xdgOutput) { - m_xdgOutput->setLogicalSize(pixelSize() / scale()); + m_xdgOutput->setLogicalSize(orientateSize(pixelSize()) / scale()); m_xdgOutput->done(); } } diff --git a/autotests/mock_screens.h b/autotests/mock_screens.h --- a/autotests/mock_screens.h +++ b/autotests/mock_screens.h @@ -37,6 +37,7 @@ float refreshRate(int screen) const override; QSize size(int screen) const override; void init() override; + int rotation(int /*screen*/) const override { return 0; } void setGeometries(const QList &geometries); diff --git a/platform.h b/platform.h --- a/platform.h +++ b/platform.h @@ -449,6 +449,8 @@ m_selectedCompositor = type; } + virtual QVector screenRotations() const; + public Q_SLOTS: void pointerMotion(const QPointF &position, quint32 time); void pointerButtonPressed(quint32 button, quint32 time); diff --git a/platform.cpp b/platform.cpp --- a/platform.cpp +++ b/platform.cpp @@ -392,6 +392,11 @@ return QVector({1}); } +QVector Platform::screenRotations() const +{ + return {0}; +} + bool Platform::requiresCompositing() const { return true; diff --git a/plugins/platforms/drm/drm_output.h b/plugins/platforms/drm/drm_output.h --- a/plugins/platforms/drm/drm_output.h +++ b/plugins/platforms/drm/drm_output.h @@ -87,6 +87,9 @@ bool supportsTransformations() const; + ///returns the angle to rotate the display to fit the output + int softwareRotationAngle() const { return m_softwareRotationAngle; } + Q_SIGNALS: void dpmsChanged(); @@ -160,6 +163,7 @@ bool m_hasNewCursor = false; bool m_internal = false; bool m_deleted = false; + int m_softwareRotationAngle = 0; }; } diff --git a/plugins/platforms/drm/drm_output.cpp b/plugins/platforms/drm/drm_output.cpp --- a/plugins/platforms/drm/drm_output.cpp +++ b/plugins/platforms/drm/drm_output.cpp @@ -24,6 +24,7 @@ #include "drm_object_connector.h" #include +#include #include "composite.h" #include "logind.h" @@ -783,7 +784,7 @@ QSize DrmOutput::pixelSize() const { - return orientateSize(QSize(m_mode.hdisplay, m_mode.vdisplay)); + return QSize(m_mode.hdisplay, m_mode.vdisplay); } void DrmOutput::setWaylandMode() @@ -876,6 +877,27 @@ } +///Copied from QPlatformScreen +static int angleBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b) +{ + if (a == Qt::PrimaryOrientation) a = Qt::LandscapeOrientation; + if (b == Qt::PrimaryOrientation) b = Qt::LandscapeOrientation; + + if (a == b) + return 0; + + int ia = std::log2(uint(a)); + int ib = std::log2(uint(b)); + + int delta = ia - ib; + + if (delta < 0) + delta = delta + 4; + + int angles[] = { 0, 90, 180, 270 }; + return angles[delta]; +} + bool DrmOutput::presentAtomically(DrmBuffer *buffer) { if (!LogindIntegration::self()->isActiveSession()) { @@ -891,14 +913,16 @@ m_primaryPlane->setNext(buffer); m_nextPlanesFlipList << m_primaryPlane; + m_softwareRotationAngle = 0; if (!doAtomicCommit(AtomicCommitMode::Test)) { //TODO: When we use planes for layered rendering, fallback to renderer instead. Also for direct scanout? //TODO: Probably should undo setNext and reset the flip list qCDebug(KWIN_DRM) << "Atomic test commit failed. Aborting present."; // go back to previous state if (m_lastWorkingState.valid) { m_mode = m_lastWorkingState.mode; - setOrientation(m_lastWorkingState.orientation); + m_softwareRotationAngle = angleBetween(m_lastWorkingState.orientation, orientation()); + qCDebug(KWIN_DRM) << "setting software rotation to" << m_softwareRotationAngle; setGlobalPos(m_lastWorkingState.globalPos); if (m_primaryPlane) { m_primaryPlane->setTransformation(m_lastWorkingState.planeTransformations); diff --git a/plugins/platforms/drm/egl_gbm_backend.cpp b/plugins/platforms/drm/egl_gbm_backend.cpp --- a/plugins/platforms/drm/egl_gbm_backend.cpp +++ b/plugins/platforms/drm/egl_gbm_backend.cpp @@ -232,8 +232,9 @@ return false; } // TODO: ensure the viewport is set correctly each time - const QSize &overall = screens()->size(); + const QSize &overall = output.output->orientateSize(screens()->size()); const QRect &v = output.output->geometry(); + qCWarning(KWIN_DRM) << "setting viewport" << overall << v; // TODO: are the values correct? qreal scale = output.output->scale(); diff --git a/plugins/platforms/drm/screens_drm.h b/plugins/platforms/drm/screens_drm.h --- a/plugins/platforms/drm/screens_drm.h +++ b/plugins/platforms/drm/screens_drm.h @@ -33,6 +33,7 @@ virtual ~DrmScreens(); bool supportsTransformations(int screen) const override; + int rotation(int screen) const override; DrmBackend *m_backend; }; diff --git a/plugins/platforms/drm/screens_drm.cpp b/plugins/platforms/drm/screens_drm.cpp --- a/plugins/platforms/drm/screens_drm.cpp +++ b/plugins/platforms/drm/screens_drm.cpp @@ -43,4 +43,13 @@ return enOuts.at(screen)->supportsTransformations(); } +int DrmScreens::rotation(int screen) const +{ + const auto enOuts = m_backend->drmEnabledOutputs(); + if (screen >= enOuts.size()) { + return false; + } + return enOuts.at(screen)->softwareRotationAngle(); +} + } diff --git a/plugins/platforms/virtual/screens_virtual.h b/plugins/platforms/virtual/screens_virtual.h --- a/plugins/platforms/virtual/screens_virtual.h +++ b/plugins/platforms/virtual/screens_virtual.h @@ -33,6 +33,7 @@ VirtualScreens(VirtualBackend *backend, QObject *parent = nullptr); virtual ~VirtualScreens(); void init() override; + int rotation(int /*screen*/) const override { return 0; } private: void createOutputs(); diff --git a/plugins/platforms/x11/standalone/screens_xrandr.h b/plugins/platforms/x11/standalone/screens_xrandr.h --- a/plugins/platforms/x11/standalone/screens_xrandr.h +++ b/plugins/platforms/x11/standalone/screens_xrandr.h @@ -41,6 +41,7 @@ float refreshRate(int screen) const override; QSize size(int screen) const override; QSize displaySize() const override; + int rotation(int /*screen*/) const override { return 0; } using QObject::event; bool event(xcb_generic_event_t *event) override; diff --git a/plugins/scenes/opengl/scene_opengl.h b/plugins/scenes/opengl/scene_opengl.h --- a/plugins/scenes/opengl/scene_opengl.h +++ b/plugins/scenes/opengl/scene_opengl.h @@ -94,7 +94,7 @@ void handleGraphicsReset(GLenum status); virtual void doPaintBackground(const QVector &vertices) = 0; - virtual void updateProjectionMatrix() = 0; + virtual void updateProjectionMatrix(int rotation) = 0; protected: bool init_ok; @@ -128,17 +128,17 @@ virtual void doPaintBackground(const QVector< float >& vertices); virtual Scene::Window *createWindow(Toplevel *t); virtual void finalDrawWindow(EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data); - virtual void updateProjectionMatrix() override; + virtual void updateProjectionMatrix(int rotation) override; void paintCursor() override; + QMatrix4x4 m_projectionMatrix; private: void performPaintWindow(EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data); - QMatrix4x4 createProjectionMatrix() const; + QMatrix4x4 createProjectionMatrix(int rotation) const; private: LanczosFilter *m_lanczosFilter; QScopedPointer m_cursorTexture; - QMatrix4x4 m_projectionMatrix; QMatrix4x4 m_screenProjectionMatrix; GLuint vao; }; diff --git a/plugins/scenes/opengl/scene_opengl.cpp b/plugins/scenes/opengl/scene_opengl.cpp --- a/plugins/scenes/opengl/scene_opengl.cpp +++ b/plugins/scenes/opengl/scene_opengl.cpp @@ -656,6 +656,7 @@ // trigger start render timer m_backend->prepareRenderingFrame(); for (int i = 0; i < screens()->count(); ++i) { + const auto rotation = screens()->rotation(i); const QRect &geo = screens()->geometry(i); QRegion update; QRegion valid; @@ -673,7 +674,8 @@ } int mask = 0; - updateProjectionMatrix(); + updateProjectionMatrix(rotation); + paintScreen(&mask, damage.intersected(geo), repaint, &update, &valid, projectionMatrix(), geo); // call generic implementation paintCursor(); @@ -698,7 +700,7 @@ GLRenderTarget::setVirtualScreenScale(1); int mask = 0; - updateProjectionMatrix(); + updateProjectionMatrix(0); paintScreen(&mask, damage, repaint, &updateRegion, &validRegion, projectionMatrix()); // call generic implementation if (!GLPlatform::instance()->isGLES()) { @@ -960,7 +962,7 @@ } } -QMatrix4x4 SceneOpenGL2::createProjectionMatrix() const +QMatrix4x4 SceneOpenGL2::createProjectionMatrix(int rotation) const { // Create a perspective projection with a 60° field-of-view, // and an aspect ratio of 1.0. @@ -976,6 +978,8 @@ QMatrix4x4 projection; projection.frustum(xMin, xMax, yMin, yMax, zNear, zFar); + if (rotation != 0) + projection.rotate(rotation, 0,0,1); // Create a second matrix that transforms screen coordinates // to world coordinates. @@ -992,9 +996,9 @@ return projection * matrix; } -void SceneOpenGL2::updateProjectionMatrix() +void SceneOpenGL2::updateProjectionMatrix(int rotation) { - m_projectionMatrix = createProjectionMatrix(); + m_projectionMatrix = createProjectionMatrix(rotation); } void SceneOpenGL2::paintSimpleScreen(int mask, QRegion region) diff --git a/screens.h b/screens.h --- a/screens.h +++ b/screens.h @@ -157,6 +157,8 @@ return m_orientationSensor; } + virtual int rotation(int screen) const = 0; + public Q_SLOTS: void reconfigure(); @@ -230,11 +232,13 @@ QSize size(int screen) const override; qreal scale(int screen) const override; void updateCount() override; + int rotation(int screen) const override; private: Platform *m_backend; QVector m_geometries; QVector m_scales; + QVector m_rotations; }; inline diff --git a/screens.cpp b/screens.cpp --- a/screens.cpp +++ b/screens.cpp @@ -289,8 +289,15 @@ return 1; } + +int BasicScreens::rotation(int screen) const +{ + return m_rotations.value(screen, 0); +} + void BasicScreens::updateCount() { + m_rotations = m_backend->screenRotations(); m_geometries = m_backend->screenGeometries(); m_scales = m_backend->screenScales(); setCount(m_geometries.count());