From e7c803b7e5a3070e8b78886f1723a037ec2f8846 Mon Sep 17 00:00:00 2001 From: Xaver Hugl Date: Tue, 11 Apr 2023 13:29:07 +0200 Subject: [PATCH] backends/drm: store drm properties directly in drm objects This makes it possible to ensure type safety for enums, as each drm property object can have its own type now, and it reduces the amount of typing needed to access properties --- autotests/drm/drmTest.cpp | 2 +- autotests/drm/mock_drm.cpp | 4 +- autotests/drm/mock_drm.h | 2 +- src/backends/drm/drm_atomic_commit.cpp | 8 +- src/backends/drm/drm_atomic_commit.h | 11 +- src/backends/drm/drm_connector.cpp | 193 +++++++++++------------ src/backends/drm/drm_connector.h | 95 ++++++----- src/backends/drm/drm_crtc.cpp | 31 +++- src/backends/drm/drm_crtc.h | 19 +-- src/backends/drm/drm_gpu.cpp | 12 +- src/backends/drm/drm_object.cpp | 70 ++++---- src/backends/drm/drm_object.h | 47 ++---- src/backends/drm/drm_output.cpp | 12 +- src/backends/drm/drm_pipeline.cpp | 68 ++++---- src/backends/drm/drm_pipeline_legacy.cpp | 30 ++-- src/backends/drm/drm_plane.cpp | 148 +++++++++-------- src/backends/drm/drm_plane.h | 75 ++++----- src/backends/drm/drm_property.cpp | 118 +++++++------- src/backends/drm/drm_property.h | 129 ++++++++------- 19 files changed, 531 insertions(+), 543 deletions(-) diff --git a/autotests/drm/drmTest.cpp b/autotests/drm/drmTest.cpp index 068926582c..216c9cc086 100644 --- a/autotests/drm/drmTest.cpp +++ b/autotests/drm/drmTest.cpp @@ -272,7 +272,7 @@ void DrmTest::testModeGeneration() mockGpu->connectors.removeAll(conn); QVERIFY(gpu->updateOutputs()); - conn->props.emplace_back(conn.get(), QStringLiteral("scaling mode"), 0, 0, QVector{"None", "Full", "Center", "Full aspect"}); + conn->props.emplace_back(conn.get(), QStringLiteral("scaling mode"), 0, DRM_MODE_PROP_ENUM, QVector{"None", "Full", "Center", "Full aspect"}); mockGpu->connectors.push_back(conn); QVERIFY(gpu->updateOutputs()); diff --git a/autotests/drm/mock_drm.cpp b/autotests/drm/mock_drm.cpp index dc0ff60335..b82378b53e 100644 --- a/autotests/drm/mock_drm.cpp +++ b/autotests/drm/mock_drm.cpp @@ -231,8 +231,8 @@ MockPlane::MockPlane(MockGpu *gpu, PlaneType type, int crtcIndex) , possibleCrtcs(1 << crtcIndex) , type(type) { - props << MockProperty(this, QStringLiteral("type"), static_cast(type), DRM_MODE_PROP_IMMUTABLE | DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK, - {QByteArrayLiteral("Primary"), QByteArrayLiteral("Overlay"), QByteArrayLiteral("Cursor")}); + props << MockProperty(this, QStringLiteral("type"), static_cast(type), DRM_MODE_PROP_IMMUTABLE | DRM_MODE_PROP_ENUM, + {QByteArrayLiteral("Primary"), QByteArrayLiteral("Overlay"), QByteArrayLiteral("Cursor")}); addProp("FB_ID", 0, DRM_MODE_PROP_ATOMIC); addProp("CRTC_ID", 0, DRM_MODE_PROP_ATOMIC); addProp("CRTC_X", 0, DRM_MODE_PROP_ATOMIC); diff --git a/autotests/drm/mock_drm.h b/autotests/drm/mock_drm.h index e20ca50a9b..dece21e72a 100644 --- a/autotests/drm/mock_drm.h +++ b/autotests/drm/mock_drm.h @@ -107,7 +107,7 @@ public: }; enum class PlaneType { - Primary, + Primary = 0, Overlay, Cursor }; diff --git a/src/backends/drm/drm_atomic_commit.cpp b/src/backends/drm/drm_atomic_commit.cpp index d74e295a18..a1da0be148 100644 --- a/src/backends/drm/drm_atomic_commit.cpp +++ b/src/backends/drm/drm_atomic_commit.cpp @@ -21,15 +21,15 @@ DrmAtomicCommit::DrmAtomicCommit(DrmGpu *gpu) { } -void DrmAtomicCommit::addProperty(DrmProperty *prop, uint64_t value) +void DrmAtomicCommit::addProperty(const DrmProperty &prop, uint64_t value) { - drmModeAtomicAddProperty(m_req.get(), prop->drmObject()->id(), prop->propId(), value); + drmModeAtomicAddProperty(m_req.get(), prop.drmObject()->id(), prop.propId(), value); } -void DrmAtomicCommit::addBlob(DrmProperty *prop, const std::shared_ptr &blob) +void DrmAtomicCommit::addBlob(const DrmProperty &prop, const std::shared_ptr &blob) { addProperty(prop, blob ? blob->blobId() : 0); - m_blobs[prop] = blob; + m_blobs[&prop] = blob; } bool DrmAtomicCommit::test() diff --git a/src/backends/drm/drm_atomic_commit.h b/src/backends/drm/drm_atomic_commit.h index 43e5bc82c8..f97354ab57 100644 --- a/src/backends/drm/drm_atomic_commit.h +++ b/src/backends/drm/drm_atomic_commit.h @@ -28,12 +28,13 @@ class DrmAtomicCommit public: DrmAtomicCommit(DrmGpu *gpu); - void addProperty(DrmProperty *prop, uint64_t value); - void addEnum(DrmProperty *prop, auto enumValue) + void addProperty(const DrmProperty &prop, uint64_t value); + template + void addEnum(const DrmEnumProperty &prop, T enumValue) { - addProperty(prop, prop->valueForEnum(enumValue)); + addProperty(prop, prop.valueForEnum(enumValue)); } - void addBlob(DrmProperty *prop, const std::shared_ptr &blob); + void addBlob(const DrmProperty &prop, const std::shared_ptr &blob); bool test(); bool testAllowModeset(); @@ -45,7 +46,7 @@ public: private: DrmGpu *const m_gpu; DrmUniquePtr m_req; - QHash> m_blobs; + QHash> m_blobs; }; } diff --git a/src/backends/drm/drm_connector.cpp b/src/backends/drm/drm_connector.cpp index 6b94836ac8..f8919192be 100644 --- a/src/backends/drm/drm_connector.cpp +++ b/src/backends/drm/drm_connector.cpp @@ -85,29 +85,50 @@ bool DrmConnectorMode::operator==(const DrmConnectorMode &otherMode) } DrmConnector::DrmConnector(DrmGpu *gpu, uint32_t connectorId) - : DrmObject(gpu, - connectorId, - {PropertyDefinition(QByteArrayLiteral("CRTC_ID"), Requirement::Required), - PropertyDefinition(QByteArrayLiteral("non-desktop"), Requirement::Optional), - PropertyDefinition(QByteArrayLiteral("DPMS"), Requirement::RequiredForLegacy), - PropertyDefinition(QByteArrayLiteral("EDID"), Requirement::Optional), - PropertyDefinition(QByteArrayLiteral("overscan"), Requirement::Optional), - PropertyDefinition(QByteArrayLiteral("vrr_capable"), Requirement::Optional), - PropertyDefinition(QByteArrayLiteral("underscan"), Requirement::Optional, - {QByteArrayLiteral("off"), QByteArrayLiteral("on"), QByteArrayLiteral("auto")}), - PropertyDefinition(QByteArrayLiteral("underscan vborder"), Requirement::Optional), - PropertyDefinition(QByteArrayLiteral("underscan hborder"), Requirement::Optional), - PropertyDefinition(QByteArrayLiteral("Broadcast RGB"), Requirement::Optional, - {QByteArrayLiteral("Automatic"), QByteArrayLiteral("Full"), QByteArrayLiteral("Limited 16:235")}), - PropertyDefinition(QByteArrayLiteral("max bpc"), Requirement::Optional), - PropertyDefinition(QByteArrayLiteral("link-status"), Requirement::Optional, - {QByteArrayLiteral("Good"), QByteArrayLiteral("Bad")}), - PropertyDefinition(QByteArrayLiteral("content type"), Requirement::Optional, - {QByteArrayLiteral("No Data"), QByteArrayLiteral("Graphics"), QByteArrayLiteral("Photo"), QByteArrayLiteral("Cinema"), QByteArrayLiteral("Game")}), - PropertyDefinition(QByteArrayLiteral("panel orientation"), Requirement::Optional, {QByteArrayLiteral("Normal"), QByteArrayLiteral("Upside Down"), QByteArrayLiteral("Left Side Up"), QByteArrayLiteral("Right Side Up")}), - PropertyDefinition(QByteArrayLiteral("HDR_OUTPUT_METADATA"), Requirement::Optional), - PropertyDefinition(QByteArrayLiteral("scaling mode"), Requirement::Optional, {QByteArrayLiteral("None"), QByteArrayLiteral("Full"), QByteArrayLiteral("Center"), QByteArrayLiteral("Full aspect")})}, - DRM_MODE_OBJECT_CONNECTOR) + : DrmObject(gpu, connectorId, DRM_MODE_OBJECT_CONNECTOR) + , crtcId(this, QByteArrayLiteral("CRTC_ID")) + , nonDesktop(this, QByteArrayLiteral("non-desktop")) + , dpms(this, QByteArrayLiteral("DPMS")) + , edidProp(this, QByteArrayLiteral("EDID")) + , overscan(this, QByteArrayLiteral("overscan")) + , vrrCapable(this, QByteArrayLiteral("vrr_capable")) + , underscan(this, QByteArrayLiteral("EDID"), { + QByteArrayLiteral("off"), + QByteArrayLiteral("on"), + QByteArrayLiteral("auto"), + }) + , underscanVBorder(this, QByteArrayLiteral("underscan vborder")) + , underscanHBorder(this, QByteArrayLiteral("underscan hborder")) + , broadcastRGB(this, QByteArrayLiteral("Broadcast RGB"), { + QByteArrayLiteral("Automatic"), + QByteArrayLiteral("Full"), + QByteArrayLiteral("Limited 16:235"), + }) + , maxBpc(this, QByteArrayLiteral("max bpc")) + , linkStatus(this, QByteArrayLiteral("link-status"), { + QByteArrayLiteral("Good"), + QByteArrayLiteral("Bad"), + }) + , contentType(this, QByteArrayLiteral("content type"), { + QByteArrayLiteral("No Data"), + QByteArrayLiteral("Graphics"), + QByteArrayLiteral("Photo"), + QByteArrayLiteral("Cinema"), + QByteArrayLiteral("Game"), + }) + , panelOrientation(this, QByteArrayLiteral("panel orientation"), { + QByteArrayLiteral("Normal"), + QByteArrayLiteral("Upside Down"), + QByteArrayLiteral("Left Side Up"), + QByteArrayLiteral("Right Side Up"), + }) + , hdrMetadata(this, QByteArrayLiteral("HDR_OUTPUT_METADATA")) + , scalingMode(this, QByteArrayLiteral("scaling mode"), { + QByteArrayLiteral("None"), + QByteArrayLiteral("Full"), + QByteArrayLiteral("Center"), + QByteArrayLiteral("Full aspect"), + }) , m_pipeline(std::make_unique(this)) , m_conn(drmModeGetConnector(gpu->fd(), connectorId)) { @@ -125,11 +146,6 @@ DrmConnector::DrmConnector(DrmGpu *gpu, uint32_t connectorId) } } -bool DrmConnector::init() -{ - return updateProperties(); -} - bool DrmConnector::isConnected() const { return !m_driverModes.empty() && m_conn && m_conn->connection == DRM_MODE_CONNECTED; @@ -197,39 +213,6 @@ Output::SubPixel DrmConnector::subpixel() const } } -bool DrmConnector::hasOverscan() const -{ - return getProp(PropertyIndex::Overscan) || getProp(PropertyIndex::Underscan); -} - -uint32_t DrmConnector::overscan() const -{ - if (const auto prop = getProp(PropertyIndex::Overscan)) { - return prop->current(); - } else if (const auto prop = getProp(PropertyIndex::Underscan_vborder)) { - return prop->current(); - } - return 0; -} - -bool DrmConnector::vrrCapable() const -{ - const auto prop = getProp(PropertyIndex::VrrCapable); - return prop && prop->current() == 1; -} - -bool DrmConnector::hasRgbRange() const -{ - const auto &rgb = getProp(PropertyIndex::Broadcast_RGB); - return rgb && rgb->hasAllEnums(); -} - -Output::RgbRange DrmConnector::rgbRange() const -{ - const auto &rgb = getProp(PropertyIndex::Broadcast_RGB); - return rgb->enumForValue(rgb->current()); -} - bool DrmConnector::updateProperties() { if (auto connector = drmModeGetConnector(gpu()->fd(), id())) { @@ -237,25 +220,31 @@ bool DrmConnector::updateProperties() } else if (!m_conn) { return false; } - if (!DrmObject::updateProperties()) { + DrmPropertyList props = queryProperties(); + crtcId.update(props); + nonDesktop.update(props); + dpms.update(props); + edidProp.update(props); + overscan.update(props); + vrrCapable.update(props); + underscan.update(props); + underscanVBorder.update(props); + underscanHBorder.update(props); + broadcastRGB.update(props); + maxBpc.update(props); + linkStatus.update(props); + contentType.update(props); + panelOrientation.update(props); + hdrMetadata.update(props); + scalingMode.update(props); + + if (gpu()->atomicModeSetting() && !crtcId.isValid()) { return false; } - if (const auto &dpms = getProp(PropertyIndex::Dpms)) { - dpms->setLegacy(); - } - - auto &underscan = m_props[static_cast(PropertyIndex::Underscan)]; - auto &vborder = m_props[static_cast(PropertyIndex::Underscan_vborder)]; - auto &hborder = m_props[static_cast(PropertyIndex::Underscan_hborder)]; - if (!underscan || !vborder || !hborder) { - underscan.reset(); - vborder.reset(); - hborder.reset(); - } // parse edid - if (const auto edidProp = getProp(PropertyIndex::Edid); edidProp && edidProp->immutableBlob()) { - m_edid = Edid(edidProp->immutableBlob()->data, edidProp->immutableBlob()->length); + if (edidProp.immutableBlob()) { + m_edid = Edid(edidProp.immutableBlob()->data, edidProp.immutableBlob()->length); if (!m_edid.isValid()) { qCWarning(KWIN_DRM) << "Couldn't parse EDID for connector" << this; } @@ -283,7 +272,7 @@ bool DrmConnector::updateProperties() } m_modes.clear(); m_modes.append(m_driverModes); - if (auto scaling = getProp(PropertyIndex::ScalingMode); scaling && scaling->hasEnum(ScalingMode::Full_Aspect)) { + if (scalingMode.isValid() && scalingMode.hasEnum(ScalingMode::Full_Aspect)) { m_modes.append(generateCommonModes()); } if (m_pipeline->mode()) { @@ -311,8 +300,7 @@ bool DrmConnector::isCrtcSupported(DrmCrtc *crtc) const bool DrmConnector::isNonDesktop() const { - const auto &prop = getProp(PropertyIndex::NonDesktop); - return prop && prop->current(); + return nonDesktop.isValid() && nonDesktop.value() == 1; } const Edid *DrmConnector::edid() const @@ -327,15 +315,7 @@ DrmPipeline *DrmConnector::pipeline() const void DrmConnector::disable(DrmAtomicCommit *commit) { - commit->addProperty(getProp(PropertyIndex::CrtcId), 0); -} - -DrmConnector::LinkStatus DrmConnector::linkStatus() const -{ - if (const auto &property = getProp(PropertyIndex::LinkStatus)) { - return property->enumForValue(property->current()); - } - return LinkStatus::Good; + commit->addProperty(crtcId, 0); } static const QVector s_commonModes = { @@ -413,15 +393,6 @@ std::shared_ptr DrmConnector::generateMode(const QSize &size, return std::make_shared(this, mode); } -DrmConnector::PanelOrientation DrmConnector::panelOrientation() const -{ - if (const auto &property = getProp(PropertyIndex::PanelOrientation)) { - return property->enumForValue(property->current()); - } else { - return PanelOrientation::Normal; - } -} - QDebug &operator<<(QDebug &s, const KWin::DrmConnector *obj) { QDebugStateSaver saver(s); @@ -473,4 +444,32 @@ Output::Transform DrmConnector::toKWinTransform(PanelOrientation orientation) Q_UNREACHABLE(); } } + +DrmConnector::BroadcastRgbOptions DrmConnector::rgbRangeToBroadcastRgb(Output::RgbRange rgbRange) +{ + switch (rgbRange) { + case Output::RgbRange::Automatic: + return BroadcastRgbOptions::Automatic; + case Output::RgbRange::Full: + return BroadcastRgbOptions::Full; + case Output::RgbRange::Limited: + return BroadcastRgbOptions::Limited; + default: + Q_UNREACHABLE(); + } +} + +Output::RgbRange DrmConnector::broadcastRgbToRgbRange(BroadcastRgbOptions rgbRange) +{ + switch (rgbRange) { + case BroadcastRgbOptions::Automatic: + return Output::RgbRange::Automatic; + case BroadcastRgbOptions::Full: + return Output::RgbRange::Full; + case BroadcastRgbOptions::Limited: + return Output::RgbRange::Limited; + default: + Q_UNREACHABLE(); + } +} } diff --git a/src/backends/drm/drm_connector.h b/src/backends/drm/drm_connector.h index f40327a848..9c3f4c9689 100644 --- a/src/backends/drm/drm_connector.h +++ b/src/backends/drm/drm_connector.h @@ -51,32 +51,36 @@ class DrmConnector : public DrmObject public: DrmConnector(DrmGpu *gpu, uint32_t connectorId); - enum class PropertyIndex : uint32_t { - CrtcId = 0, - NonDesktop = 1, - Dpms = 2, - Edid = 3, - Overscan = 4, - VrrCapable = 5, - Underscan = 6, - Underscan_vborder = 7, - Underscan_hborder = 8, - Broadcast_RGB = 9, - MaxBpc = 10, - LinkStatus = 11, - ContentType = 12, - PanelOrientation = 13, - HdrMetadata = 14, - ScalingMode = 15, - Count - }; + bool updateProperties() override; + void disable(DrmAtomicCommit *commit) override; + + bool isCrtcSupported(DrmCrtc *crtc) const; + bool isConnected() const; + bool isNonDesktop() const; + bool isInternal() const; + DrmPipeline *pipeline() const; + + const Edid *edid() const; + QString connectorName() const; + QString modelName() const; + QSize physicalSize() const; + + QList> modes() const; + std::shared_ptr findMode(const drmModeModeInfo &modeInfo) const; - enum class UnderscanOptions : uint32_t { + Output::SubPixel subpixel() const; + + enum class UnderscanOptions : uint64_t { Off = 0, On = 1, Auto = 2, }; - enum class LinkStatus : uint32_t { + enum class BroadcastRgbOptions : uint64_t { + Automatic = 0, + Full = 1, + Limited = 2 + }; + enum class LinkStatus : uint64_t { Good = 0, Bad = 1 }; @@ -87,48 +91,39 @@ public: Cinema = 3, Game = 4 }; - enum class PanelOrientation : uint32_t { + enum class PanelOrientation : uint64_t { Normal = 0, UpsideDown = 1, LeftUp = 2, RightUp = 3 }; - enum class ScalingMode : uint32_t { + enum class ScalingMode : uint64_t { None = 0, Full = 1, Center = 2, Full_Aspect = 3 }; - - bool init() override; - bool updateProperties() override; - void disable(DrmAtomicCommit *commit) override; - - bool isCrtcSupported(DrmCrtc *crtc) const; - bool isConnected() const; - bool isNonDesktop() const; - bool isInternal() const; - DrmPipeline *pipeline() const; - - const Edid *edid() const; - QString connectorName() const; - QString modelName() const; - QSize physicalSize() const; - - QList> modes() const; - std::shared_ptr findMode(const drmModeModeInfo &modeInfo) const; - - Output::SubPixel subpixel() const; - bool hasOverscan() const; - uint32_t overscan() const; - bool vrrCapable() const; - bool hasRgbRange() const; - Output::RgbRange rgbRange() const; - LinkStatus linkStatus() const; - PanelOrientation panelOrientation() const; + DrmProperty crtcId; + DrmProperty nonDesktop; + DrmProperty dpms; + DrmProperty edidProp; + DrmProperty overscan; + DrmProperty vrrCapable; + DrmEnumProperty underscan; + DrmProperty underscanVBorder; + DrmProperty underscanHBorder; + DrmEnumProperty broadcastRGB; + DrmProperty maxBpc; + DrmEnumProperty linkStatus; + DrmEnumProperty contentType; + DrmEnumProperty panelOrientation; + DrmProperty hdrMetadata; + DrmEnumProperty scalingMode; static DrmContentType kwinToDrmContentType(ContentType type); static Output::Transform toKWinTransform(PanelOrientation orientation); + static BroadcastRgbOptions rgbRangeToBroadcastRgb(Output::RgbRange rgbRange); + static Output::RgbRange broadcastRgbToRgbRange(BroadcastRgbOptions rgbRange); private: QList> generateCommonModes(); diff --git a/src/backends/drm/drm_crtc.cpp b/src/backends/drm/drm_crtc.cpp index 4e1652e6ff..485cd247cf 100644 --- a/src/backends/drm/drm_crtc.cpp +++ b/src/backends/drm/drm_crtc.cpp @@ -20,7 +20,13 @@ namespace KWin { DrmCrtc::DrmCrtc(DrmGpu *gpu, uint32_t crtcId, int pipeIndex, DrmPlane *primaryPlane, DrmPlane *cursorPlane) - : DrmObject(gpu, crtcId, {PropertyDefinition(QByteArrayLiteral("MODE_ID"), Requirement::Required), PropertyDefinition(QByteArrayLiteral("ACTIVE"), Requirement::Required), PropertyDefinition(QByteArrayLiteral("VRR_ENABLED"), Requirement::Optional), PropertyDefinition(QByteArrayLiteral("GAMMA_LUT"), Requirement::Optional), PropertyDefinition(QByteArrayLiteral("GAMMA_LUT_SIZE"), Requirement::Optional), PropertyDefinition(QByteArrayLiteral("CTM"), Requirement::Optional)}, DRM_MODE_OBJECT_CRTC) + : DrmObject(gpu, crtcId, DRM_MODE_OBJECT_CRTC) + , modeId(this, QByteArrayLiteral("MODE_ID")) + , active(this, QByteArrayLiteral("ACTIVE")) + , vrrEnabled(this, QByteArrayLiteral("VRR_ENABLED")) + , gammaLut(this, QByteArrayLiteral("GAMMA_LUT")) + , gammaLutSize(this, QByteArrayLiteral("GAMMA_LUT_SIZE")) + , ctm(this, QByteArrayLiteral("CTM")) , m_crtc(drmModeGetCrtc(gpu->fd(), crtcId)) , m_pipeIndex(pipeIndex) , m_primaryPlane(primaryPlane) @@ -28,9 +34,20 @@ DrmCrtc::DrmCrtc(DrmGpu *gpu, uint32_t crtcId, int pipeIndex, DrmPlane *primaryP { } -bool DrmCrtc::init() +bool DrmCrtc::updateProperties() { - return m_crtc && updateProperties(); + if (!m_crtc) { + return false; + } + DrmPropertyList props = queryProperties(); + modeId.update(props); + active.update(props); + vrrEnabled.update(props); + gammaLut.update(props); + gammaLutSize.update(props); + ctm.update(props); + + return !gpu()->atomicModeSetting() || (modeId.isValid() && active.isValid()); } void DrmCrtc::flipBuffer() @@ -74,8 +91,8 @@ int DrmCrtc::gammaRampSize() const { if (gpu()->atomicModeSetting()) { // limit atomic gamma ramp to 4096 to work around https://gitlab.freedesktop.org/drm/intel/-/issues/3916 - if (auto prop = getProp(PropertyIndex::Gamma_LUT_Size); prop && prop->current() <= 4096) { - return prop->current(); + if (gammaLutSize.isValid() && gammaLutSize.value() <= 4096) { + return gammaLutSize.value(); } } return m_crtc->gamma_size; @@ -93,8 +110,8 @@ DrmPlane *DrmCrtc::cursorPlane() const void DrmCrtc::disable(DrmAtomicCommit *commit) { - commit->addProperty(getProp(PropertyIndex::Active), 0); - commit->addProperty(getProp(PropertyIndex::ModeId), 0); + commit->addProperty(active, 0); + commit->addProperty(modeId, 0); } void DrmCrtc::releaseBuffers() diff --git a/src/backends/drm/drm_crtc.h b/src/backends/drm/drm_crtc.h index 321f9d23bf..54a192cba9 100644 --- a/src/backends/drm/drm_crtc.h +++ b/src/backends/drm/drm_crtc.h @@ -28,18 +28,8 @@ class DrmCrtc : public DrmObject public: DrmCrtc(DrmGpu *gpu, uint32_t crtcId, int pipeIndex, DrmPlane *primaryPlane, DrmPlane *cursorPlane); - enum class PropertyIndex : uint32_t { - ModeId = 0, - Active, - VrrEnabled, - Gamma_LUT, - Gamma_LUT_Size, - CTM, - Count - }; - - bool init() override; void disable(DrmAtomicCommit *commit) override; + bool updateProperties() override; int pipeIndex() const; int gammaRampSize() const; @@ -54,6 +44,13 @@ public: void flipBuffer(); void releaseBuffers(); + DrmProperty modeId; + DrmProperty active; + DrmProperty vrrEnabled; + DrmProperty gammaLut; + DrmProperty gammaLutSize; + DrmProperty ctm; + private: DrmUniquePtr m_crtc; std::shared_ptr m_currentBuffer; diff --git a/src/backends/drm/drm_gpu.cpp b/src/backends/drm/drm_gpu.cpp index d0763062b2..ee4e1f4113 100644 --- a/src/backends/drm/drm_gpu.cpp +++ b/src/backends/drm/drm_gpu.cpp @@ -173,9 +173,9 @@ void DrmGpu::initDrmResources() QVector cursorCandidates; for (const auto &plane : m_planes) { if (plane->isCrtcSupported(i) && !assignedPlanes.contains(plane.get())) { - if (plane->type() == DrmPlane::TypeIndex::Primary) { + if (plane->type.enumValue() == DrmPlane::TypeIndex::Primary) { primaryCandidates.push_back(plane.get()); - } else if (plane->type() == DrmPlane::TypeIndex::Cursor) { + } else if (plane->type.enumValue() == DrmPlane::TypeIndex::Cursor) { cursorCandidates.push_back(plane.get()); } } @@ -187,14 +187,14 @@ void DrmGpu::initDrmResources() const auto findBestPlane = [crtcId](const QVector &list) { // if the plane is already used with this crtc, prefer it const auto connected = std::find_if(list.begin(), list.end(), [crtcId](DrmPlane *plane) { - return plane->getProp(DrmPlane::PropertyIndex::CrtcId)->current() == crtcId; + return plane->crtcId.value() == crtcId; }); if (connected != list.end()) { return *connected; } // don't take away planes from other crtcs. The kernel currently rejects such commits const auto notconnected = std::find_if(list.begin(), list.end(), [](DrmPlane *plane) { - return plane->getProp(DrmPlane::PropertyIndex::CrtcId)->current() == 0; + return plane->crtcId.value() == 0; }); if (notconnected != list.end()) { return *notconnected; @@ -375,7 +375,7 @@ DrmPipeline::Error DrmGpu::checkCrtcAssignment(QVector connector DrmCrtc *currentCrtc = nullptr; if (m_atomicModeSetting) { // try the crtc that this connector is already connected to first - const uint32_t id = connector->getProp(DrmConnector::PropertyIndex::CrtcId)->current(); + const uint32_t id = connector->crtcId.value(); auto it = std::find_if(crtcs.begin(), crtcs.end(), [id](const auto &crtc) { return id == crtc->id(); }); @@ -432,7 +432,7 @@ DrmPipeline::Error DrmGpu::testPendingConfiguration() if (m_atomicModeSetting) { // sort outputs by being already connected (to any CRTC) so that already working outputs get preferred std::sort(connectors.begin(), connectors.end(), [](auto c1, auto c2) { - return c1->getProp(DrmConnector::PropertyIndex::CrtcId)->current() > c2->getProp(DrmConnector::PropertyIndex::CrtcId)->current(); + return c1->crtcId.value() > c2->crtcId.value(); }); } return checkCrtcAssignment(connectors, crtcs); diff --git a/src/backends/drm/drm_object.cpp b/src/backends/drm/drm_object.cpp index 64eb549752..edfe6808df 100644 --- a/src/backends/drm/drm_object.cpp +++ b/src/backends/drm/drm_object.cpp @@ -18,54 +18,35 @@ namespace KWin { -DrmObject::DrmObject(DrmGpu *gpu, uint32_t objectId, const QVector &&vector, uint32_t objectType) +DrmObject::DrmObject(DrmGpu *gpu, uint32_t objectId, uint32_t objectType) : m_gpu(gpu) , m_id(objectId) , m_objectType(objectType) - , m_propertyDefinitions(vector) { - m_props.resize(m_propertyDefinitions.count()); } -bool DrmObject::updateProperties() +bool DrmObject::init() +{ + return updateProperties(); +} + +DrmPropertyList DrmObject::queryProperties() const { DrmUniquePtr properties(drmModeObjectGetProperties(m_gpu->fd(), m_id, m_objectType)); if (!properties) { qCWarning(KWIN_DRM) << "Failed to get properties for object" << m_id; - return false; + return {}; } - for (int propIndex = 0; propIndex < m_propertyDefinitions.count(); propIndex++) { - const PropertyDefinition &def = m_propertyDefinitions[propIndex]; - bool found = false; - for (uint32_t drmPropIndex = 0; drmPropIndex < properties->count_props; drmPropIndex++) { - DrmUniquePtr prop(drmModeGetProperty(m_gpu->fd(), properties->props[drmPropIndex])); - if (!prop) { - qCWarning(KWIN_DRM, "Getting property %d of object %d failed!", drmPropIndex, m_id); - continue; - } - if (def.name == prop->name) { - if (m_props[propIndex]) { - m_props[propIndex]->setCurrent(properties->prop_values[drmPropIndex]); - } else { - m_props[propIndex] = std::make_unique(this, prop.get(), properties->prop_values[drmPropIndex], def.enumNames); - } - found = true; - break; - } - } - if (!found) { - m_props[propIndex].reset(); + DrmPropertyList ret; + for (uint32_t i = 0; i < properties->count_props; i++) { + DrmUniquePtr prop(drmModeGetProperty(m_gpu->fd(), properties->props[i])); + if (!prop) { + qCWarning(KWIN_DRM, "Getting property %d of object %d failed!", properties->props[i], m_id); + continue; } + ret.addProperty(std::move(prop), properties->prop_values[i]); } - for (int i = 0; i < m_propertyDefinitions.count(); i++) { - bool required = m_gpu->atomicModeSetting() ? m_propertyDefinitions[i].requirement == Requirement::Required - : m_propertyDefinitions[i].requirement == Requirement::RequiredForLegacy; - if (!m_props[i] && required) { - qCWarning(KWIN_DRM, "Required property %s for object %d not found!", qPrintable(m_propertyDefinitions[i].name), m_id); - return false; - } - } - return true; + return ret; } uint32_t DrmObject::id() const @@ -96,6 +77,25 @@ QString DrmObject::typeName() const return QStringLiteral("unknown?"); } } + +void DrmPropertyList::addProperty(DrmUniquePtr &&prop, uint64_t value) +{ + m_properties.push_back(std::make_pair(std::move(prop), value)); +} + +std::optional, uint64_t>> DrmPropertyList::takeProperty(const QByteArray &name) +{ + const auto it = std::find_if(m_properties.begin(), m_properties.end(), [&name](const auto &pair) { + return pair.first->name == name; + }); + if (it != m_properties.end()) { + auto ret = std::move(*it); + m_properties.erase(it); + return ret; + } else { + return std::nullopt; + } +} } QDebug operator<<(QDebug s, const KWin::DrmObject *obj) diff --git a/src/backends/drm/drm_object.h b/src/backends/drm/drm_object.h index df3ce37bd4..1ad0ea9de6 100644 --- a/src/backends/drm/drm_object.h +++ b/src/backends/drm/drm_object.h @@ -28,6 +28,16 @@ class DrmGpu; class DrmOutput; class DrmAtomicCommit; +class DrmPropertyList +{ +public: + void addProperty(DrmUniquePtr &&prop, uint64_t value); + std::optional, uint64_t>> takeProperty(const QByteArray &name); + +private: + std::vector, uint64_t>> m_properties; +}; + class DrmObject { public: @@ -38,54 +48,29 @@ public: * Must be called to query necessary data directly after creation. * @return true when initializing was successful */ - virtual bool init() = 0; + bool init(); /** * Set the properties in such a way that this resource won't be used anymore */ virtual void disable(DrmAtomicCommit *commit) = 0; + virtual bool updateProperties() = 0; + uint32_t id() const; DrmGpu *gpu() const; uint32_t type() const; QString typeName() const; - virtual bool updateProperties(); - - template - DrmProperty *getProp(T propIndex) const - { - return m_props[static_cast(propIndex)].get(); - } - protected: - enum class Requirement { - Required, - RequiredForLegacy, - Optional, - }; - struct PropertyDefinition - { - PropertyDefinition(const QByteArray &name, Requirement requirement, const QVector &&enumNames = {}) - : name(name) - , requirement(requirement) - , enumNames(enumNames) - { - } - QByteArray name; - Requirement requirement; - QVector enumNames; - }; - - DrmObject(DrmGpu *gpu, uint32_t objectId, const QVector &&vector, uint32_t objectType); - - std::vector> m_props; + DrmObject(DrmGpu *gpu, uint32_t objectId, uint32_t objectType); + + DrmPropertyList queryProperties() const; private: DrmGpu *m_gpu; const uint32_t m_id; const uint32_t m_objectType; - const QVector m_propertyDefinitions; }; } diff --git a/src/backends/drm/drm_output.cpp b/src/backends/drm/drm_output.cpp index 45e056c170..6f3d866bfe 100644 --- a/src/backends/drm/drm_output.cpp +++ b/src/backends/drm/drm_output.cpp @@ -55,17 +55,17 @@ DrmOutput::DrmOutput(const std::shared_ptr &conn) Capabilities capabilities = Capability::Dpms; State initialState; - if (conn->hasOverscan()) { + if (conn->overscan.isValid() || conn->underscan.isValid()) { capabilities |= Capability::Overscan; - initialState.overscan = conn->overscan(); + initialState.overscan = conn->overscan.isValid() ? conn->overscan.value() : conn->underscanVBorder.value(); } - if (conn->vrrCapable()) { + if (conn->vrrCapable.isValid() && conn->vrrCapable.value()) { capabilities |= Capability::Vrr; setVrrPolicy(RenderLoop::VrrPolicy::Automatic); } - if (conn->hasRgbRange()) { + if (conn->broadcastRGB.isValid()) { capabilities |= Capability::RgbRange; - initialState.rgbRange = conn->rgbRange(); + initialState.rgbRange = DrmConnector::broadcastRgbToRgbRange(conn->broadcastRGB.enumValue()); } const Edid *edid = conn->edid(); @@ -80,7 +80,7 @@ DrmOutput::DrmOutput(const std::shared_ptr &conn) .edid = *edid, .subPixel = conn->subpixel(), .capabilities = capabilities, - .panelOrientation = DrmConnector::toKWinTransform(conn->panelOrientation()), + .panelOrientation = conn->panelOrientation.isValid() ? DrmConnector::toKWinTransform(conn->panelOrientation.enumValue()) : Transform::Normal, .internal = conn->isInternal(), .nonDesktop = conn->isNonDesktop(), }); diff --git a/src/backends/drm/drm_pipeline.cpp b/src/backends/drm/drm_pipeline.cpp index 605bb8ce08..703db637d7 100644 --- a/src/backends/drm/drm_pipeline.cpp +++ b/src/backends/drm/drm_pipeline.cpp @@ -186,31 +186,31 @@ static QRect centerBuffer(const QSize &bufferSize, const QSize &modeSize) bool DrmPipeline::prepareAtomicPresentation(DrmAtomicCommit *commit) { - if (const auto contentType = m_connector->getProp(DrmConnector::PropertyIndex::ContentType)) { - commit->addEnum(contentType, m_pending.contentType); + if (m_connector->contentType.isValid()) { + commit->addEnum(m_connector->contentType, m_pending.contentType); } - commit->addProperty(m_pending.crtc->getProp(DrmCrtc::PropertyIndex::VrrEnabled), m_pending.syncMode == RenderLoopPrivate::SyncMode::Adaptive || m_pending.syncMode == RenderLoopPrivate::SyncMode::AdaptiveAsync); - if (const auto gamma = m_pending.crtc->getProp(DrmCrtc::PropertyIndex::Gamma_LUT)) { - commit->addBlob(gamma, m_pending.gamma ? m_pending.gamma->blob() : nullptr); + commit->addProperty(m_pending.crtc->vrrEnabled, m_pending.syncMode == RenderLoopPrivate::SyncMode::Adaptive || m_pending.syncMode == RenderLoopPrivate::SyncMode::AdaptiveAsync); + if (m_pending.crtc->gammaLut.isValid()) { + commit->addBlob(m_pending.crtc->gammaLut, m_pending.gamma ? m_pending.gamma->blob() : nullptr); } else if (m_pending.gamma) { return false; } - if (const auto ctm = m_pending.crtc->getProp(DrmCrtc::PropertyIndex::CTM)) { - commit->addBlob(ctm, m_pending.ctm); + if (m_pending.crtc->ctm.isValid()) { + commit->addBlob(m_pending.crtc->ctm, m_pending.ctm); } else if (m_pending.ctm) { return false; } const auto fb = m_pending.layer->currentBuffer().get(); m_pending.crtc->primaryPlane()->set(commit, QPoint(0, 0), fb->buffer()->size(), centerBuffer(fb->buffer()->size(), m_pending.mode->size())); - commit->addProperty(m_pending.crtc->primaryPlane()->getProp(DrmPlane::PropertyIndex::FbId), fb->framebufferId()); + commit->addProperty(m_pending.crtc->primaryPlane()->fbId, fb->framebufferId()); if (auto plane = m_pending.crtc->cursorPlane()) { const auto layer = cursorLayer(); plane->set(commit, QPoint(0, 0), gpu()->cursorSize(), QRect(layer->position(), gpu()->cursorSize())); - commit->addProperty(plane->getProp(DrmPlane::PropertyIndex::CrtcId), layer->isVisible() ? m_pending.crtc->id() : 0); - commit->addProperty(plane->getProp(DrmPlane::PropertyIndex::FbId), layer->isVisible() ? layer->currentBuffer()->framebufferId() : 0); + commit->addProperty(plane->crtcId, layer->isVisible() ? m_pending.crtc->id() : 0); + commit->addProperty(plane->fbId, layer->isVisible() ? layer->currentBuffer()->framebufferId() : 0); } return true; } @@ -229,45 +229,45 @@ void DrmPipeline::prepareAtomicDisable(DrmAtomicCommit *commit) void DrmPipeline::prepareAtomicModeset(DrmAtomicCommit *commit) { - commit->addProperty(m_connector->getProp(DrmConnector::PropertyIndex::CrtcId), m_pending.crtc->id()); - if (const auto prop = m_connector->getProp(DrmConnector::PropertyIndex::Broadcast_RGB)) { - commit->addEnum(prop, m_pending.rgbRange); + commit->addProperty(m_connector->crtcId, m_pending.crtc->id()); + if (m_connector->broadcastRGB.isValid()) { + commit->addEnum(m_connector->broadcastRGB, DrmConnector::rgbRangeToBroadcastRgb(m_pending.rgbRange)); } - if (const auto prop = m_connector->getProp(DrmConnector::PropertyIndex::LinkStatus)) { - commit->addEnum(prop, DrmConnector::LinkStatus::Good); + if (m_connector->linkStatus.isValid()) { + commit->addEnum(m_connector->linkStatus, DrmConnector::LinkStatus::Good); } - if (const auto overscan = m_connector->getProp(DrmConnector::PropertyIndex::Overscan)) { - commit->addProperty(overscan, m_pending.overscan); - } else if (const auto underscan = m_connector->getProp(DrmConnector::PropertyIndex::Underscan)) { + if (m_connector->overscan.isValid()) { + commit->addProperty(m_connector->overscan, m_pending.overscan); + } else if (m_connector->underscan.isValid()) { const uint32_t hborder = calculateUnderscan(); - commit->addEnum(underscan, m_pending.overscan != 0 ? DrmConnector::UnderscanOptions::On : DrmConnector::UnderscanOptions::Off); - commit->addProperty(m_connector->getProp(DrmConnector::PropertyIndex::Underscan_vborder), m_pending.overscan); - commit->addProperty(m_connector->getProp(DrmConnector::PropertyIndex::Underscan_hborder), hborder); + commit->addEnum(m_connector->underscan, m_pending.overscan != 0 ? DrmConnector::UnderscanOptions::On : DrmConnector::UnderscanOptions::Off); + commit->addProperty(m_connector->underscanVBorder, m_pending.overscan); + commit->addProperty(m_connector->underscanHBorder, hborder); } - if (const auto bpc = m_connector->getProp(DrmConnector::PropertyIndex::MaxBpc)) { + if (m_connector->maxBpc.isValid()) { uint64_t preferred = 8; if (auto backend = dynamic_cast(gpu()->platform()->renderBackend()); backend && backend->prefer10bpc()) { preferred = 10; } - commit->addProperty(bpc, preferred); + commit->addProperty(m_connector->maxBpc, preferred); } - if (const auto hdr = m_connector->getProp(DrmConnector::PropertyIndex::HdrMetadata)) { - commit->addProperty(hdr, 0); + if (m_connector->hdrMetadata.isValid()) { + commit->addProperty(m_connector->hdrMetadata, 0); } - if (const auto scaling = m_connector->getProp(DrmConnector::PropertyIndex::ScalingMode); scaling && scaling->hasEnum(DrmConnector::ScalingMode::None)) { - commit->addEnum(scaling, DrmConnector::ScalingMode::None); + if (m_connector->scalingMode.isValid() && m_connector->scalingMode.hasEnum(DrmConnector::ScalingMode::None)) { + commit->addEnum(m_connector->scalingMode, DrmConnector::ScalingMode::None); } - commit->addProperty(m_pending.crtc->getProp(DrmCrtc::PropertyIndex::Active), 1); - commit->addBlob(m_pending.crtc->getProp(DrmCrtc::PropertyIndex::ModeId), m_pending.mode->blob()); + commit->addProperty(m_pending.crtc->active, 1); + commit->addBlob(m_pending.crtc->modeId, m_pending.mode->blob()); - commit->addProperty(m_pending.crtc->primaryPlane()->getProp(DrmPlane::PropertyIndex::CrtcId), m_pending.crtc->id()); - if (const auto rotation = m_pending.crtc->primaryPlane()->getProp(DrmPlane::PropertyIndex::Rotation)) { - commit->addEnum(rotation, DrmPlane::Transformation::Rotate0); + commit->addProperty(m_pending.crtc->primaryPlane()->crtcId, m_pending.crtc->id()); + if (const auto &rotation = m_pending.crtc->primaryPlane()->rotation; rotation.isValid()) { + commit->addEnum(rotation, {DrmPlane::Transformation::Rotate0}); } if (m_pending.crtc->cursorPlane()) { - if (const auto rotation = m_pending.crtc->cursorPlane()->getProp(DrmPlane::PropertyIndex::Rotation)) { - commit->addEnum(rotation, DrmPlane::Transformation::Rotate0); + if (const auto &rotation = m_pending.crtc->cursorPlane()->rotation; rotation.isValid()) { + commit->addEnum(rotation, DrmPlane::Transformations(DrmPlane::Transformation::Rotate0)); } } } diff --git a/src/backends/drm/drm_pipeline_legacy.cpp b/src/backends/drm/drm_pipeline_legacy.cpp index dabf6d418e..c7b0776221 100644 --- a/src/backends/drm/drm_pipeline_legacy.cpp +++ b/src/backends/drm/drm_pipeline_legacy.cpp @@ -96,24 +96,24 @@ DrmPipeline::Error DrmPipeline::applyPendingChangesLegacy() drmModeSetCursor(gpu()->fd(), m_pending.crtc->id(), 0, 0, 0); } if (activePending()) { - auto vrr = m_pending.crtc->getProp(DrmCrtc::PropertyIndex::VrrEnabled); - if (vrr && !vrr->setPropertyLegacy(m_pending.syncMode == RenderLoopPrivate::SyncMode::Adaptive || m_pending.syncMode == RenderLoopPrivate::SyncMode::AdaptiveAsync)) { + const bool shouldEnableVrr = m_pending.syncMode == RenderLoopPrivate::SyncMode::Adaptive || m_pending.syncMode == RenderLoopPrivate::SyncMode::AdaptiveAsync; + if (m_pending.crtc->vrrEnabled.isValid() && !m_pending.crtc->vrrEnabled.setPropertyLegacy(shouldEnableVrr)) { qCWarning(KWIN_DRM) << "Setting vrr failed!" << strerror(errno); return errnoToError(); } - if (const auto &rgbRange = m_connector->getProp(DrmConnector::PropertyIndex::Broadcast_RGB)) { - rgbRange->setEnumLegacy(m_pending.rgbRange); + if (m_connector->broadcastRGB.isValid()) { + m_connector->broadcastRGB.setEnumLegacy(DrmConnector::rgbRangeToBroadcastRgb(m_pending.rgbRange)); } - if (const auto overscan = m_connector->getProp(DrmConnector::PropertyIndex::Overscan)) { - overscan->setPropertyLegacy(m_pending.overscan); - } else if (const auto underscan = m_connector->getProp(DrmConnector::PropertyIndex::Underscan)) { + if (m_connector->overscan.isValid()) { + m_connector->overscan.setPropertyLegacy(m_pending.overscan); + } else if (m_connector->underscan.isValid()) { const uint32_t hborder = calculateUnderscan(); - underscan->setEnumLegacy(m_pending.overscan != 0 ? DrmConnector::UnderscanOptions::On : DrmConnector::UnderscanOptions::Off); - m_connector->getProp(DrmConnector::PropertyIndex::Underscan_vborder)->setPropertyLegacy(m_pending.overscan); - m_connector->getProp(DrmConnector::PropertyIndex::Underscan_hborder)->setPropertyLegacy(hborder); + m_connector->underscan.setEnumLegacy(m_pending.overscan != 0 ? DrmConnector::UnderscanOptions::On : DrmConnector::UnderscanOptions::Off); + m_connector->underscanVBorder.setPropertyLegacy(m_pending.overscan); + m_connector->underscanHBorder.setPropertyLegacy(hborder); } - if (const auto scaling = m_connector->getProp(DrmConnector::PropertyIndex::ScalingMode); scaling && scaling->hasEnum(DrmConnector::ScalingMode::None)) { - scaling->setEnumLegacy(DrmConnector::ScalingMode::None); + if (m_connector->scalingMode.isValid() && m_connector->scalingMode.hasEnum(DrmConnector::ScalingMode::None)) { + m_connector->scalingMode.setEnumLegacy(DrmConnector::ScalingMode::None); } if (m_pending.crtc != m_current.crtc || m_pending.mode != m_current.mode) { Error err = legacyModeset(); @@ -125,13 +125,13 @@ DrmPipeline::Error DrmPipeline::applyPendingChangesLegacy() qCWarning(KWIN_DRM) << "Setting gamma failed!" << strerror(errno); return errnoToError(); } - if (const auto contentType = m_connector->getProp(DrmConnector::PropertyIndex::ContentType)) { - contentType->setEnumLegacy(m_pending.contentType); + if (m_connector->contentType.isValid()) { + m_connector->contentType.setEnumLegacy(m_pending.contentType); } setCursorLegacy(); moveCursorLegacy(); } - if (!m_connector->getProp(DrmConnector::PropertyIndex::Dpms)->setPropertyLegacy(activePending() ? DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF)) { + if (!m_connector->dpms.setPropertyLegacy(activePending() ? DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF)) { qCWarning(KWIN_DRM) << "Setting legacy dpms failed!" << strerror(errno); return errnoToError(); } diff --git a/src/backends/drm/drm_plane.cpp b/src/backends/drm/drm_plane.cpp index cc1257ad30..f42bd76a60 100644 --- a/src/backends/drm/drm_plane.cpp +++ b/src/backends/drm/drm_plane.cpp @@ -23,78 +23,79 @@ namespace KWin { DrmPlane::DrmPlane(DrmGpu *gpu, uint32_t planeId) - : DrmObject(gpu, planeId, { - PropertyDefinition(QByteArrayLiteral("type"), Requirement::Required, {QByteArrayLiteral("Overlay"), QByteArrayLiteral("Primary"), QByteArrayLiteral("Cursor")}), - PropertyDefinition(QByteArrayLiteral("SRC_X"), Requirement::Required), - PropertyDefinition(QByteArrayLiteral("SRC_Y"), Requirement::Required), - PropertyDefinition(QByteArrayLiteral("SRC_W"), Requirement::Required), - PropertyDefinition(QByteArrayLiteral("SRC_H"), Requirement::Required), - PropertyDefinition(QByteArrayLiteral("CRTC_X"), Requirement::Required), - PropertyDefinition(QByteArrayLiteral("CRTC_Y"), Requirement::Required), - PropertyDefinition(QByteArrayLiteral("CRTC_W"), Requirement::Required), - PropertyDefinition(QByteArrayLiteral("CRTC_H"), Requirement::Required), - PropertyDefinition(QByteArrayLiteral("FB_ID"), Requirement::Required), - PropertyDefinition(QByteArrayLiteral("CRTC_ID"), Requirement::Required), - PropertyDefinition(QByteArrayLiteral("rotation"), Requirement::Optional, {QByteArrayLiteral("rotate-0"), QByteArrayLiteral("rotate-90"), QByteArrayLiteral("rotate-180"), QByteArrayLiteral("rotate-270"), QByteArrayLiteral("reflect-x"), QByteArrayLiteral("reflect-y")}), - PropertyDefinition(QByteArrayLiteral("IN_FORMATS"), Requirement::Optional), - }, - DRM_MODE_OBJECT_PLANE) -{ -} - -bool DrmPlane::init() + : DrmObject(gpu, planeId, DRM_MODE_OBJECT_PLANE) + , type(this, QByteArrayLiteral("type"), { + QByteArrayLiteral("Overlay"), + QByteArrayLiteral("Primary"), + QByteArrayLiteral("Cursor"), + }) + , srcX(this, QByteArrayLiteral("SRC_X")) + , srcY(this, QByteArrayLiteral("SRC_Y")) + , srcW(this, QByteArrayLiteral("SRC_W")) + , srcH(this, QByteArrayLiteral("SRC_H")) + , crtcX(this, QByteArrayLiteral("CRTC_X")) + , crtcY(this, QByteArrayLiteral("CRTC_Y")) + , crtcW(this, QByteArrayLiteral("CRTC_W")) + , crtcH(this, QByteArrayLiteral("CRTC_H")) + , fbId(this, QByteArrayLiteral("FB_ID")) + , crtcId(this, QByteArrayLiteral("CRTC_ID")) + , rotation(this, QByteArrayLiteral("rotation"), { + QByteArrayLiteral("rotate-0"), + QByteArrayLiteral("rotate-90"), + QByteArrayLiteral("rotate-180"), + QByteArrayLiteral("rotate-270"), + QByteArrayLiteral("reflect-x"), + QByteArrayLiteral("reflect-y"), + }) + , inFormats(this, QByteArrayLiteral("IN_FORMATS")) +{ +} + +bool DrmPlane::updateProperties() { DrmUniquePtr p(drmModeGetPlane(gpu()->fd(), id())); - if (!p) { qCWarning(KWIN_DRM) << "Failed to get kernel plane" << id(); return false; } + DrmPropertyList props = queryProperties(); + type.update(props); + srcX.update(props); + srcY.update(props); + srcW.update(props); + srcH.update(props); + crtcX.update(props); + crtcY.update(props); + crtcW.update(props); + crtcH.update(props); + fbId.update(props); + crtcId.update(props); + rotation.update(props); + inFormats.update(props); + + if (!type.isValid() || !srcX.isValid() || !srcY.isValid() || !srcW.isValid() || !srcH.isValid() + || !crtcX.isValid() || !crtcY.isValid() || !crtcW.isValid() || !crtcH.isValid() || !fbId.isValid()) { + return false; + } m_possibleCrtcs = p->possible_crtcs; - bool success = updateProperties(); - if (success) { - if (const auto prop = getProp(PropertyIndex::Rotation)) { - m_supportedTransformations = Transformations(); - auto checkSupport = [this, prop](Transformation t) { - if (prop->hasEnum(t)) { - m_supportedTransformations |= t; - } - }; - checkSupport(Transformation::Rotate0); - checkSupport(Transformation::Rotate90); - checkSupport(Transformation::Rotate180); - checkSupport(Transformation::Rotate270); - checkSupport(Transformation::ReflectX); - checkSupport(Transformation::ReflectY); - } else { - m_supportedTransformations = Transformation::Rotate0; - } - - // read formats from blob if available and if modifiers are supported, and from the plane object if not - if (const auto formatProp = getProp(PropertyIndex::In_Formats); formatProp && formatProp->immutableBlob() && gpu()->addFB2ModifiersSupported()) { - drmModeFormatModifierIterator iterator{}; - while (drmModeFormatModifierBlobIterNext(formatProp->immutableBlob(), &iterator)) { - m_supportedFormats[iterator.fmt].push_back(iterator.mod); - } - } else { - for (uint32_t i = 0; i < p->count_formats; i++) { - m_supportedFormats.insert(p->formats[i], {DRM_FORMAT_MOD_LINEAR}); - } + // read formats from blob if available and if modifiers are supported, and from the plane object if not + if (inFormats.isValid() && inFormats.immutableBlob() && gpu()->addFB2ModifiersSupported()) { + drmModeFormatModifierIterator iterator{}; + while (drmModeFormatModifierBlobIterNext(inFormats.immutableBlob(), &iterator)) { + m_supportedFormats[iterator.fmt].push_back(iterator.mod); } - if (m_supportedFormats.isEmpty()) { - qCWarning(KWIN_DRM) << "Driver doesn't advertise any formats for this plane. Falling back to XRGB8888 without explicit modifiers"; - m_supportedFormats.insert(DRM_FORMAT_XRGB8888, {}); + } else { + for (uint32_t i = 0; i < p->count_formats; i++) { + m_supportedFormats.insert(p->formats[i], {DRM_FORMAT_MOD_LINEAR}); } } - return success; -} - -DrmPlane::TypeIndex DrmPlane::type() const -{ - const auto &prop = getProp(PropertyIndex::Type); - return prop->enumForValue(prop->current()); + if (m_supportedFormats.isEmpty()) { + qCWarning(KWIN_DRM) << "Driver doesn't advertise any formats for this plane. Falling back to XRGB8888 without explicit modifiers"; + m_supportedFormats.insert(DRM_FORMAT_XRGB8888, {}); + } + return true; } void DrmPlane::setNext(const std::shared_ptr &b) @@ -111,15 +112,15 @@ void DrmPlane::flipBuffer() void DrmPlane::set(DrmAtomicCommit *commit, const QPoint &srcPos, const QSize &srcSize, const QRect &dst) { // Src* are in 16.16 fixed point format - commit->addProperty(getProp(PropertyIndex::SrcX), srcPos.x() << 16); - commit->addProperty(getProp(PropertyIndex::SrcX), srcPos.x() << 16); - commit->addProperty(getProp(PropertyIndex::SrcY), srcPos.y() << 16); - commit->addProperty(getProp(PropertyIndex::SrcW), srcSize.width() << 16); - commit->addProperty(getProp(PropertyIndex::SrcH), srcSize.height() << 16); - commit->addProperty(getProp(PropertyIndex::CrtcX), dst.x()); - commit->addProperty(getProp(PropertyIndex::CrtcY), dst.y()); - commit->addProperty(getProp(PropertyIndex::CrtcW), dst.width()); - commit->addProperty(getProp(PropertyIndex::CrtcH), dst.height()); + commit->addProperty(srcX, srcPos.x() << 16); + commit->addProperty(srcX, srcPos.x() << 16); + commit->addProperty(srcY, srcPos.y() << 16); + commit->addProperty(srcW, srcSize.width() << 16); + commit->addProperty(srcH, srcSize.height() << 16); + commit->addProperty(crtcX, dst.x()); + commit->addProperty(crtcY, dst.y()); + commit->addProperty(crtcW, dst.width()); + commit->addProperty(crtcH, dst.height()); } bool DrmPlane::isCrtcSupported(int pipeIndex) const @@ -147,15 +148,10 @@ void DrmPlane::setCurrent(const std::shared_ptr &b) m_current = b; } -DrmPlane::Transformations DrmPlane::supportedTransformations() const -{ - return m_supportedTransformations; -} - void DrmPlane::disable(DrmAtomicCommit *commit) { - commit->addProperty(getProp(PropertyIndex::CrtcId), 0); - commit->addProperty(getProp(PropertyIndex::FbId), 0); + commit->addProperty(crtcId, 0); + commit->addProperty(fbId, 0); m_next = nullptr; } diff --git a/src/backends/drm/drm_plane.h b/src/backends/drm/drm_plane.h index 50f370b188..6943191c39 100644 --- a/src/backends/drm/drm_plane.h +++ b/src/backends/drm/drm_plane.h @@ -29,46 +29,8 @@ class DrmPlane : public DrmObject public: DrmPlane(DrmGpu *gpu, uint32_t planeId); - enum class PropertyIndex : uint32_t { - Type = 0, - SrcX, - SrcY, - SrcW, - SrcH, - CrtcX, - CrtcY, - CrtcW, - CrtcH, - FbId, - CrtcId, - Rotation, - In_Formats, - Count - }; - Q_ENUM(PropertyIndex) - - enum class TypeIndex : uint32_t { - Overlay = 0, - Primary, - Cursor, - Count - }; - Q_ENUM(TypeIndex) - - enum class Transformation : uint32_t { - Rotate0 = 1 << 0, - Rotate90 = 1 << 1, - Rotate180 = 1 << 2, - Rotate270 = 1 << 3, - ReflectX = 1 << 4, - ReflectY = 1 << 5 - }; - Q_ENUM(Transformation) - Q_DECLARE_FLAGS(Transformations, Transformation) - - bool init() override; + bool updateProperties() override; void disable(DrmAtomicCommit *commit) override; - TypeIndex type() const; bool isCrtcSupported(int pipeIndex) const; QMap> formats() const; @@ -81,11 +43,39 @@ public: void set(DrmAtomicCommit *commit, const QPoint &srcPos, const QSize &srcSize, const QRect &dst); - Transformations supportedTransformations() const; - void releaseBuffers(); - static int32_t transformationToDegrees(DrmPlane::Transformations transformation); + enum class TypeIndex : uint64_t { + Overlay = 0, + Primary = 1, + Cursor = 2 + }; + enum class Transformation : uint32_t { + Rotate0 = 1 << 0, + Rotate90 = 1 << 1, + Rotate180 = 1 << 2, + Rotate270 = 1 << 3, + ReflectX = 1 << 4, + ReflectY = 1 << 5 + }; + Q_ENUM(Transformation) + Q_DECLARE_FLAGS(Transformations, Transformation) + + DrmEnumProperty type; + DrmProperty srcX; + DrmProperty srcY; + DrmProperty srcW; + DrmProperty srcH; + DrmProperty crtcX; + DrmProperty crtcY; + DrmProperty crtcW; + DrmProperty crtcH; + DrmProperty fbId; + DrmProperty crtcId; + DrmEnumProperty rotation; + DrmProperty inFormats; + + static int32_t transformationToDegrees(Transformations transformation); private: std::shared_ptr m_current; @@ -93,7 +83,6 @@ private: QMap> m_supportedFormats; uint32_t m_possibleCrtcs; - Transformations m_supportedTransformations = Transformation::Rotate0; }; } diff --git a/src/backends/drm/drm_property.cpp b/src/backends/drm/drm_property.cpp index 7b187a8de2..f9d7539964 100644 --- a/src/backends/drm/drm_property.cpp +++ b/src/backends/drm/drm_property.cpp @@ -17,25 +17,11 @@ namespace KWin { -DrmProperty::DrmProperty(DrmObject *obj, drmModePropertyRes *prop, uint64_t val, const QVector &enumNames) - : m_propId(prop->prop_id) - , m_propName(prop->name) - , m_current(val) - , m_immutable(prop->flags & DRM_MODE_PROP_IMMUTABLE) - , m_isBlob(prop->flags & DRM_MODE_PROP_BLOB) - , m_isBitmask(prop->flags & DRM_MODE_PROP_BITMASK) - , m_obj(obj) +DrmProperty::DrmProperty(DrmObject *obj, const QByteArray &name, const QVector &enumNames) + : m_obj(obj) + , m_propName(name) + , m_enumNames(enumNames) { - if (!enumNames.isEmpty()) { - m_enumNames = enumNames; - initEnumMap(prop); - } - if (prop->flags & DRM_MODE_PROP_RANGE) { - Q_ASSERT(prop->count_values > 1); - m_minValue = prop->values[0]; - m_maxValue = prop->values[1]; - } - updateBlob(); } bool DrmProperty::setPropertyLegacy(uint64_t value) @@ -50,32 +36,59 @@ bool DrmProperty::setPropertyLegacy(uint64_t value) } } -void DrmProperty::initEnumMap(drmModePropertyRes *prop) +void DrmProperty::update(DrmPropertyList &propertyList) { - for (int i = 0; i < prop->count_enums; i++) { - struct drm_mode_property_enum *en = &prop->enums[i]; - int j = m_enumNames.indexOf(QByteArray(en->name)); - if (j >= 0) { - if (m_isBitmask) { - m_enumToPropertyMap[1 << j] = 1 << en->value; - m_propertyToEnumMap[1 << en->value] = 1 << j; + if (const auto opt = propertyList.takeProperty(m_propName)) { + const auto &[prop, value] = *opt; + m_propId = prop->prop_id; + m_current = value; + m_immutable = prop->flags & DRM_MODE_PROP_IMMUTABLE; + m_isBlob = prop->flags & DRM_MODE_PROP_BLOB; + m_isBitmask = prop->flags & DRM_MODE_PROP_BITMASK; + if (prop->flags & DRM_MODE_PROP_RANGE) { + Q_ASSERT(prop->count_values > 1); + m_minValue = prop->values[0]; + m_maxValue = prop->values[1]; + } + m_enumToPropertyMap.clear(); + m_propertyToEnumMap.clear(); + // bitmasks need translation too, not just enums + if (prop->flags & (DRM_MODE_PROP_ENUM | DRM_MODE_PROP_BITMASK)) { + for (int i = 0; i < prop->count_enums; i++) { + struct drm_mode_property_enum *en = &prop->enums[i]; + int j = m_enumNames.indexOf(QByteArray(en->name)); + if (j >= 0) { + if (m_isBitmask) { + m_enumToPropertyMap[1 << j] = 1 << en->value; + m_propertyToEnumMap[1 << en->value] = 1 << j; + } else { + m_enumToPropertyMap[j] = en->value; + m_propertyToEnumMap[en->value] = j; + } + } else { + qCWarning(KWIN_DRM, "%s has unrecognized enum '%s'", qPrintable(m_propName), en->name); + } + } + } + if (m_immutable && m_isBlob) { + if (m_current != 0) { + m_immutableBlob.reset(drmModeGetPropertyBlob(m_obj->gpu()->fd(), m_current)); + if (m_immutableBlob && (!m_immutableBlob->data || !m_immutableBlob->length)) { + m_immutableBlob.reset(); + } } else { - m_enumToPropertyMap[j] = en->value; - m_propertyToEnumMap[en->value] = j; + m_immutableBlob.reset(); } - } else { - qCWarning(KWIN_DRM, "%s has unrecognized enum '%s'", qPrintable(m_propName), en->name); } + } else { + m_propId = 0; + m_immutableBlob.reset(); + m_enumToPropertyMap.clear(); + m_propertyToEnumMap.clear(); } } -void DrmProperty::setCurrent(uint64_t value) -{ - m_current = value; - updateBlob(); -} - -uint64_t DrmProperty::current() const +uint64_t DrmProperty::value() const { return m_current; } @@ -105,16 +118,6 @@ bool DrmProperty::isBitmask() const return m_isBitmask; } -bool DrmProperty::isLegacy() const -{ - return m_legacy; -} - -void DrmProperty::setLegacy() -{ - m_legacy = true; -} - uint64_t DrmProperty::minValue() const { return m_minValue; @@ -125,27 +128,18 @@ uint64_t DrmProperty::maxValue() const return m_maxValue; } -void DrmProperty::updateBlob() -{ - if (m_immutable && m_isBlob) { - if (m_current != 0) { - m_immutableBlob.reset(drmModeGetPropertyBlob(m_obj->gpu()->fd(), m_current)); - if (m_immutableBlob && (!m_immutableBlob->data || !m_immutableBlob->length)) { - m_immutableBlob.reset(); - } - } else { - m_immutableBlob.reset(); - } - } -} - drmModePropertyBlobRes *DrmProperty::immutableBlob() const { return m_immutableBlob.get(); } -const DrmObject *DrmProperty::drmObject() const +DrmObject *DrmProperty::drmObject() const { return m_obj; } + +bool DrmProperty::isValid() const +{ + return m_propId != 0; +} } diff --git a/src/backends/drm/drm_property.h b/src/backends/drm/drm_property.h index 04c208ebf6..ae874cc4bc 100644 --- a/src/backends/drm/drm_property.h +++ b/src/backends/drm/drm_property.h @@ -22,21 +22,79 @@ namespace KWin { class DrmObject; +class DrmPropertyList; class DrmProperty { public: - DrmProperty(DrmObject *obj, drmModePropertyRes *prop, uint64_t val, const QVector &enumNames); + DrmProperty(DrmObject *obj, const QByteArray &name, const QVector &enumNames = {}); + const QByteArray &name() const; + DrmObject *drmObject() const; + + uint32_t propId() const; + bool isImmutable() const; + bool isBitmask() const; bool hasAllEnums() const; + uint64_t value() const; + drmModePropertyBlobRes *immutableBlob() const; + uint64_t minValue() const; + uint64_t maxValue() const; + bool isValid() const; + + void update(DrmPropertyList &propertyList); + bool setPropertyLegacy(uint64_t value); + +protected: + DrmObject *const m_obj; + const QByteArray m_propName; + const QVector m_enumNames; + + uint32_t m_propId = 0; + // the last known value from the kernel + uint64_t m_current = 0; + DrmUniquePtr m_immutableBlob; + + uint64_t m_minValue = -1; + uint64_t m_maxValue = -1; + + QMap m_enumToPropertyMap; + QMap m_propertyToEnumMap; + bool m_immutable = false; + bool m_isBlob = false; + bool m_isBitmask = false; +}; + +template +class DrmEnumProperty : public DrmProperty +{ +public: + DrmEnumProperty(DrmObject *obj, const QByteArray &name, const QVector &enumNames) + : DrmProperty(obj, name, enumNames) + { + } + + Enum enumValue() const + { + return enumForValue(value()); + } - template bool hasEnum(Enum value) const { - return m_enumToPropertyMap.contains(static_cast(value)); + const uint64_t integerValue = static_cast(value); + if (m_isBitmask) { + for (uint64_t mask = 1; integerValue >= mask && mask != 0; mask <<= 1) { + if ((integerValue & mask) && !m_enumToPropertyMap.contains(mask)) { + return false; + } + } + return true; + } else { + return m_enumToPropertyMap.contains(integerValue); + } } - template - T enumForValue(uint64_t value) const + + Enum enumForValue(uint64_t value) const { if (m_isBitmask) { uint64_t ret = 0; @@ -45,12 +103,13 @@ public: ret |= m_propertyToEnumMap[mask]; } } - return static_cast(ret); + return static_cast(ret); } else { - return static_cast(m_propertyToEnumMap[value]); + return static_cast(m_propertyToEnumMap[value]); } } - uint64_t valueForEnum(auto enumValue) + + uint64_t valueForEnum(Enum enumValue) const { const uint64_t integer = static_cast(enumValue); if (m_isBitmask) { @@ -66,57 +125,13 @@ public: } } - uint32_t propId() const; - const QByteArray &name() const; - bool isImmutable() const; - bool isBitmask() const; - bool isLegacy() const; - /** - * Makes this property be ignored by DrmObject::atomicPopulate - */ - void setLegacy(); - - void setCurrent(uint64_t value); - uint64_t current() const; - drmModePropertyBlobRes *immutableBlob() const; - - uint64_t minValue() const; - uint64_t maxValue() const; - - bool setPropertyLegacy(uint64_t value); - template - bool setEnumLegacy(T value) + bool setEnumLegacy(Enum value) { - if (hasEnum(static_cast(value))) { - return setPropertyLegacy(m_enumToPropertyMap[static_cast(value)]); + if (hasEnum(value)) { + return setPropertyLegacy(valueForEnum(value)); + } else { + return false; } - return false; } - - const DrmObject *drmObject() const; - -private: - void initEnumMap(drmModePropertyRes *prop); - void updateBlob(); - - uint32_t m_propId = 0; - QByteArray m_propName; - - // the last known value from the kernel - uint64_t m_current = 0; - DrmUniquePtr m_immutableBlob; - - uint64_t m_minValue = -1; - uint64_t m_maxValue = -1; - - QMap m_enumToPropertyMap; - QMap m_propertyToEnumMap; - QVector m_enumNames; - const bool m_immutable; - const bool m_isBlob; - const bool m_isBitmask; - bool m_legacy = false; - const DrmObject *m_obj; }; - }