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; }; - }