diff --git a/abstract_output.h b/abstract_output.h --- a/abstract_output.h +++ b/abstract_output.h @@ -117,6 +117,15 @@ return false; } + /** + * @returns the angle to rotate the display to fit the output + **/ + virtual int softwareRotationAngle() const { + return 0; + } + + QSize orientateSize(const QSize &size) const; + Q_SIGNALS: void modeChanged(); @@ -168,8 +177,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/autotests/test_screen_paint_data.cpp b/autotests/test_screen_paint_data.cpp --- a/autotests/test_screen_paint_data.cpp +++ b/autotests/test_screen_paint_data.cpp @@ -63,7 +63,7 @@ void TestScreenPaintData::testCopyCtor() { - ScreenPaintData data(QMatrix4x4(), QRect(10, 20, 30, 40)); + ScreenPaintData data(QMatrix4x4(), 0, QRect(10, 20, 30, 40)); ScreenPaintData data2(data); // no value had been changed QCOMPARE(data2.xScale(), 1.0); @@ -100,7 +100,7 @@ void TestScreenPaintData::testAssignmentOperator() { ScreenPaintData data; - ScreenPaintData data2(QMatrix4x4(), QRect(10, 20, 30, 40)); + ScreenPaintData data2(QMatrix4x4(), 0, QRect(10, 20, 30, 40)); data2.setScale(QVector3D(0.5, 2.0, 3.0)); data2.translate(0.5, 2.0, 3.0); diff --git a/effects/backgroundcontrast/contrast.h b/effects/backgroundcontrast/contrast.h --- a/effects/backgroundcontrast/contrast.h +++ b/effects/backgroundcontrast/contrast.h @@ -65,6 +65,7 @@ } bool eventFilter(QObject *watched, QEvent *event) override; + void paintScreen(int mask, QRegion region, KWin::ScreenPaintData & data) override; public Q_SLOTS: void slotWindowAdded(KWin::EffectWindow *w); @@ -88,6 +89,7 @@ QHash< const EffectWindow*, QMatrix4x4> m_colorMatrices; QHash< const EffectWindow*, QMetaObject::Connection > m_contrastChangedConnections; // used only in Wayland to keep track of effect changed KWayland::Server::ContrastManagerInterface *m_contrastManager = nullptr; + int m_screenRotation = 0; }; inline diff --git a/effects/backgroundcontrast/contrast.cpp b/effects/backgroundcontrast/contrast.cpp --- a/effects/backgroundcontrast/contrast.cpp +++ b/effects/backgroundcontrast/contrast.cpp @@ -193,6 +193,12 @@ updateContrastRegion(w); } +void ContrastEffect::paintScreen(int mask, QRegion region, KWin::ScreenPaintData & data) +{ + Effect::paintScreen(mask, region, data); + m_screenRotation = data.screenRotation(); +} + bool ContrastEffect::eventFilter(QObject *watched, QEvent *event) { auto internal = qobject_cast(watched); @@ -476,6 +482,10 @@ void ContrastEffect::doContrast(EffectWindow *w, const QRegion& shape, const QRect& screen, const float opacity, const QMatrix4x4 &screenProjection) { + if (m_screenRotation == 90 || m_screenRotation == 270) { + return; + } + const QRegion actualShape = shape & screen; const QRect r = actualShape.boundingRect(); diff --git a/effects/blur/blur.h b/effects/blur/blur.h --- a/effects/blur/blur.h +++ b/effects/blur/blur.h @@ -57,6 +57,7 @@ void reconfigure(ReconfigureFlags flags) override; void prePaintScreen(ScreenPrePaintData &data, int time) override; + void paintScreen(int mask, QRegion region, KWin::ScreenPaintData & data) override; void prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) override; void drawWindow(EffectWindow *w, int mask, QRegion region, WindowPaintData &data) override; void paintEffectFrame(EffectFrame *frame, QRegion region, double opacity, double frameOpacity) override; @@ -114,6 +115,7 @@ int m_expandSize; int m_noiseStrength; int m_scalingFactor; + int m_screenRotation = 0; struct OffsetStruct { float minOffset; diff --git a/effects/blur/blur.cpp b/effects/blur/blur.cpp --- a/effects/blur/blur.cpp +++ b/effects/blur/blur.cpp @@ -470,6 +470,12 @@ effects->prePaintScreen(data, time); } +void BlurEffect::paintScreen(int mask, QRegion region, KWin::ScreenPaintData & data) +{ + Effect::paintScreen(mask, region, data); + m_screenRotation = data.screenRotation(); +} + void BlurEffect::prePaintWindow(EffectWindow* w, WindowPrePaintData& data, int time) { // this effect relies on prePaintWindow being called in the bottom to top order @@ -636,6 +642,9 @@ void BlurEffect::doBlur(const QRegion& shape, const QRect& screen, const float opacity, const QMatrix4x4 &screenProjection, bool isDock, QRect windowRect) { + if (m_screenRotation == 90 || m_screenRotation == 270) { + return; + } // Blur would not render correctly on a secondary monitor because of wrong coordinates // BUG: 393723 const int xTranslate = -screen.x(); diff --git a/effects/screenshot/screenshot.h b/effects/screenshot/screenshot.h --- a/effects/screenshot/screenshot.h +++ b/effects/screenshot/screenshot.h @@ -155,6 +155,7 @@ ScreenShotType m_type; QRect m_scheduledGeometry; QDBusMessage m_replyMessage; + qreal m_rotation = 0; QRect m_cachedOutputGeometry; QImage m_multipleOutputsImage; QRegion m_multipleOutputsRendered; diff --git a/effects/screenshot/screenshot.cpp b/effects/screenshot/screenshot.cpp --- a/effects/screenshot/screenshot.cpp +++ b/effects/screenshot/screenshot.cpp @@ -89,6 +89,7 @@ void ScreenShotEffect::paintScreen(int mask, QRegion region, ScreenPaintData &data) { + m_rotation = data.screenRotation(); m_cachedOutputGeometry = data.outputGeometry(); effects->paintScreen(mask, region, data); } @@ -227,7 +228,14 @@ // doesn't intersect, not going onto this screenshot return; } - const QImage img = blitScreenshot(intersection); + + auto correctedIntersection = intersection; + if (m_rotation != 0 && m_rotation != 180) + correctedIntersection = correctedIntersection.transposed(); + QImage img = blitScreenshot(correctedIntersection); + if (m_rotation) + img = img.transformed(QTransform().rotate(m_rotation), Qt::SmoothTransformation); + if (img.size() == m_scheduledGeometry.size()) { // we are done sendReplyImage(img); @@ -553,7 +561,7 @@ if (GLRenderTarget::blitSupported() && !GLPlatform::instance()->isGLES()) { GLTexture tex(GL_RGBA8, geometry.width(), geometry.height()); GLRenderTarget target(tex); - target.blitFromFramebuffer(geometry); + target.blitFromFramebuffer(geometry, {}, GL_LINEAR, m_rotation == 90 || m_rotation == 270); // copy content from framebuffer into image tex.bind(); glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)img.bits()); @@ -588,6 +596,7 @@ return; QPainter painter(&snapshot); + painter.rotate(-m_rotation); painter.drawImage(effects->cursorPos() - cursor.hotSpot() - QPoint(offsetx, offsety), cursor.image()); } diff --git a/libkwineffects/kwineffects.h b/libkwineffects/kwineffects.h --- a/libkwineffects/kwineffects.h +++ b/libkwineffects/kwineffects.h @@ -2908,7 +2908,7 @@ { public: ScreenPaintData(); - ScreenPaintData(const QMatrix4x4 &projectionMatrix, const QRect &outputGeometry = QRect()); + ScreenPaintData(const QMatrix4x4 &projectionMatrix, int screenRotation, const QRect &outputGeometry = QRect()); ScreenPaintData(const ScreenPaintData &other); virtual ~ScreenPaintData(); /** @@ -2961,6 +2961,8 @@ **/ QMatrix4x4 projectionMatrix() const; + int screenRotation() const; + /** * The geometry of the currently rendered output. * Only set for per-output rendering (e.g. Wayland). diff --git a/libkwineffects/kwineffects.cpp b/libkwineffects/kwineffects.cpp --- a/libkwineffects/kwineffects.cpp +++ b/libkwineffects/kwineffects.cpp @@ -437,20 +437,22 @@ public: QMatrix4x4 projectionMatrix; QRect outputGeometry; + int screenRotation = 0; }; ScreenPaintData::ScreenPaintData() : PaintData() , d(new Private()) { } -ScreenPaintData::ScreenPaintData(const QMatrix4x4 &projectionMatrix, const QRect &outputGeometry) +ScreenPaintData::ScreenPaintData(const QMatrix4x4 &projectionMatrix, int rotation, const QRect &outputGeometry) : PaintData() , d(new Private()) { d->projectionMatrix = projectionMatrix; d->outputGeometry = outputGeometry; + d->screenRotation = rotation; } ScreenPaintData::~ScreenPaintData() = default; @@ -540,6 +542,11 @@ return d->outputGeometry; } +int ScreenPaintData::screenRotation() const +{ + return d->screenRotation; +} + //**************************************** // Effect //**************************************** diff --git a/libkwineffects/kwinglutils.h b/libkwineffects/kwinglutils.h --- a/libkwineffects/kwinglutils.h +++ b/libkwineffects/kwinglutils.h @@ -498,7 +498,7 @@ * @see blitSupported * @since 4.8 **/ - void blitFromFramebuffer(const QRect &source = QRect(), const QRect &destination = QRect(), GLenum filter = GL_LINEAR); + void blitFromFramebuffer(const QRect &source = QRect(), const QRect &destination = QRect(), GLenum filter = GL_LINEAR, bool transpose = false); /** * Sets the virtual screen size to @p s. diff --git a/libkwineffects/kwinglutils.cpp b/libkwineffects/kwinglutils.cpp --- a/libkwineffects/kwinglutils.cpp +++ b/libkwineffects/kwinglutils.cpp @@ -1225,7 +1225,7 @@ glGenFramebuffers(1, &mFramebuffer); #if DEBUG_GLRENDERTARGET - if ((err = glGetError()) != GL_NO_ERROR) { + if ((err = glGetError()) != GL_NO_ERROR) { qCCritical(LIBKWINGLUTILS) << "glGenFramebuffers failed: " << formatGLError(err); return; } @@ -1270,7 +1270,7 @@ mValid = true; } -void GLRenderTarget::blitFromFramebuffer(const QRect &source, const QRect &destination, GLenum filter) +void GLRenderTarget::blitFromFramebuffer(const QRect &source, const QRect &destination, GLenum filter, bool transpose) { if (!GLRenderTarget::blitSupported()) { return; @@ -1283,13 +1283,14 @@ GLRenderTarget::pushRenderTarget(this); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mFramebuffer); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - const QRect s = source.isNull() ? s_virtualScreenGeometry : source; + const auto vsg = transpose ? s_virtualScreenGeometry.transposed() : s_virtualScreenGeometry; + const QRect s = source.isNull() ? vsg : source; const QRect d = destination.isNull() ? QRect(0, 0, mTexture.width(), mTexture.height()) : destination; - glBlitFramebuffer((s.x() - s_virtualScreenGeometry.x()) * s_virtualScreenScale, - (s_virtualScreenGeometry.height() - (s.y() - s_virtualScreenGeometry.y() + s.height())) * s_virtualScreenScale, - (s.x() - s_virtualScreenGeometry.x() + s.width()) * s_virtualScreenScale, - (s_virtualScreenGeometry.height() - (s.y() - s_virtualScreenGeometry.y())) * s_virtualScreenScale, + glBlitFramebuffer((s.x() - vsg.x()) * s_virtualScreenScale, + (vsg.height() - (s.y() - vsg.y() + s.height())) * s_virtualScreenScale, + (s.x() - vsg.x() + s.width()) * s_virtualScreenScale, + (vsg.height() - (s.y() - vsg.y())) * s_virtualScreenScale, d.x(), mTexture.height() - d.y() - d.height(), d.x() + d.width(), mTexture.height() - d.y(), GL_COLOR_BUFFER_BIT, filter); GLRenderTarget::popRenderTarget(); diff --git a/outputscreens.h b/outputscreens.h --- a/outputscreens.h +++ b/outputscreens.h @@ -43,6 +43,7 @@ QSize size(int screen) const override; qreal scale(int screen) const override; float refreshRate(int screen) const override; + int rotation(int screen) const override; Qt::ScreenOrientation orientation(int screen) const override; void updateCount() override; int number(const QPoint &pos) const override; diff --git a/outputscreens.cpp b/outputscreens.cpp --- a/outputscreens.cpp +++ b/outputscreens.cpp @@ -110,6 +110,14 @@ } return enOuts.at(screen)->orientation(); } +int OutputScreens::rotation(int screen) const +{ + auto output = m_platform->enabledOutputs().value(screen, nullptr); + if (!output) { + return 0; + } + return output->softwareRotationAngle(); +} void OutputScreens::updateCount() { 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/platformsupport/scenes/opengl/abstract_egl_backend.h b/platformsupport/scenes/opengl/abstract_egl_backend.h --- a/platformsupport/scenes/opengl/abstract_egl_backend.h +++ b/platformsupport/scenes/opengl/abstract_egl_backend.h @@ -38,6 +38,7 @@ namespace KWin { +class AbstractOutput; class KWIN_EXPORT AbstractEglBackend : public QObject, public OpenGLBackend { @@ -77,6 +78,8 @@ bool createContext(); + static QRect orientateRect(AbstractOutput *output, const QRect &r); + private: void unbindWaylandDisplay(); diff --git a/platformsupport/scenes/opengl/abstract_egl_backend.cpp b/platformsupport/scenes/opengl/abstract_egl_backend.cpp --- a/platformsupport/scenes/opengl/abstract_egl_backend.cpp +++ b/platformsupport/scenes/opengl/abstract_egl_backend.cpp @@ -19,6 +19,7 @@ *********************************************************************/ #include "abstract_egl_backend.h" #include "texture.h" +#include "abstract_output.h" #include "composite.h" #include "egl_context_attribute_builder.h" #include "options.h" @@ -546,5 +547,16 @@ return true; } + +QRect AbstractEglBackend::orientateRect(AbstractOutput *output, const QRect &r) +{ + if (output->softwareRotationAngle() != 0) { + QTransform m; + m.rotate(-output->softwareRotationAngle(), Qt::ZAxis); + return QRect(m.map(r.topLeft()), r.size()); + } + return r; +} + } 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 @@ -94,6 +94,10 @@ bool supportsTransformations() const; + int softwareRotationAngle() const override { + return m_softwareRotationAngle; + } + Q_SIGNALS: void dpmsChanged(); @@ -136,6 +140,8 @@ int getGammaRampSize() const override; bool setGammaRamp(const ColorCorrect::GammaRamp &gamma) override; + int angleBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b) const; + DrmBackend *m_backend; DrmConnector *m_conn = nullptr; DrmCrtc *m_crtc = nullptr; @@ -166,6 +172,8 @@ int m_cursorIndex = 0; bool m_hasNewCursor = false; bool m_deleted = false; + int m_softwareRotationAngle = 0; + Qt::ScreenOrientation m_preferredOrientation = Qt::LandscapeOrientation; }; } 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" @@ -312,6 +313,7 @@ const QString model = connectorName + QStringLiteral("-") + QString::number(connector->connector_type_id) + QStringLiteral("-") + modelName; // read in mode information + m_preferredOrientation = Qt::LandscapeOrientation; QVector modes; for (int i = 0; i < connector->count_modes; ++i) { // TODO: in AMS here we could read and store for later every mode's blob_id @@ -322,6 +324,7 @@ deviceflags |= KWayland::Server::OutputDeviceInterface::ModeFlag::Current; } if (m->type & DRM_MODE_TYPE_PREFERRED) { + m_preferredOrientation = m->hdisplay > m->vdisplay ? Qt::LandscapeOrientation : Qt::PortraitOrientation; deviceflags |= KWayland::Server::OutputDeviceInterface::ModeFlag::Preferred; } @@ -713,6 +716,7 @@ using KWayland::Server::OutputDeviceInterface; using KWayland::Server::OutputInterface; auto wlOutput = waylandOutput(); + m_softwareRotationAngle = 0; switch (transform) { case OutputDeviceInterface::Transform::Normal: @@ -804,7 +808,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() @@ -897,6 +901,27 @@ } +///Copied from QPlatformScreen +int DrmOutput::angleBetween(Qt::ScreenOrientation a, Qt::ScreenOrientation b) const +{ + if (a == Qt::PrimaryOrientation) a = m_preferredOrientation; + if (b == Qt::PrimaryOrientation) b = m_preferredOrientation; + + 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()) { @@ -928,7 +953,8 @@ // 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) << "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 @@ -215,9 +215,9 @@ } } -bool EglGbmBackend::makeContextCurrent(const Output &output) +bool EglGbmBackend::makeContextCurrent(const Output &_output) { - const EGLSurface surface = output.eglSurface; + const EGLSurface surface = _output.eglSurface; if (surface == EGL_NO_SURFACE) { return false; } @@ -231,15 +231,15 @@ qCWarning(KWIN_DRM) << "Error occurred while creating context " << error; return false; } - // TODO: ensure the viewport is set correctly each time - const QSize &overall = screens()->size(); - const QRect &v = output.output->geometry(); - // TODO: are the values correct? - - qreal scale = output.output->scale(); + DrmOutput* output = _output.output; + const QRect v = orientateRect(output, output->geometry()); + const qreal scale = output->scale(); + const QSize overall = screens()->size(); + const QSize orientedOverall = output->orientateSize(overall) * scale; glViewport(-v.x() * scale, (v.height() - overall.height() + v.y()) * scale, - overall.width() * scale, overall.height() * scale); + orientedOverall.width(), orientedOverall.height()); + return true; } 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,9 @@ 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/virtual/virtual_output.h b/plugins/platforms/virtual/virtual_output.h --- a/plugins/platforms/virtual/virtual_output.h +++ b/plugins/platforms/virtual/virtual_output.h @@ -49,6 +49,10 @@ return m_gammaResult; } + int softwareRotationAngle() const override { + return 0; + } + private: Q_DISABLE_COPY(VirtualOutput); friend class VirtualBackend; diff --git a/plugins/platforms/wayland/egl_wayland_backend.cpp b/plugins/platforms/wayland/egl_wayland_backend.cpp --- a/plugins/platforms/wayland/egl_wayland_backend.cpp +++ b/plugins/platforms/wayland/egl_wayland_backend.cpp @@ -240,13 +240,13 @@ return false; } - const QRect &v = output->m_waylandOutput->geometry(); - - qreal scale = output->m_waylandOutput->scale(); - + const QRect v = orientateRect(output->m_waylandOutput, output->m_waylandOutput->geometry()); + const qreal scale = output->m_waylandOutput->scale(); const QSize overall = screens()->size(); + const QSize orientedOverall = output->m_waylandOutput->orientateSize(overall) * scale; glViewport(-v.x() * scale, (v.height() - overall.height() + v.y()) * scale, - overall.width() * scale, overall.height() * scale); + orientedOverall.width(), orientedOverall.height()); + return true; } 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,9 @@ 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,12 +128,12 @@ 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; private: void performPaintWindow(EffectWindowImpl* w, int mask, QRegion region, WindowPaintData& data); - QMatrix4x4 createProjectionMatrix() const; + QMatrix4x4 createProjectionMatrix(int rotation) const; private: LanczosFilter *m_lanczosFilter; 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 @@ -661,6 +661,7 @@ // trigger start render timer m_backend->prepareRenderingFrame(); for (int i = 0; i < screens()->count(); ++i) { + const int rotation = screens()->rotation(i); const QRect &geo = screens()->geometry(i); QRegion update; QRegion valid; @@ -678,8 +679,9 @@ } int mask = 0; - updateProjectionMatrix(); - paintScreen(&mask, damage.intersected(geo), repaint, &update, &valid, projectionMatrix(), geo); // call generic implementation + updateProjectionMatrix(rotation); + + paintScreen(&mask, damage.intersected(geo), repaint, &update, &valid, rotation, projectionMatrix(), geo); // call generic implementation paintCursor(); GLVertexBuffer::streamingBuffer()->endOfFrame(); @@ -703,8 +705,8 @@ GLRenderTarget::setVirtualScreenScale(1); int mask = 0; - updateProjectionMatrix(); - paintScreen(&mask, damage, repaint, &updateRegion, &validRegion, projectionMatrix()); // call generic implementation + updateProjectionMatrix(0); + paintScreen(&mask, damage, repaint, &updateRegion, &validRegion, 0, projectionMatrix()); // call generic implementation if (!GLPlatform::instance()->isGLES()) { const QSize &screenSize = screens()->size(); @@ -965,7 +967,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. @@ -981,6 +983,9 @@ 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. @@ -997,9 +1002,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/plugins/scenes/qpainter/scene_qpainter.cpp b/plugins/scenes/qpainter/scene_qpainter.cpp --- a/plugins/scenes/qpainter/scene_qpainter.cpp +++ b/plugins/scenes/qpainter/scene_qpainter.cpp @@ -115,7 +115,7 @@ m_painter->setWindow(geometry); QRegion updateRegion, validRegion; - paintScreen(&mask, damage.intersected(geometry), QRegion(), &updateRegion, &validRegion); + paintScreen(&mask, damage.intersected(geometry), QRegion(), &updateRegion, &validRegion, 0); overallUpdate = overallUpdate.united(updateRegion); paintCursor(); @@ -133,7 +133,7 @@ damage = screens()->geometry(); } QRegion updateRegion, validRegion; - paintScreen(&mask, damage, QRegion(), &updateRegion, &validRegion); + paintScreen(&mask, damage, QRegion(), &updateRegion, &validRegion, 0); paintCursor(); m_backend->showOverlay(); diff --git a/plugins/scenes/xrender/scene_xrender.cpp b/plugins/scenes/xrender/scene_xrender.cpp --- a/plugins/scenes/xrender/scene_xrender.cpp +++ b/plugins/scenes/xrender/scene_xrender.cpp @@ -256,7 +256,7 @@ int mask = 0; QRegion updateRegion, validRegion; - paintScreen(&mask, damage, QRegion(), &updateRegion, &validRegion); + paintScreen(&mask, damage, QRegion(), &updateRegion, &validRegion, 0); m_backend->showOverlay(); diff --git a/scene.h b/scene.h --- a/scene.h +++ b/scene.h @@ -213,7 +213,7 @@ void clearStackingOrder(); // shared implementation, starts painting the screen void paintScreen(int *mask, const QRegion &damage, const QRegion &repaint, - QRegion *updateRegion, QRegion *validRegion, const QMatrix4x4 &projection = QMatrix4x4(), const QRect &outputGeometry = QRect()); + QRegion *updateRegion, QRegion *validRegion, int screenRotation, const QMatrix4x4 &projection = QMatrix4x4(), const QRect &outputGeometry = QRect()); // Render cursor texture in case hardware cursor is disabled/non-applicable virtual void paintCursor() = 0; friend class EffectsHandlerImpl; diff --git a/scene.cpp b/scene.cpp --- a/scene.cpp +++ b/scene.cpp @@ -105,7 +105,7 @@ // returns mask and possibly modified region void Scene::paintScreen(int* mask, const QRegion &damage, const QRegion &repaint, - QRegion *updateRegion, QRegion *validRegion, const QMatrix4x4 &projection, const QRect &outputGeometry) + QRegion *updateRegion, QRegion *validRegion, int screenRotation, const QMatrix4x4 &projection, const QRect &outputGeometry) { const QSize &screenSize = screens()->size(); const QRegion displayRegion(0, 0, screenSize.width(), screenSize.height()); @@ -145,7 +145,7 @@ paintBackground(region); } - ScreenPaintData data(projection, outputGeometry); + ScreenPaintData data(projection, screenRotation, outputGeometry); effects->paintScreen(*mask, region, data); foreach (Window *w, stacking_order) { 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,14 @@ 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());