From 02bb276ebfa076ebef1afa875b3737ebf010d8af Mon Sep 17 00:00:00 2001 From: Vlad Zahorodnii Date: Tue, 28 Sep 2021 11:30:57 +0300 Subject: [PATCH] platforms/drm: Move ownership of mode blob to connector mode The main motivation behind this change is to move management of drm blobs out of property wrappers in specialized wrappers to simplify state management with blobs. Connector mode blobs are created on demand. --- src/backends/drm/drm_object_connector.cpp | 118 ++++++++++++++-------- src/backends/drm/drm_object_connector.h | 35 +++++-- src/backends/drm/drm_object_crtc.cpp | 2 +- src/backends/drm/drm_output.cpp | 20 ++-- src/backends/drm/drm_pipeline.cpp | 14 +-- 5 files changed, 123 insertions(+), 66 deletions(-) diff --git a/src/backends/drm/drm_object_connector.cpp b/src/backends/drm/drm_object_connector.cpp index 959942cb09..1e7de2bc11 100644 --- a/src/backends/drm/drm_object_connector.cpp +++ b/src/backends/drm/drm_object_connector.cpp @@ -22,6 +22,64 @@ namespace KWin { +static quint64 refreshRateForMode(_drmModeModeInfo *m) +{ + // Calculate higher precision (mHz) refresh rate + // logic based on Weston, see compositor-drm.c + quint64 refreshRate = (m->clock * 1000000LL / m->htotal + m->vtotal / 2) / m->vtotal; + if (m->flags & DRM_MODE_FLAG_INTERLACE) { + refreshRate *= 2; + } + if (m->flags & DRM_MODE_FLAG_DBLSCAN) { + refreshRate /= 2; + } + if (m->vscan > 1) { + refreshRate /= m->vscan; + } + return refreshRate; +} + +DrmConnectorMode::DrmConnectorMode(DrmConnector *connector, drmModeModeInfo nativeMode) + : m_connector(connector) + , m_nativeMode(nativeMode) + , m_size(nativeMode.hdisplay, nativeMode.vdisplay) + , m_refreshRate(refreshRateForMode(&nativeMode)) +{ +} + +DrmConnectorMode::~DrmConnectorMode() +{ + if (m_blobId) { + drmModeDestroyPropertyBlob(m_connector->gpu()->fd(), m_blobId); + m_blobId = 0; + } +} + +drmModeModeInfo *DrmConnectorMode::nativeMode() +{ + return &m_nativeMode; +} + +QSize DrmConnectorMode::size() const +{ + return m_size; +} + +uint32_t DrmConnectorMode::refreshRate() const +{ + return m_refreshRate; +} + +uint32_t DrmConnectorMode::blobId() +{ + if (!m_blobId) { + if (drmModeCreatePropertyBlob(m_connector->gpu()->fd(), &m_nativeMode, sizeof(m_nativeMode), &m_blobId) != 0) { + qCWarning(KWIN_DRM) << "Failed to create connector mode blob:" << strerror(errno); + } + } + return m_blobId; +} + DrmConnector::DrmConnector(DrmGpu *gpu, uint32_t connectorId) : DrmObject(gpu, connectorId, { PropertyDefinition(QByteArrayLiteral("CRTC_ID"), Requirement::Required), @@ -55,25 +113,9 @@ DrmConnector::DrmConnector(DrmGpu *gpu, uint32_t connectorId) } } -DrmConnector::~DrmConnector() = default; - -namespace { -quint64 refreshRateForMode(_drmModeModeInfo *m) +DrmConnector::~DrmConnector() { - // Calculate higher precision (mHz) refresh rate - // logic based on Weston, see compositor-drm.c - quint64 refreshRate = (m->clock * 1000000LL / m->htotal + m->vtotal / 2) / m->vtotal; - if (m->flags & DRM_MODE_FLAG_INTERLACE) { - refreshRate *= 2; - } - if (m->flags & DRM_MODE_FLAG_DBLSCAN) { - refreshRate /= 2; - } - if (m->vscan > 1) { - refreshRate /= m->vscan; - } - return refreshRate; -} + qDeleteAll(m_modes); } bool DrmConnector::init() @@ -137,7 +179,7 @@ QSize DrmConnector::physicalSize() const return m_physicalSize; } -const DrmConnector::Mode &DrmConnector::currentMode() const +DrmConnectorMode *DrmConnector::currentMode() const { return m_modes[m_modeIndex]; } @@ -147,7 +189,7 @@ int DrmConnector::currentModeIndex() const return m_modeIndex; } -const QVector &DrmConnector::modes() +QVector DrmConnector::modes() { return m_modes; } @@ -157,26 +199,26 @@ void DrmConnector::setModeIndex(int index) m_modeIndex = index; } -static bool checkIfEqual(drmModeModeInfo one, drmModeModeInfo two) +static bool checkIfEqual(const drmModeModeInfo *one, const drmModeModeInfo *two) { - return one.clock == two.clock - && one.hdisplay == two.hdisplay - && one.hsync_start == two.hsync_start - && one.hsync_end == two.hsync_end - && one.htotal == two.htotal - && one.hskew == two.hskew - && one.vdisplay == two.vdisplay - && one.vsync_start == two.vsync_start - && one.vsync_end == two.vsync_end - && one.vtotal == two.vtotal - && one.vscan == two.vscan - && one.vrefresh == two.vrefresh; + return one->clock == two->clock + && one->hdisplay == two->hdisplay + && one->hsync_start == two->hsync_start + && one->hsync_end == two->hsync_end + && one->htotal == two->htotal + && one->hskew == two->hskew + && one->vdisplay == two->vdisplay + && one->vsync_start == two->vsync_start + && one->vsync_end == two->vsync_end + && one->vtotal == two->vtotal + && one->vscan == two->vscan + && one->vrefresh == two->vrefresh; } void DrmConnector::findCurrentMode(drmModeModeInfo currentMode) { for (int i = 0; i < m_modes.count(); i++) { - if (checkIfEqual(m_modes[i].mode, currentMode)) { + if (checkIfEqual(m_modes[i]->nativeMode(), ¤tMode)) { m_modeIndex = i; return; } @@ -259,16 +301,12 @@ bool DrmConnector::needsModeset() const void DrmConnector::updateModes() { + qDeleteAll(m_modes); m_modes.clear(); // reload modes for (int i = 0; i < m_conn->count_modes; i++) { - auto mode = m_conn->modes[i]; - Mode m; - m.mode = mode; - m.size = QSize(mode.hdisplay, mode.vdisplay); - m.refreshRate = refreshRateForMode(&mode); - m_modes << m; + m_modes.append(new DrmConnectorMode(this, m_conn->modes[i])); } } diff --git a/src/backends/drm/drm_object_connector.h b/src/backends/drm/drm_object_connector.h index 873ed46e0d..75805f6a36 100644 --- a/src/backends/drm/drm_object_connector.h +++ b/src/backends/drm/drm_object_connector.h @@ -23,6 +23,30 @@ namespace KWin { class DrmPipeline; +class DrmConnector; + +/** + * The DrmConnectorMode class represents a native mode and the associated blob. + */ +class DrmConnectorMode +{ +public: + DrmConnectorMode(DrmConnector *connector, drmModeModeInfo nativeMode); + ~DrmConnectorMode(); + + uint32_t blobId(); + + drmModeModeInfo *nativeMode(); + QSize size() const; + uint32_t refreshRate() const; + +private: + DrmConnector *m_connector; + drmModeModeInfo m_nativeMode; + QSize m_size; + uint32_t m_refreshRate; + uint32_t m_blobId = 0; +}; class DrmConnector : public DrmObject { @@ -66,14 +90,9 @@ public: QString modelName() const; QSize physicalSize() const; - struct Mode { - drmModeModeInfo mode; - QSize size; - uint32_t refreshRate; - }; - const Mode ¤tMode() const; + DrmConnectorMode *currentMode() const; int currentModeIndex() const; - const QVector &modes(); + QVector modes(); void setModeIndex(int index); void findCurrentMode(drmModeModeInfo currentMode); void updateModes(); @@ -92,7 +111,7 @@ private: QVector m_encoders; Edid m_edid; QSize m_physicalSize = QSize(-1, -1); - QVector m_modes; + QVector m_modes; int m_modeIndex = 0; friend QDebug& operator<<(QDebug& s, const KWin::DrmConnector *obj); diff --git a/src/backends/drm/drm_object_crtc.cpp b/src/backends/drm/drm_object_crtc.cpp index 79da043223..2e5dd54ca0 100644 --- a/src/backends/drm/drm_object_crtc.cpp +++ b/src/backends/drm/drm_object_crtc.cpp @@ -156,7 +156,7 @@ DrmPlane *DrmCrtc::cursorPlane() const void DrmCrtc::disable() { setPending(PropertyIndex::Active, 0); - setPendingBlob(PropertyIndex::ModeId, nullptr, sizeof(drmModeModeInfo)); + setPending(PropertyIndex::ModeId, 0); } } diff --git a/src/backends/drm/drm_output.cpp b/src/backends/drm/drm_output.cpp index 76bbb09631..101d5f5e01 100644 --- a/src/backends/drm/drm_output.cpp +++ b/src/backends/drm/drm_output.cpp @@ -42,7 +42,7 @@ DrmOutput::DrmOutput(DrmPipeline *pipeline) { m_pipeline->setOutput(this); auto conn = m_pipeline->connector(); - m_renderLoop->setRefreshRate(conn->currentMode().refreshRate); + m_renderLoop->setRefreshRate(conn->currentMode()->refreshRate()); setSubPixelInternal(conn->subpixel()); setInternal(conn->isInternal()); setCapabilityInternal(DrmOutput::Capability::Dpms); @@ -192,7 +192,7 @@ QVector DrmOutput::getModes() const bool modeFound = false; QVector modes; auto conn = m_pipeline->connector(); - auto modelist = conn->modes(); + QVector modelist = conn->modes(); modes.reserve(modelist.count()); for (int i = 0; i < modelist.count(); ++i) { @@ -201,13 +201,13 @@ QVector DrmOutput::getModes() const mode.flags |= ModeFlag::Current; modeFound = true; } - if (modelist[i].mode.type & DRM_MODE_TYPE_PREFERRED) { + if (modelist[i]->nativeMode()->type & DRM_MODE_TYPE_PREFERRED) { mode.flags |= ModeFlag::Preferred; } mode.id = i; - mode.size = modelist[i].size; - mode.refreshRate = modelist[i].refreshRate; + mode.size = modelist[i]->size(); + mode.refreshRate = modelist[i]->refreshRate(); modes << mode; } if (!modeFound) { @@ -353,8 +353,8 @@ void DrmOutput::updateModes() if (DrmPipeline::commitPipelines({m_pipeline}, DrmPipeline::CommitMode::Test)) { m_pipeline->applyPendingChanges(); auto mode = m_pipeline->connector()->currentMode(); - setCurrentModeInternal(mode.size, mode.refreshRate); - m_renderLoop->setRefreshRate(mode.refreshRate); + setCurrentModeInternal(mode->size(), mode->refreshRate()); + m_renderLoop->setRefreshRate(mode->refreshRate()); } else { qCWarning(KWIN_DRM) << "Setting changed mode failed!"; m_pipeline->revertPendingChanges(); @@ -440,7 +440,7 @@ bool DrmOutput::queueChanges(const WaylandOutputConfig &config) auto modelist = m_connector->modes(); int index = -1; for (int i = 0; i < modelist.size(); i++) { - if (modelist[i].size == props->modeSize && modelist[i].refreshRate == props->refreshRate) { + if (modelist[i]->size() == props->modeSize && modelist[i]->refreshRate() == props->refreshRate) { index = i; break; } @@ -471,8 +471,8 @@ void DrmOutput::applyQueuedChanges(const WaylandOutputConfig &config) m_connector->setModeIndex(m_pipeline->pending.modeIndex); auto mode = m_connector->currentMode(); - setCurrentModeInternal(mode.size, mode.refreshRate); - m_renderLoop->setRefreshRate(mode.refreshRate); + setCurrentModeInternal(mode->size(), mode->refreshRate()); + m_renderLoop->setRefreshRate(mode->refreshRate()); setOverscanInternal(m_pipeline->pending.overscan); setRgbRangeInternal(m_pipeline->pending.rgbRange); setVrrPolicy(props->vrrPolicy); diff --git a/src/backends/drm/drm_pipeline.cpp b/src/backends/drm/drm_pipeline.cpp index 4119fac249..9711b044c4 100644 --- a/src/backends/drm/drm_pipeline.cpp +++ b/src/backends/drm/drm_pipeline.cpp @@ -259,7 +259,7 @@ bool DrmPipeline::populateAtomicValues(drmModeAtomicReq *req, uint32_t &flags) flags |= DRM_MODE_PAGE_FLIP_EVENT; } if (pending.crtc) { - auto modeSize = m_connector->modes()[pending.modeIndex].size; + auto modeSize = m_connector->modes()[pending.modeIndex]->size(); pending.crtc->primaryPlane()->set(QPoint(0, 0), m_primaryBuffer ? m_primaryBuffer->size() : modeSize, QPoint(0, 0), modeSize); pending.crtc->primaryPlane()->setBuffer(activePending() ? m_primaryBuffer.get() : nullptr); pending.crtc->setPending(DrmCrtc::PropertyIndex::VrrEnabled, pending.syncMode == RenderLoopPrivate::SyncMode::Adaptive); @@ -362,11 +362,11 @@ void DrmPipeline::prepareModeset() } pending.crtc->setPending(DrmCrtc::PropertyIndex::Active, activePending()); - pending.crtc->setPendingBlob(DrmCrtc::PropertyIndex::ModeId, activePending() ? &mode.mode : nullptr, sizeof(drmModeModeInfo)); + pending.crtc->setPending(DrmCrtc::PropertyIndex::ModeId, activePending() ? mode->blobId() : 0); pending.crtc->primaryPlane()->setPending(DrmPlane::PropertyIndex::CrtcId, activePending() ? pending.crtc->id() : 0); pending.crtc->primaryPlane()->setTransformation(DrmPlane::Transformation::Rotate0); - pending.crtc->primaryPlane()->set(QPoint(0, 0), sourceSize(), QPoint(0, 0), mode.size); + pending.crtc->primaryPlane()->set(QPoint(0, 0), sourceSize(), QPoint(0, 0), mode->size()); m_formats = pending.crtc->primaryPlane()->formats(); } @@ -418,7 +418,7 @@ bool DrmPipeline::legacyModeset() { auto mode = m_connector->modes()[pending.modeIndex]; uint32_t connId = m_connector->id(); - if (!checkTestBuffer() || drmModeSetCrtc(gpu()->fd(), pending.crtc->id(), m_primaryBuffer->bufferId(), 0, 0, &connId, 1, &mode.mode) != 0) { + if (!checkTestBuffer() || drmModeSetCrtc(gpu()->fd(), pending.crtc->id(), m_primaryBuffer->bufferId(), 0, 0, &connId, 1, mode->nativeMode()) != 0) { qCWarning(KWIN_DRM) << "Modeset failed!" << strerror(errno); pending = m_next; m_primaryBuffer = m_oldTestBuffer; @@ -438,14 +438,14 @@ QSize DrmPipeline::sourceSize() const { auto mode = m_connector->modes()[pending.modeIndex]; if (pending.transformation & (DrmPlane::Transformation::Rotate90 | DrmPlane::Transformation::Rotate270)) { - return mode.size.transposed(); + return mode->size().transposed(); } - return mode.size; + return mode->size(); } bool DrmPipeline::isCursorVisible() const { - return pending.crtc && pending.crtc->isCursorVisible(QRect(QPoint(0, 0), m_connector->currentMode().size)); + return pending.crtc && pending.crtc->isCursorVisible(QRect(QPoint(0, 0), m_connector->currentMode()->size())); } QPoint DrmPipeline::cursorPos() const