diff --git a/plugins/platforms/drm/drm_backend.h b/plugins/platforms/drm/drm_backend.h --- a/plugins/platforms/drm/drm_backend.h +++ b/plugins/platforms/drm/drm_backend.h @@ -55,6 +55,8 @@ class DrmOutput; class DrmPlane; +class DrmCrtc; +class DrmConnector; class KWIN_EXPORT DrmBackend : public Platform @@ -128,8 +130,6 @@ void updateCursor(); void moveCursor(); void initCursor(); - quint32 findCrtc(drmModeRes *res, drmModeConnector *connector, bool *ok = nullptr); - bool crtcIsUsed(quint32 crtc); void outputDpmsChanged(); void readOutputsConfiguration(); QByteArray generateOutputConfigurationUuid() const; @@ -139,6 +139,11 @@ QScopedPointer m_udevMonitor; int m_fd = -1; int m_drmId = 0; + // all crtcs + QVector m_crtcs; + // all connectors + QVector m_connectors; + // currently active output pipelines (planes + crtc + encoder + connector) QVector m_outputs; DrmBuffer *m_cursor[2]; bool m_atomicModeSetting = false; diff --git a/plugins/platforms/drm/drm_backend.cpp b/plugins/platforms/drm/drm_backend.cpp --- a/plugins/platforms/drm/drm_backend.cpp +++ b/plugins/platforms/drm/drm_backend.cpp @@ -87,8 +87,10 @@ while (m_pageFlipsPending != 0) { QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents); } - qDeleteAll(m_planes); qDeleteAll(m_outputs); + qDeleteAll(m_planes); + qDeleteAll(m_crtcs); + qDeleteAll(m_connectors); delete m_cursor[0]; delete m_cursor[1]; close(m_fd); @@ -168,7 +170,7 @@ for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { DrmOutput *o = *it; o->pageFlipped(); - o->blank(); + o->m_crtc->blank(); o->showCursor(c); o->moveCursor(cp); } @@ -194,7 +196,6 @@ for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { DrmOutput *o = *it; o->hideCursor(); - o->restoreSaved(); } m_active = false; } @@ -286,7 +287,35 @@ } } + ScopedDrmPointer<_drmModeRes, &drmModeFreeResources> resources(drmModeGetResources(m_fd)); + drmModeRes *res = resources.data(); + if (!resources) { + qCWarning(KWIN_DRM) << "drmModeGetResources failed"; + return; + } + + for (int i = 0; i < res->count_connectors; ++i) { + m_connectors << new DrmConnector(res->connectors[i], m_fd); + } + for (int i = 0; i < res->count_crtcs; ++i) { + m_crtcs << new DrmCrtc(res->crtcs[i], m_fd, i); + } + + if (m_atomicModeSetting) { + auto tryInit = [] (DrmObject *o) -> bool { + if (o->init()) { + return false; + } else { + delete o; + return true; + } + }; + std::remove_if(m_connectors.begin(), m_connectors.end(), tryInit); + std::remove_if(m_crtcs.begin(), m_crtcs.end(), tryInit); + } + queryResources(); + if (m_outputs.isEmpty()) { qCWarning(KWIN_DRM) << "No outputs, cannot render, will terminate now"; emit initFailed(); @@ -329,81 +358,29 @@ if (m_fd < 0) { return; } + ScopedDrmPointer<_drmModeRes, &drmModeFreeResources> resources(drmModeGetResources(m_fd)); if (!resources) { qCWarning(KWIN_DRM) << "drmModeGetResources failed"; return; } QVector connectedOutputs; - for (int i = 0; i < resources->count_connectors; ++i) { - const auto id = resources->connectors[i]; - ScopedDrmPointer<_drmModeConnector, &drmModeFreeConnector> connector(drmModeGetConnector(m_fd, id)); - if (!connector) { - continue; - } - if (connector->connection != DRM_MODE_CONNECTED) { - continue; - } - if (connector->count_modes == 0) { - continue; - } - if (DrmOutput *o = findOutput(connector->connector_id)) { - connectedOutputs << o; - continue; - } - bool crtcFound = false; - const quint32 crtcId = findCrtc(resources.data(), connector.data(), &crtcFound); - if (!crtcFound) { - continue; - } - ScopedDrmPointer<_drmModeCrtc, &drmModeFreeCrtc> crtc(drmModeGetCrtc(m_fd, crtcId)); - if (!crtc) { - continue; - } - DrmOutput *drmOutput = new DrmOutput(this); - connect(drmOutput, &DrmOutput::dpmsChanged, this, &DrmBackend::outputDpmsChanged); - drmOutput->m_crtcId = crtcId; - drmOutput->m_connector = connector->connector_id; - - if (m_atomicModeSetting) { - drmOutput->m_crtc = new DrmCrtc(crtcId, m_fd); - if (drmOutput->m_crtc->init()) { - drmOutput->m_crtc->setOutput(drmOutput); - } else { - qCWarning(KWIN_DRM) << "Crtc object failed, skipping output on connector" << connector->connector_id; - delete drmOutput->m_crtc; - delete drmOutput; - continue; - } + QVector pendingConnectors; - drmOutput->m_conn = new DrmConnector(connector->connector_id, m_fd); - if (drmOutput->m_conn->init()) { - drmOutput->m_conn->setOutput(drmOutput); - } else { - qCWarning(KWIN_DRM) << "Connector object failed, skipping output on connector" << connector->connector_id; - delete drmOutput->m_conn; - delete drmOutput; - continue; - } + // split up connected connectors in already or not yet assigned ones + for (DrmConnector *con : m_connectors) { + if (!con->isConnected()) { + continue; } - if (crtc->mode_valid) { - drmOutput->m_mode = crtc->mode; + if (DrmOutput *o = findOutput(con->id())) { + connectedOutputs << o; } else { - drmOutput->m_mode = connector->modes[0]; + pendingConnectors << con; } - qCDebug(KWIN_DRM) << "For new output use mode " << drmOutput->m_mode.name; - - if (!drmOutput->init(connector.data())) { - qCWarning(KWIN_DRM) << "Failed to create output for connector " << connector->connector_id; - delete drmOutput; - continue; - } - qCDebug(KWIN_DRM) << "Found new output with uuid" << drmOutput->uuid(); - connectedOutputs << drmOutput; } - std::sort(connectedOutputs.begin(), connectedOutputs.end(), [] (DrmOutput *a, DrmOutput *b) { return a->m_connector < b->m_connector; }); + // check for outputs which got removed auto it = m_outputs.begin(); while (it != m_outputs.end()) { @@ -416,11 +393,77 @@ emit outputRemoved(removed); delete removed; } - for (auto it = connectedOutputs.constBegin(); it != connectedOutputs.constEnd(); ++it) { - if (!m_outputs.contains(*it)) { - emit outputAdded(*it); + + // now check new connections + for (DrmConnector *con : pendingConnectors) { + ScopedDrmPointer<_drmModeConnector, &drmModeFreeConnector> connector(drmModeGetConnector(m_fd, con->id())); + if (!connector) { + continue; + } + if (connector->count_modes == 0) { + continue; + } + bool outputDone = false; + + for (auto encId : con->encoders()) { + ScopedDrmPointer<_drmModeEncoder, &drmModeFreeEncoder> encoder(drmModeGetEncoder(m_fd, encId)); + if (!encoder) { + continue; + } + for (DrmCrtc *crtc : m_crtcs) { + if (!(encoder->possible_crtcs & (1 << crtc->resIndex()))) { + continue; + } + + // check if crtc isn't used yet -- currently we don't allow multiple outputs on one crtc (cloned mode) + auto it = std::find_if(connectedOutputs.constBegin(), connectedOutputs.constEnd(), + [crtc] (DrmOutput *o) { + return o->m_crtc == crtc; + } + ); + if (it != connectedOutputs.constEnd()) { + continue; + } + + // we found a suitable encoder+crtc + // TODO: we could avoid these lib drm calls if we store all struct data in DrmCrtc and DrmConnector in the beginning + ScopedDrmPointer<_drmModeCrtc, &drmModeFreeCrtc> modeCrtc(drmModeGetCrtc(m_fd, crtc->id())); + if (!modeCrtc) { + continue; + } + + DrmOutput *output = new DrmOutput(this); + con->setOutput(output); + output->m_conn = con; + crtc->setOutput(output); + output->m_crtc = crtc; + connect(output, &DrmOutput::dpmsChanged, this, &DrmBackend::outputDpmsChanged); + + if (modeCrtc->mode_valid) { + output->m_mode = modeCrtc->mode; + } else { + output->m_mode = connector->modes[0]; + } + qCDebug(KWIN_DRM) << "For new output use mode " << output->m_mode.name; + + if (!output->init(connector.data())) { + qCWarning(KWIN_DRM) << "Failed to create output for connector " << con->id(); + delete output; + continue; + } + qCDebug(KWIN_DRM) << "Found new output with uuid" << output->uuid(); + + connectedOutputs << output; + emit outputAdded(output); + outputDone = true; + break; + } + if (outputDone) { + break; + } } } + std::sort(connectedOutputs.begin(), connectedOutputs.end(), [] (DrmOutput *a, DrmOutput *b) { return a->m_conn->id() < b->m_conn->id(); }); m_outputs = connectedOutputs; readOutputsConfiguration(); if (!m_outputs.isEmpty()) { @@ -481,7 +524,7 @@ DrmOutput *DrmBackend::findOutput(quint32 connector) { auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(), [connector] (DrmOutput *o) { - return o->m_connector == connector; + return o->m_conn->id() == connector; }); if (it != m_outputs.constEnd()) { return *it; @@ -500,51 +543,6 @@ return nullptr; } -quint32 DrmBackend::findCrtc(drmModeRes *res, drmModeConnector *connector, bool *ok) -{ - if (ok) { - *ok = false; - } - ScopedDrmPointer<_drmModeEncoder, &drmModeFreeEncoder> encoder(drmModeGetEncoder(m_fd, connector->encoder_id)); - if (encoder) { - if (!crtcIsUsed(encoder->crtc_id)) { - if (ok) { - *ok = true; - } - return encoder->crtc_id; - } - } - // let's iterate over all encoders to find a suitable crtc - for (int i = 0; i < connector->count_encoders; ++i) { - ScopedDrmPointer<_drmModeEncoder, &drmModeFreeEncoder> encoder(drmModeGetEncoder(m_fd, connector->encoders[i])); - if (!encoder) { - continue; - } - for (int j = 0; j < res->count_crtcs; ++j) { - if (!(encoder->possible_crtcs & (1 << j))) { - continue; - } - if (!crtcIsUsed(res->crtcs[j])) { - if (ok) { - *ok = true; - } - return res->crtcs[j]; - } - } - } - return 0; -} - -bool DrmBackend::crtcIsUsed(quint32 crtc) -{ - auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(), - [crtc] (DrmOutput *o) { - return o->m_crtcId == crtc; - } - ); - return it != m_outputs.constEnd(); -} - void DrmBackend::present(DrmBuffer *buffer, DrmOutput *output) { if (output->present(buffer)) { diff --git a/plugins/platforms/drm/drm_buffer.h b/plugins/platforms/drm/drm_buffer.h --- a/plugins/platforms/drm/drm_buffer.h +++ b/plugins/platforms/drm/drm_buffer.h @@ -61,7 +61,6 @@ bool deleteAfterPageFlip() const { return m_deleteAfterPageFlip; } - void releaseGbm(); private: diff --git a/plugins/platforms/drm/drm_buffer.cpp b/plugins/platforms/drm/drm_buffer.cpp --- a/plugins/platforms/drm/drm_buffer.cpp +++ b/plugins/platforms/drm/drm_buffer.cpp @@ -93,14 +93,14 @@ DrmBuffer::~DrmBuffer() { + if (m_bufferId) { + drmModeRmFB(m_backend->fd(), m_bufferId); + } m_backend->bufferDestroyed(this); delete m_image; if (m_memory) { munmap(m_memory, m_bufferSize); } - if (m_bufferId) { - drmModeRmFB(m_backend->fd(), m_bufferId); - } if (m_handle) { drm_mode_destroy_dumb destroyArgs; destroyArgs.handle = m_handle; diff --git a/plugins/platforms/drm/drm_object_connector.h b/plugins/platforms/drm/drm_object_connector.h --- a/plugins/platforms/drm/drm_object_connector.h +++ b/plugins/platforms/drm/drm_object_connector.h @@ -38,8 +38,17 @@ CrtcId = 0, Count }; + + QVector encoders() { + return m_encoders; + } bool initProps(); + bool isConnected(); + + +private: + QVector m_encoders; }; } diff --git a/plugins/platforms/drm/drm_object_connector.cpp b/plugins/platforms/drm/drm_object_connector.cpp --- a/plugins/platforms/drm/drm_object_connector.cpp +++ b/plugins/platforms/drm/drm_object_connector.cpp @@ -18,15 +18,22 @@ along with this program. If not, see . *********************************************************************/ #include "drm_object_connector.h" +#include "drm_pointer.h" #include "logging.h" namespace KWin { DrmConnector::DrmConnector(uint32_t connector_id, int fd) : DrmObject(connector_id, fd) { - + ScopedDrmPointer<_drmModeConnector, &drmModeFreeConnector> con(drmModeGetConnector(fd, connector_id)); + if (!con) { + return; + } + for (int i = 0; i < con->count_encoders; ++i) { + m_encoders << con->encoders[i]; + } } DrmConnector::~DrmConnector() = default; @@ -61,4 +68,13 @@ return true; } +bool DrmConnector::isConnected() +{ + ScopedDrmPointer<_drmModeConnector, &drmModeFreeConnector> con(drmModeGetConnector(m_fd, m_id)); + if (!con) { + return false; + } + return con->connection == DRM_MODE_CONNECTED; +} + } diff --git a/plugins/platforms/drm/drm_object_crtc.h b/plugins/platforms/drm/drm_object_crtc.h --- a/plugins/platforms/drm/drm_object_crtc.h +++ b/plugins/platforms/drm/drm_object_crtc.h @@ -25,12 +25,13 @@ namespace KWin { +class DrmBackend; class DrmBuffer; class DrmCrtc : public DrmObject { public: - DrmCrtc(uint32_t crtc_id, int fd); + DrmCrtc(uint32_t crtc_id, int fd, int resIndex); virtual ~DrmCrtc(); @@ -43,6 +44,30 @@ }; bool initProps(); + + int resIndex() const { + return m_resIndex; + } + + DrmBuffer *current() { + return m_currentBuffer; + } + DrmBuffer *next() { + return m_nextBuffer; + } + void setNext(DrmBuffer *buffer) { + m_nextBuffer = buffer; + } + + void flipBuffer(); + bool blank(); + +private: + DrmBackend *m_backend; + int m_resIndex; + + DrmBuffer *m_currentBuffer = nullptr; + DrmBuffer *m_nextBuffer = nullptr; }; } diff --git a/plugins/platforms/drm/drm_object_crtc.cpp b/plugins/platforms/drm/drm_object_crtc.cpp --- a/plugins/platforms/drm/drm_object_crtc.cpp +++ b/plugins/platforms/drm/drm_object_crtc.cpp @@ -18,21 +18,27 @@ along with this program. If not, see . *********************************************************************/ #include "drm_object_crtc.h" +#include "drm_backend.h" +#include "drm_output.h" +#include "drm_buffer.h" #include "logging.h" namespace KWin { -DrmCrtc::DrmCrtc(uint32_t crtc_id, int fd) - : DrmObject(crtc_id, fd) +DrmCrtc::DrmCrtc(uint32_t crtc_id, int fd, int resIndex) + : DrmObject(crtc_id, fd), + m_resIndex(resIndex) { } -DrmCrtc::~DrmCrtc() = default; +DrmCrtc::~DrmCrtc() +{ +} bool DrmCrtc::init() { - qCDebug(KWIN_DRM) << "Creating CRTC" << m_id; + qCDebug(KWIN_DRM) << "Atomic init for CRTC:" << resIndex() << "id:" << m_id; if (!initProps()) { return false; @@ -61,4 +67,34 @@ return true; } +void DrmCrtc::flipBuffer() +{ + if (m_currentBuffer && m_currentBuffer->deleteAfterPageFlip() && m_currentBuffer != m_nextBuffer) { + delete m_currentBuffer; + } + m_currentBuffer = m_nextBuffer; + m_nextBuffer = nullptr; +} + +bool DrmCrtc::blank() +{ + DrmBuffer *blackBuffer = m_output->m_backend->createBuffer(m_output->size()); + if (!blackBuffer->map()) { + delete blackBuffer; + return false; + } + blackBuffer->image()->fill(Qt::black); + + // TODO: Do this atomically + if (m_output->setModeLegacy(blackBuffer)) { + if (m_currentBuffer && m_currentBuffer->deleteAfterPageFlip()) { + delete m_currentBuffer; + } + delete m_nextBuffer; + m_currentBuffer = blackBuffer; + return true; + } + return false; +} + } diff --git a/plugins/platforms/drm/drm_output.h b/plugins/platforms/drm/drm_output.h --- a/plugins/platforms/drm/drm_output.h +++ b/plugins/platforms/drm/drm_output.h @@ -61,15 +61,13 @@ QSize physicalSize; }; virtual ~DrmOutput(); - void cleanup(); + void releaseGbm(); void showCursor(DrmBuffer *buffer); void hideCursor(); void moveCursor(const QPoint &globalPos); bool init(drmModeConnector *connector); bool present(DrmBuffer *buffer); void pageFlipped(); - void restoreSaved(); - bool blank(); /** * This sets the changes and tests them against the DRM output @@ -102,8 +100,9 @@ private: friend class DrmBackend; + friend class DrmCrtc; // TODO: For use of setModeLegacy. Remove later when we allow multiple connectors per crtc + // and save the connector ids in the DrmCrtc instance. DrmOutput(DrmBackend *backend); - void cleanupBlackBuffer(); bool presentAtomically(DrmBuffer *buffer); bool presentLegacy(DrmBuffer *buffer); bool setModeLegacy(DrmBuffer *buffer); @@ -119,31 +118,20 @@ DrmObject::AtomicReturn atomicReqModesetPopulate(drmModeAtomicReq *req, bool enable); DrmBackend *m_backend; + DrmConnector *m_conn = nullptr; + DrmCrtc *m_crtc = nullptr; QPoint m_globalPos; - quint32 m_crtcId = 0; - quint32 m_connector = 0; quint32 m_lastStride = 0; bool m_lastGbm = false; drmModeModeInfo m_mode; - DrmBuffer *m_currentBuffer = nullptr; - DrmBuffer *m_nextBuffer = nullptr; - DrmBuffer *m_blackBuffer = nullptr; - struct CrtcCleanup { - static void inline cleanup(_drmModeCrtc *ptr) { - drmModeFreeCrtc(ptr); // TODO: Atomically? See compositor-drm.c l.3670 - } - }; Edid m_edid; - QScopedPointer<_drmModeCrtc, CrtcCleanup> m_savedCrtc; QPointer m_waylandOutput; QPointer m_waylandOutputDevice; QPointer m_changeset; KWin::ScopedDrmPointer<_drmModeProperty, &drmModeFreeProperty> m_dpms; DpmsMode m_dpmsMode = DpmsMode::On; QByteArray m_uuid; - DrmConnector *m_conn = nullptr; - DrmCrtc *m_crtc = nullptr; uint32_t m_blobId = 0; DrmPlane* m_primaryPlane = nullptr; DrmPlane* m_cursorPlane = nullptr; diff --git a/plugins/platforms/drm/drm_output.cpp b/plugins/platforms/drm/drm_output.cpp --- a/plugins/platforms/drm/drm_output.cpp +++ b/plugins/platforms/drm/drm_output.cpp @@ -62,54 +62,38 @@ DrmOutput::~DrmOutput() { hideCursor(); - cleanupBlackBuffer(); - delete m_crtc; - delete m_conn; + m_crtc->blank(); delete m_waylandOutput.data(); delete m_waylandOutputDevice.data(); } -void DrmOutput::cleanup() +void DrmOutput::releaseGbm() { - if (m_currentBuffer) { - m_currentBuffer->releaseGbm(); - } - if (m_nextBuffer) { - m_nextBuffer->releaseGbm(); + if (DrmBuffer *b = m_crtc->current()) { + b->releaseGbm(); } if (m_primaryPlane) { if (m_primaryPlane->current()) { m_primaryPlane->current()->releaseGbm(); } - if (m_primaryPlane->next()) { - m_primaryPlane->next()->releaseGbm(); - } } } void DrmOutput::hideCursor() { - drmModeSetCursor(m_backend->fd(), m_crtcId, 0, 0, 0); -} - -void DrmOutput::restoreSaved() -{ - if (!m_savedCrtc.isNull()) { - drmModeSetCrtc(m_backend->fd(), m_savedCrtc->crtc_id, m_savedCrtc->buffer_id, - m_savedCrtc->x, m_savedCrtc->y, &m_connector, 1, &m_savedCrtc->mode); - } + drmModeSetCursor(m_backend->fd(), m_crtc->id(), 0, 0, 0); } void DrmOutput::showCursor(DrmBuffer *c) { const QSize &s = c->size(); - drmModeSetCursor(m_backend->fd(), m_crtcId, c->handle(), s.width(), s.height()); + drmModeSetCursor(m_backend->fd(), m_crtc->id(), c->handle(), s.width(), s.height()); } void DrmOutput::moveCursor(const QPoint &globalPos) { const QPoint p = globalPos - m_globalPos; - drmModeMoveCursor(m_backend->fd(), m_crtcId, p.x(), p.y()); + drmModeMoveCursor(m_backend->fd(), m_crtc->id(), p.x(), p.y()); } QSize DrmOutput::size() const @@ -187,8 +171,7 @@ return false; } } - m_savedCrtc.reset(drmModeGetCrtc(m_backend->fd(), m_crtcId)); - if (!blank()) { + if (!m_crtc->blank()) { return false; } setDpms(DpmsMode::On); @@ -306,7 +289,7 @@ void DrmOutput::initUuid() { QCryptographicHash hash(QCryptographicHash::Md5); - hash.addData(QByteArray::number(m_connector)); + hash.addData(QByteArray::number(m_conn->id())); hash.addData(m_edid.eisaId); hash.addData(m_edid.monitorName); hash.addData(m_edid.serialNumber); @@ -507,12 +490,12 @@ if (m_primaryPlane) { // Output already has a primary plane continue; } - if (!p->isCrtcSupported(m_crtcId)) { + if (!p->isCrtcSupported(m_crtc->id())) { continue; } p->setOutput(this); m_primaryPlane = p; - qCDebug(KWIN_DRM) << "Initialized primary plane" << p->id() << "on CRTC" << m_crtcId; + qCDebug(KWIN_DRM) << "Initialized primary plane" << p->id() << "on CRTC" << m_crtc->id(); return true; } qCCritical(KWIN_DRM) << "Failed to initialize primary plane."; @@ -535,12 +518,12 @@ if (m_cursorPlane) { // Output already has a cursor plane continue; } - if (!p->isCrtcSupported(m_crtcId)) { + if (!p->isCrtcSupported(m_crtc->id())) { continue; } p->setOutput(this); m_cursorPlane = p; - qCDebug(KWIN_DRM) << "Initialized cursor plane" << p->id() << "on CRTC" << m_crtcId; + qCDebug(KWIN_DRM) << "Initialized cursor plane" << p->id() << "on CRTC" << m_crtc->id(); return true; } return false; @@ -574,17 +557,17 @@ drmModeAtomicReq *req = drmModeAtomicAlloc(); if (atomicReqModesetPopulate(req, mode == DpmsMode::On) == DrmObject::AtomicReturn::Error) { - qCWarning(KWIN_DRM) << "Failed to populate atomic request for output" << m_crtcId; + qCWarning(KWIN_DRM) << "Failed to populate atomic request for output" << m_crtc->id(); return; } if (drmModeAtomicCommit(m_backend->fd(), req, DRM_MODE_ATOMIC_ALLOW_MODESET, this)) { - qCWarning(KWIN_DRM) << "Failed to commit atomic request for output" << m_crtcId; + qCWarning(KWIN_DRM) << "Failed to commit atomic request for output" << m_crtc->id(); } else { - qCDebug(KWIN_DRM) << "DPMS set for output" << m_crtcId; + qCDebug(KWIN_DRM) << "DPMS set for output" << m_crtc->id(); } drmModeAtomicFree(req); } else { - if (drmModeConnectorSetProperty(m_backend->fd(), m_connector, m_dpms->prop_id, uint64_t(mode)) < 0) { + if (drmModeConnectorSetProperty(m_backend->fd(), m_conn->id(), m_dpms->prop_id, uint64_t(mode)) < 0) { qCWarning(KWIN_DRM) << "Setting DPMS failed"; return; } @@ -599,7 +582,7 @@ m_backend->outputWentOff(); } else { m_backend->checkOutputsAreOn(); - blank(); + m_crtc->blank(); if (Compositor *compositor = Compositor::self()) { compositor->addRepaintFull(); } @@ -682,6 +665,9 @@ void DrmOutput::pageFlipped() { + if (!m_crtc) { + return; + } if (m_backend->atomicModeSetting()){ foreach (DrmPlane *p, m_planesFlipList) { pageFlippedBufferRemover(p->current(), p->next()); @@ -691,18 +677,15 @@ m_planesFlipList.clear(); } else { - if (!m_nextBuffer) { + if (!m_crtc->next()) { // on manual vt switch - if (m_currentBuffer) { - m_currentBuffer->releaseGbm(); + if (DrmBuffer *b = m_crtc->current()) { + b->releaseGbm(); } return; } - pageFlippedBufferRemover(m_currentBuffer, m_nextBuffer); - m_currentBuffer = m_nextBuffer; - m_nextBuffer = nullptr; + m_crtc->flipBuffer(); } - cleanupBlackBuffer(); } void DrmOutput::pageFlippedBufferRemover(DrmBuffer *oldbuffer, DrmBuffer *newbuffer) @@ -712,28 +695,6 @@ } } -void DrmOutput::cleanupBlackBuffer() -{ - if (m_blackBuffer) { - delete m_blackBuffer; - m_blackBuffer = nullptr; - } -} - -bool DrmOutput::blank() -{ - if (!m_blackBuffer) { - m_blackBuffer = m_backend->createBuffer(size()); - if (!m_blackBuffer->map()) { - cleanupBlackBuffer(); - return false; - } - m_blackBuffer->image()->fill(Qt::black); - } - // TODO: Do this atomically - return setModeLegacy(m_blackBuffer); -} - bool DrmOutput::present(DrmBuffer *buffer) { if (!buffer || buffer->bufferId() == 0) { @@ -852,11 +813,11 @@ bool DrmOutput::presentLegacy(DrmBuffer *buffer) { - if (m_nextBuffer) { + if (m_crtc->next()) { return false; } if (!LogindIntegration::self()->isActiveSession()) { - m_nextBuffer = buffer; + m_crtc->setNext(buffer); return false; } if (m_dpmsMode != DpmsMode::On) { @@ -869,9 +830,9 @@ return false; } int errno_save = 0; - const bool ok = drmModePageFlip(m_backend->fd(), m_crtcId, buffer->bufferId(), DRM_MODE_PAGE_FLIP_EVENT, this) == 0; + const bool ok = drmModePageFlip(m_backend->fd(), m_crtc->id(), buffer->bufferId(), DRM_MODE_PAGE_FLIP_EVENT, this) == 0; if (ok) { - m_nextBuffer = buffer; + m_crtc->setNext(buffer); } else { errno_save = errno; qCWarning(KWIN_DRM) << "Page flip failed:" << strerror(errno); @@ -882,7 +843,8 @@ bool DrmOutput::setModeLegacy(DrmBuffer *buffer) { - if (drmModeSetCrtc(m_backend->fd(), m_crtcId, buffer->bufferId(), 0, 0, &m_connector, 1, &m_mode) == 0) { + uint32_t connId = m_conn->id(); + if (drmModeSetCrtc(m_backend->fd(), m_crtc->id(), buffer->bufferId(), 0, 0, &connId, 1, &m_mode) == 0) { m_lastStride = buffer->stride(); m_lastGbm = buffer->isGbm(); return true; diff --git a/plugins/platforms/drm/egl_gbm_backend.cpp b/plugins/platforms/drm/egl_gbm_backend.cpp --- a/plugins/platforms/drm/egl_gbm_backend.cpp +++ b/plugins/platforms/drm/egl_gbm_backend.cpp @@ -74,7 +74,7 @@ void EglGbmBackend::cleanupOutput(const Output &o) { - o.output->cleanup(); + o.output->releaseGbm(); if (o.eglSurface != EGL_NO_SURFACE) { eglDestroySurface(eglDisplay(), o.eglSurface);