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 @@ -158,11 +158,10 @@ QVector m_connectors; // currently active output pipelines (planes + crtc + encoder + connector) QVector m_outputs; - DrmDumbBuffer *m_cursor[2]; bool m_deleteBufferAfterPageFlip; bool m_atomicModeSetting = false; bool m_cursorEnabled = false; - int m_cursorIndex = 0; + QSize m_cursorSize; int m_pageFlipsPending = 0; bool m_active = false; // all available planes: primarys, cursors and overlays 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 @@ -74,8 +74,6 @@ , m_dpmsFilter() { handleOutputs(); - m_cursor[0] = nullptr; - m_cursor[1] = nullptr; } DrmBackend::~DrmBackend() @@ -94,8 +92,6 @@ qDeleteAll(m_planes); qDeleteAll(m_crtcs); qDeleteAll(m_connectors); - delete m_cursor[0]; - delete m_cursor[1]; close(m_fd); } } @@ -170,15 +166,14 @@ } m_active = true; if (!usesSoftwareCursor()) { - DrmDumbBuffer *c = m_cursor[(m_cursorIndex + 1) % 2]; const QPoint cp = Cursor::pos() - softwareCursorHotspot(); for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { DrmOutput *o = *it; // only relevant in atomic mode o->m_modesetRequested = true; o->pageFlipped(); // TODO: Do we really need this? o->m_crtc->blank(); - o->showCursor(c); + o->showCursor(); o->moveCursor(cp); } } @@ -327,6 +322,7 @@ m_crtcs.erase(std::remove_if(m_crtcs.begin(), m_crtcs.end(), tryAtomicInit), m_crtcs.end()); } + initCursor(); updateOutputs(); if (m_outputs.isEmpty()) { @@ -353,17 +349,14 @@ if (device->hasProperty("HOTPLUG", "1")) { qCDebug(KWIN_DRM) << "Received hot plug event for monitored drm device"; updateOutputs(); - m_cursorIndex = (m_cursorIndex + 1) % 2; updateCursor(); } } ); m_udevMonitor->enable(); } } setReady(true); - - initCursor(); } void DrmBackend::updateOutputs() @@ -467,6 +460,9 @@ delete output; continue; } + if (!output->initCursor(m_cursorSize)) { + setSoftWareCursor(true); + } qCDebug(KWIN_DRM) << "Found new output with uuid" << output->uuid(); connectedOutputs << output; @@ -594,7 +590,7 @@ } for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { if (m_cursorEnabled) { - (*it)->showCursor(m_cursor[m_cursorIndex]); + (*it)->showCursor(); } else { (*it)->hideCursor(); } @@ -613,30 +609,17 @@ } else { cursorSize.setHeight(64); } - auto createCursor = [this, cursorSize] (int index) { - m_cursor[index] = createBuffer(cursorSize); - if (!m_cursor[index]->map(QImage::Format_ARGB32_Premultiplied)) { - return false; - } - m_cursor[index]->image()->fill(Qt::transparent); - return true; - }; - if (!createCursor(0) || !createCursor(1)) { - setSoftWareCursor(true); - return; - } + m_cursorSize = cursorSize; // now we have screens and can set cursors, so start tracking connect(this, &DrmBackend::cursorChanged, this, &DrmBackend::updateCursor); connect(Cursor::self(), &Cursor::posChanged, this, &DrmBackend::moveCursor); } void DrmBackend::setCursor() { - DrmDumbBuffer *c = m_cursor[m_cursorIndex]; - m_cursorIndex = (m_cursorIndex + 1) % 2; if (m_cursorEnabled) { for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { - (*it)->showCursor(c); + (*it)->showCursor(); } } markCursorAsRendered(); @@ -655,12 +638,9 @@ doHideCursor(); return; } - QImage *c = m_cursor[m_cursorIndex]->image(); - c->fill(Qt::transparent); - QPainter p; - p.begin(c); - p.drawImage(QPoint(0, 0), cursorImage); - p.end(); + for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { + (*it)->updateCursor(); + } setCursor(); moveCursor(); 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 @@ -65,7 +65,9 @@ virtual ~DrmOutput(); void releaseGbm(); void showCursor(DrmDumbBuffer *buffer); + void showCursor(); void hideCursor(); + void updateCursor(); void moveCursor(const QPoint &globalPos); bool init(drmModeConnector *connector); bool present(DrmBuffer *buffer); @@ -106,6 +108,8 @@ QSize physicalSize() const; + bool initCursor(const QSize &cursorSize); + Q_SIGNALS: void dpmsChanged(); void modeChanged(); @@ -174,6 +178,9 @@ QPoint globalPos; bool valid = false; } m_lastWorkingState; + DrmDumbBuffer *m_cursor[2] = {nullptr, nullptr}; + int m_cursorIndex = 0; + bool m_hasNewCursor = false; }; } 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 @@ -45,6 +45,7 @@ // Qt #include #include +#include // drm #include #include @@ -80,6 +81,8 @@ delete m_waylandOutput.data(); delete m_waylandOutputDevice.data(); + delete m_cursor[0]; + delete m_cursor[1]; } void DrmOutput::releaseGbm() @@ -103,6 +106,37 @@ drmModeSetCursor(m_backend->fd(), m_crtc->id(), c->handle(), s.width(), s.height()); } +void DrmOutput::showCursor() +{ + showCursor(m_cursor[m_cursorIndex]); + if (m_hasNewCursor) { + m_cursorIndex = (m_cursorIndex + 1) % 2; + m_hasNewCursor = false; + } +} + +void DrmOutput::updateCursor() +{ + QImage cursorImage = m_backend->softwareCursor(); + if (cursorImage.isNull()) { + return; + } + m_hasNewCursor = true; + QImage *c = m_cursor[m_cursorIndex]->image(); + c->fill(Qt::transparent); + QPainter p; + p.begin(c); + if (m_orientation == Qt::InvertedLandscapeOrientation) { + QMatrix4x4 matrix; + matrix.translate(cursorImage.width() / 2.0, cursorImage.height() / 2.0); + matrix.rotate(180.0f, 0.0f, 0.0f, 1.0f); + matrix.translate(-cursorImage.width() / 2.0, -cursorImage.height() / 2.0); + p.setWorldTransform(matrix.toTransform()); + } + p.drawImage(QPoint(0, 0), cursorImage); + p.end(); +} + void DrmOutput::moveCursor(const QPoint &globalPos) { QMatrix4x4 matrix; @@ -787,6 +821,9 @@ break; } m_modesetRequested = true; + // the cursor might need to get rotated + updateCursor(); + showCursor(); emit modeChanged(); } if (m_changeset->positionChanged()) { @@ -926,6 +963,9 @@ m_primaryPlane->setTransformation(m_lastWorkingState.planeTransformations); } m_modesetRequested = true; + // the cursor might need to get rotated + updateCursor(); + showCursor(); // TODO: forward to OutputInterface and OutputDeviceInterface emit modeChanged(); emit screens()->changed(); @@ -1122,4 +1162,19 @@ return ret; } +bool DrmOutput::initCursor(const QSize &cursorSize) +{ + auto createCursor = [this, cursorSize] (int index) { + m_cursor[index] = m_backend->createBuffer(cursorSize); + if (!m_cursor[index]->map(QImage::Format_ARGB32_Premultiplied)) { + return false; + } + return true; + }; + if (!createCursor(0) || !createCursor(1)) { + return false; + } + return true; +} + }