diff --git a/plugins/platforms/drm/drm_object.h b/plugins/platforms/drm/drm_object.h --- a/plugins/platforms/drm/drm_object.h +++ b/plugins/platforms/drm/drm_object.h @@ -74,10 +74,24 @@ virtual bool atomicPopulate(drmModeAtomicReq *req); + enum class Transformation { + Rotate0 = 1 << 0, + Rotate90 = 1 << 1, + Rotate180 = 1 << 2, + Rotate270 = 1 << 3, + ReflectX = 1 << 4, + ReflectY = 1 << 5 + }; + Q_DECLARE_FLAGS(Transformations, Transformation); + Transformations supportedTransformations() const { + return m_supportedTransformations; + } + protected: virtual bool initProps() = 0; // only derived classes know names and quantity of properties void setPropertyNames(QVector &&vector); void initProp(int n, drmModeObjectProperties *properties, QVector enumNames = QVector(0)); + void initTransformationProp(int n, drmModeObjectProperties *properties); class Property; bool atomicAddProperty(drmModeAtomicReq *req, Property *property); @@ -127,6 +141,7 @@ private: QVector m_propsNames; + Transformations m_supportedTransformations = Transformation::Rotate0; }; diff --git a/plugins/platforms/drm/drm_object.cpp b/plugins/platforms/drm/drm_object.cpp --- a/plugins/platforms/drm/drm_object.cpp +++ b/plugins/platforms/drm/drm_object.cpp @@ -62,6 +62,30 @@ } } +void DrmObject::initTransformationProp(int n, drmModeObjectProperties *properties) +{ + initProp(n, properties, { + QByteArrayLiteral("rotate-0"), + QByteArrayLiteral("rotate-90"), + QByteArrayLiteral("rotate-180"), + QByteArrayLiteral("rotate-270"), + QByteArrayLiteral("reflect-x"), + QByteArrayLiteral("reflect-y") + }); + m_supportedTransformations = Transformations(); + auto testTransform = [n, this] (uint64_t value, Transformation t) { + if (propHasEnum(n, value)) { + m_supportedTransformations |= t; + } + }; + testTransform(0, Transformation::Rotate0); + testTransform(1, Transformation::Rotate90); + testTransform(2, Transformation::Rotate180); + testTransform(3, Transformation::Rotate270); + testTransform(4, Transformation::ReflectX); + testTransform(5, Transformation::ReflectY); +} + bool DrmObject::atomicAddProperty(drmModeAtomicReq *req, Property *property) { if (drmModeAtomicAddProperty(req, m_id, property->propId(), property->value()) <= 0) { diff --git a/plugins/platforms/drm/drm_object_crtc.h b/plugins/platforms/drm/drm_object_crtc.h --- a/plugins/platforms/drm/drm_object_crtc.h +++ b/plugins/platforms/drm/drm_object_crtc.h @@ -45,6 +45,7 @@ enum class PropertyIndex { ModeId = 0, Active, + Rotation, Count }; @@ -72,6 +73,9 @@ } bool setGammaRamp(const ColorCorrect::GammaRamp &gamma); + void setTransformation(Transformations t); + Transformations transformation(); + private: int m_resIndex; uint32_t m_gammaRampSize = 0; diff --git a/plugins/platforms/drm/drm_object_crtc.cpp b/plugins/platforms/drm/drm_object_crtc.cpp --- a/plugins/platforms/drm/drm_object_crtc.cpp +++ b/plugins/platforms/drm/drm_object_crtc.cpp @@ -57,6 +57,7 @@ setPropertyNames({ QByteArrayLiteral("MODE_ID"), QByteArrayLiteral("ACTIVE"), + QByteArrayLiteral("rotation") }); drmModeObjectProperties *properties = drmModeObjectGetProperties(fd(), m_id, DRM_MODE_OBJECT_CRTC); @@ -67,7 +68,12 @@ int propCount = int(PropertyIndex::Count); for (int j = 0; j < propCount; ++j) { - initProp(j, properties); + if (j == int(PropertyIndex::Rotation)) { + initTransformationProp(j, properties); + qCDebug(KWIN_DRM) << "Supported Transformations: " << supportedTransformations() << " on crtc " << m_id; + } else { + initProp(j, properties); + } } drmModeFreeObjectProperties(properties); return true; @@ -118,4 +124,20 @@ return !isError; } + +void DrmCrtc::setTransformation(Transformations t) +{ + if (auto property = m_props.at(int(PropertyIndex::Rotation))) { + property->setValue(int(t)); + } +} + +DrmCrtc::Transformations DrmCrtc::transformation() +{ + if (auto property = m_props.at(int(PropertyIndex::Rotation))) { + return Transformations(int(property->value())); + } + return Transformations(Transformation::Rotate0); +} + } diff --git a/plugins/platforms/drm/drm_object_plane.h b/plugins/platforms/drm/drm_object_plane.h --- a/plugins/platforms/drm/drm_object_plane.h +++ b/plugins/platforms/drm/drm_object_plane.h @@ -59,16 +59,6 @@ Count }; - enum class Transformation { - Rotate0 = 1 << 0, - Rotate90 = 1 << 1, - Rotate180 = 1 << 2, - Rotate270 = 1 << 3, - ReflectX = 1 << 4, - ReflectY = 1 << 5 - }; - Q_DECLARE_FLAGS(Transformations, Transformation); - bool atomicInit(); bool initProps(); TypeIndex type(); @@ -97,10 +87,6 @@ void flipBuffer(); void flipBufferWithDelete(); - Transformations supportedTransformations() const { - return m_supportedTransformations; - } - private: DrmBuffer *m_current = nullptr; DrmBuffer *m_next = nullptr; @@ -110,8 +96,6 @@ // TODO: when using overlay planes in the future: restrict possible screens / crtcs of planes uint32_t m_possibleCrtcs; - - Transformations m_supportedTransformations = Transformation::Rotate0; }; } diff --git a/plugins/platforms/drm/drm_object_plane.cpp b/plugins/platforms/drm/drm_object_plane.cpp --- a/plugins/platforms/drm/drm_object_plane.cpp +++ b/plugins/platforms/drm/drm_object_plane.cpp @@ -83,15 +83,6 @@ QByteArrayLiteral("Overlay"), }; - const QVector rotationNames{ - QByteArrayLiteral("rotate-0"), - QByteArrayLiteral("rotate-90"), - QByteArrayLiteral("rotate-180"), - QByteArrayLiteral("rotate-270"), - QByteArrayLiteral("reflect-x"), - QByteArrayLiteral("reflect-y") - }; - drmModeObjectProperties *properties = drmModeObjectGetProperties(fd(), m_id, DRM_MODE_OBJECT_PLANE); if (!properties){ qCWarning(KWIN_DRM) << "Failed to get properties for plane " << m_id ; @@ -103,20 +94,8 @@ if (j == int(PropertyIndex::Type)) { initProp(j, properties, typeNames); } else if (j == int(PropertyIndex::Rotation)) { - initProp(j, properties, rotationNames); - m_supportedTransformations = Transformations(); - auto testTransform = [j, this] (uint64_t value, Transformation t) { - if (propHasEnum(j, value)) { - m_supportedTransformations |= t; - } - }; - testTransform(0, Transformation::Rotate0); - testTransform(1, Transformation::Rotate90); - testTransform(2, Transformation::Rotate180); - testTransform(3, Transformation::Rotate270); - testTransform(4, Transformation::ReflectX); - testTransform(5, Transformation::ReflectY); - qCDebug(KWIN_DRM) << "Supported Transformations: " << m_supportedTransformations << " on plane " << m_id; + initTransformationProp(j, properties); + qCDebug(KWIN_DRM) << "Supported Transformations: " << supportedTransformations() << " on plane " << m_id; } else { initProp(j, properties); } 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 @@ -166,6 +166,7 @@ Qt::ScreenOrientation orientation; drmModeModeInfo mode; DrmPlane::Transformations planeTransformations; + DrmObject::Transformations crtcTransformations; QPoint globalPos; bool valid = false; } m_lastWorkingState; 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 @@ -818,37 +818,55 @@ using KWayland::Server::OutputInterface; auto wlOutput = waylandOutput(); + bool setOnPlane = false; + bool setOnCrtc = false; switch (transform) { case OutputDeviceInterface::Transform::Normal: if (m_primaryPlane) { m_primaryPlane->setTransformation(DrmPlane::Transformation::Rotate0); + setOnPlane = true; + } else { + m_crtc->setTransformation(DrmObject::Transformation::Rotate0); + setOnCrtc = true; } if (wlOutput) { wlOutput->setTransform(OutputInterface::Transform::Normal); } setOrientation(Qt::PrimaryOrientation); break; case OutputDeviceInterface::Transform::Rotated90: - if (m_primaryPlane) { + if (m_primaryPlane && m_primaryPlane->supportedTransformations().testFlag(DrmPlane::Transformation::Rotate90)) { m_primaryPlane->setTransformation(DrmPlane::Transformation::Rotate90); + setOnPlane = true; + } else if (m_crtc->supportedTransformations().testFlag(DrmObject::Transformation::Rotate90)) { + m_crtc->setTransformation(DrmObject::Transformation::Rotate90); + setOnCrtc = true; } if (wlOutput) { wlOutput->setTransform(OutputInterface::Transform::Rotated90); } setOrientation(Qt::PortraitOrientation); break; case OutputDeviceInterface::Transform::Rotated180: - if (m_primaryPlane) { + if (m_primaryPlane && m_primaryPlane->supportedTransformations().testFlag(DrmPlane::Transformation::Rotate180)) { m_primaryPlane->setTransformation(DrmPlane::Transformation::Rotate180); + setOnPlane = true; + } else if (m_crtc->supportedTransformations().testFlag(DrmObject::Transformation::Rotate180)) { + m_crtc->setTransformation(DrmObject::Transformation::Rotate180); + setOnCrtc = true; } if (wlOutput) { wlOutput->setTransform(OutputInterface::Transform::Rotated180); } setOrientation(Qt::InvertedLandscapeOrientation); break; case OutputDeviceInterface::Transform::Rotated270: - if (m_primaryPlane) { + if (m_primaryPlane && m_primaryPlane->supportedTransformations().testFlag(DrmPlane::Transformation::Rotate270)) { m_primaryPlane->setTransformation(DrmPlane::Transformation::Rotate270); + setOnPlane = true; + } else if (m_crtc->supportedTransformations().testFlag(DrmObject::Transformation::Rotate270)) { + m_crtc->setTransformation(DrmObject::Transformation::Rotate270); + setOnCrtc = true; } if (wlOutput) { wlOutput->setTransform(OutputInterface::Transform::Rotated270); @@ -880,6 +898,12 @@ } break; } + if (setOnPlane) { + m_crtc->setTransformation(DrmObject::Transformation::Rotate0); + } + if (setOnCrtc && m_primaryPlane) { + m_primaryPlane->setTransformation(DrmObject::Transformation::Rotate0); + } m_modesetRequested = true; // the cursor might need to get rotated updateCursor(); @@ -1015,6 +1039,9 @@ if (m_primaryPlane) { m_primaryPlane->setTransformation(m_lastWorkingState.planeTransformations); } + if (m_crtc) { + m_crtc->setTransformation(m_lastWorkingState.crtcTransformations); + } m_modesetRequested = true; // the cursor might need to get rotated updateCursor(); @@ -1039,6 +1066,9 @@ if (m_primaryPlane) { m_lastWorkingState.planeTransformations = m_primaryPlane->transformation(); } + if (m_crtc) { + m_lastWorkingState.crtcTransformations = m_crtc->transformation(); + } m_lastWorkingState.valid = true; } m_pageFlipPending = true; @@ -1232,21 +1262,21 @@ bool DrmOutput::supportsTransformations() const { - if (!m_primaryPlane) { + if (!m_primaryPlane && !m_crtc) { return false; } - const auto transformations = m_primaryPlane->supportedTransformations(); + const auto transformations = m_primaryPlane->supportedTransformations() | m_crtc->supportedTransformations(); return transformations.testFlag(DrmPlane::Transformation::Rotate90) || transformations.testFlag(DrmPlane::Transformation::Rotate180) || transformations.testFlag(DrmPlane::Transformation::Rotate270); } void DrmOutput::automaticRotation() { - if (!m_primaryPlane) { + if (!m_primaryPlane && !m_crtc) { return; } - const auto supportedTransformations = m_primaryPlane->supportedTransformations(); + const auto supportedTransformations = m_primaryPlane->supportedTransformations() | m_crtc->supportedTransformations(); const auto requestedTransformation = screens()->orientationSensor()->orientation(); using KWayland::Server::OutputDeviceInterface; OutputDeviceInterface::Transform newTransformation = OutputDeviceInterface::Transform::Normal;