Changeset View
Standalone View
plugins/platforms/drm/drm_backend.cpp
Show First 20 Lines • Show All 43 Lines • ▼ Show 20 Line(s) | |||||
44 | #include <KCoreAddons> | 44 | #include <KCoreAddons> | ||
45 | #include <KLocalizedString> | 45 | #include <KLocalizedString> | ||
46 | #include <KSharedConfig> | 46 | #include <KSharedConfig> | ||
47 | // Qt | 47 | // Qt | ||
48 | #include <QCryptographicHash> | 48 | #include <QCryptographicHash> | ||
49 | #include <QSocketNotifier> | 49 | #include <QSocketNotifier> | ||
50 | #include <QPainter> | 50 | #include <QPainter> | ||
51 | // system | 51 | // system | ||
52 | #include <algorithm> | ||||
52 | #include <unistd.h> | 53 | #include <unistd.h> | ||
53 | // drm | 54 | // drm | ||
54 | #include <xf86drm.h> | 55 | #include <xf86drm.h> | ||
55 | #include <xf86drmMode.h> | 56 | #include <xf86drmMode.h> | ||
56 | #include <libdrm/drm_mode.h> | 57 | #include <libdrm/drm_mode.h> | ||
57 | 58 | | |||
58 | #ifndef DRM_CAP_CURSOR_WIDTH | 59 | #ifndef DRM_CAP_CURSOR_WIDTH | ||
59 | #define DRM_CAP_CURSOR_WIDTH 0x8 | 60 | #define DRM_CAP_CURSOR_WIDTH 0x8 | ||
Show All 25 Lines | 85 | if (m_gbmDevice) { | |||
85 | gbm_device_destroy(m_gbmDevice); | 86 | gbm_device_destroy(m_gbmDevice); | ||
86 | } | 87 | } | ||
87 | #endif | 88 | #endif | ||
88 | if (m_fd >= 0) { | 89 | if (m_fd >= 0) { | ||
89 | // wait for pageflips | 90 | // wait for pageflips | ||
90 | while (m_pageFlipsPending != 0) { | 91 | while (m_pageFlipsPending != 0) { | ||
91 | QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents); | 92 | QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents); | ||
92 | } | 93 | } | ||
94 | // we need to first remove all outputs | ||||
93 | qDeleteAll(m_outputs); | 95 | qDeleteAll(m_outputs); | ||
96 | m_outputs.clear(); | ||||
97 | m_enabledOutputs.clear(); | ||||
98 | | ||||
94 | qDeleteAll(m_planes); | 99 | qDeleteAll(m_planes); | ||
95 | qDeleteAll(m_crtcs); | 100 | qDeleteAll(m_crtcs); | ||
96 | qDeleteAll(m_connectors); | 101 | qDeleteAll(m_connectors); | ||
97 | close(m_fd); | 102 | close(m_fd); | ||
98 | } | 103 | } | ||
99 | } | 104 | } | ||
100 | 105 | | |||
101 | void DrmBackend::init() | 106 | void DrmBackend::init() | ||
Show All 9 Lines | 107 | { | |||
111 | }; | 116 | }; | ||
112 | if (logind->isConnected()) { | 117 | if (logind->isConnected()) { | ||
113 | takeControl(); | 118 | takeControl(); | ||
114 | } else { | 119 | } else { | ||
115 | connect(logind, &LogindIntegration::connectedChanged, this, takeControl); | 120 | connect(logind, &LogindIntegration::connectedChanged, this, takeControl); | ||
116 | } | 121 | } | ||
117 | } | 122 | } | ||
118 | 123 | | |||
124 | QVector<AbstractOutput*> DrmBackend::outputs() const | ||||
125 | { | ||||
126 | QVector<AbstractOutput*> ret(m_outputs.size()); | ||||
127 | std::copy(m_outputs.begin(), m_outputs.end(), ret.begin()); | ||||
128 | return ret; | ||||
129 | } | ||||
130 | | ||||
131 | QVector<AbstractOutput*> DrmBackend::enabledOutputs() const | ||||
132 | { | ||||
133 | QVector<AbstractOutput*> ret(m_enabledOutputs.size()); | ||||
134 | std::copy(m_enabledOutputs.begin(), m_enabledOutputs.end(), ret.begin()); | ||||
135 | return ret; | ||||
136 | } | ||||
137 | | ||||
119 | void DrmBackend::outputWentOff() | 138 | void DrmBackend::outputWentOff() | ||
120 | { | 139 | { | ||
121 | if (!m_dpmsFilter.isNull()) { | 140 | if (!m_dpmsFilter.isNull()) { | ||
122 | // already another output is off | 141 | // already another output is off | ||
123 | return; | 142 | return; | ||
124 | } | 143 | } | ||
125 | m_dpmsFilter.reset(new DpmsInputEventFilter(this)); | 144 | m_dpmsFilter.reset(new DpmsInputEventFilter(this)); | ||
126 | input()->prependInputEventFilter(m_dpmsFilter.data()); | 145 | input()->prependInputEventFilter(m_dpmsFilter.data()); | ||
127 | } | 146 | } | ||
128 | 147 | | |||
129 | void DrmBackend::turnOutputsOn() | 148 | void DrmBackend::turnOutputsOn() | ||
130 | { | 149 | { | ||
131 | m_dpmsFilter.reset(); | 150 | m_dpmsFilter.reset(); | ||
132 | for (auto it = m_enabledOutputs.constBegin(), end = m_enabledOutputs.constEnd(); it != end; it++) { | 151 | for (auto it = m_enabledOutputs.constBegin(), end = m_enabledOutputs.constEnd(); it != end; it++) { | ||
133 | (*it)->setDpms(DrmOutput::DpmsMode::On); | 152 | (*it)->setDpms(DrmOutput::DpmsMode::On); | ||
graesslin: static_cast? That sounds wrong. I doubt you need it. Just do:
```
auto o = *it;
``` | |||||
134 | } | 153 | } | ||
135 | } | 154 | } | ||
136 | 155 | | |||
137 | void DrmBackend::checkOutputsAreOn() | 156 | void DrmBackend::checkOutputsAreOn() | ||
138 | { | 157 | { | ||
139 | if (m_dpmsFilter.isNull()) { | 158 | if (m_dpmsFilter.isNull()) { | ||
140 | // already disabled, all outputs are on | 159 | // already disabled, all outputs are on | ||
141 | return; | 160 | return; | ||
142 | } | 161 | } | ||
143 | for (auto it = m_enabledOutputs.constBegin(), end = m_enabledOutputs.constEnd(); it != end; it++) { | 162 | for (auto it = m_enabledOutputs.constBegin(), end = m_enabledOutputs.constEnd(); it != end; it++) { | ||
144 | if (!(*it)->isDpmsEnabled()) { | 163 | if (!(*it)->isDpmsEnabled()) { | ||
graesslin: same here, static_cast looks wrong | |||||
145 | // dpms still disabled, need to keep the filter | 164 | // dpms still disabled, need to keep the filter | ||
146 | return; | 165 | return; | ||
147 | } | 166 | } | ||
148 | } | 167 | } | ||
149 | // all outputs are on, disable the filter | 168 | // all outputs are on, disable the filter | ||
150 | m_dpmsFilter.reset(); | 169 | m_dpmsFilter.reset(); | ||
151 | } | 170 | } | ||
152 | 171 | | |||
Show All 12 Lines | |||||
165 | { | 184 | { | ||
166 | if (m_active) { | 185 | if (m_active) { | ||
167 | return; | 186 | return; | ||
168 | } | 187 | } | ||
169 | m_active = true; | 188 | m_active = true; | ||
170 | if (!usesSoftwareCursor()) { | 189 | if (!usesSoftwareCursor()) { | ||
171 | const QPoint cp = Cursor::pos() - softwareCursorHotspot(); | 190 | const QPoint cp = Cursor::pos() - softwareCursorHotspot(); | ||
172 | for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { | 191 | for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { | ||
173 | DrmOutput *o = *it; | 192 | DrmOutput *o = *it; | ||
zzag: You could use `auto`. ;-) | |||||
graesslin: here as well the static cast looks like not needed | |||||
174 | // only relevant in atomic mode | 193 | // only relevant in atomic mode | ||
175 | o->m_modesetRequested = true; | 194 | o->m_modesetRequested = true; | ||
176 | o->pageFlipped(); // TODO: Do we really need this? | 195 | o->pageFlipped(); // TODO: Do we really need this? | ||
177 | o->m_crtc->blank(); | 196 | o->m_crtc->blank(); | ||
178 | o->showCursor(); | 197 | o->showCursor(); | ||
179 | o->moveCursor(cp); | 198 | o->moveCursor(cp); | ||
180 | } | 199 | } | ||
181 | } | 200 | } | ||
Show All 11 Lines | 211 | if (!m_active) { | |||
193 | return; | 212 | return; | ||
194 | } | 213 | } | ||
195 | // block compositor | 214 | // block compositor | ||
196 | if (m_pageFlipsPending == 0 && Compositor::self()) { | 215 | if (m_pageFlipsPending == 0 && Compositor::self()) { | ||
197 | Compositor::self()->aboutToSwapBuffers(); | 216 | Compositor::self()->aboutToSwapBuffers(); | ||
198 | } | 217 | } | ||
199 | // hide cursor and disable | 218 | // hide cursor and disable | ||
200 | for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { | 219 | for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { | ||
201 | DrmOutput *o = *it; | 220 | DrmOutput *o = *it; | ||
graesslin: and here as well | |||||
202 | o->hideCursor(); | 221 | o->hideCursor(); | ||
203 | } | 222 | } | ||
204 | m_active = false; | 223 | m_active = false; | ||
205 | } | 224 | } | ||
206 | 225 | | |||
207 | void DrmBackend::pageFlipHandler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data) | 226 | void DrmBackend::pageFlipHandler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data) | ||
208 | { | 227 | { | ||
209 | Q_UNUSED(fd) | 228 | Q_UNUSED(fd) | ||
▲ Show 20 Lines • Show All 158 Lines • ▼ Show 20 Line(s) | 384 | { | |||
368 | } | 387 | } | ||
369 | 388 | | |||
370 | ScopedDrmPointer<_drmModeRes, &drmModeFreeResources> resources(drmModeGetResources(m_fd)); | 389 | ScopedDrmPointer<_drmModeRes, &drmModeFreeResources> resources(drmModeGetResources(m_fd)); | ||
371 | if (!resources) { | 390 | if (!resources) { | ||
372 | qCWarning(KWIN_DRM) << "drmModeGetResources failed"; | 391 | qCWarning(KWIN_DRM) << "drmModeGetResources failed"; | ||
373 | return; | 392 | return; | ||
374 | } | 393 | } | ||
375 | 394 | | |||
376 | QVector<DrmOutput*> connectedOutputs; | 395 | QVector<DrmOutput*> connectedOutputs; | ||
I don't understand why you changed from QVector<DrmOutput*> to QVector<Output*>. The list still gets filled with DrmOutput and afterwards you make your life hard by having to static_cast back to DrmOutput. graesslin: I don't understand why you changed from QVector<DrmOutput*> to QVector<Output*>. The list still… | |||||
377 | QVector<DrmConnector*> pendingConnectors; | 396 | QVector<DrmConnector*> pendingConnectors; | ||
378 | 397 | | |||
379 | // split up connected connectors in already or not yet assigned ones | 398 | // split up connected connectors in already or not yet assigned ones | ||
380 | for (DrmConnector *con : qAsConst(m_connectors)) { | 399 | for (DrmConnector *con : qAsConst(m_connectors)) { | ||
381 | if (!con->isConnected()) { | 400 | if (!con->isConnected()) { | ||
382 | continue; | 401 | continue; | ||
383 | } | 402 | } | ||
384 | 403 | | |||
Show All 11 Lines | 414 | if (connectedOutputs.contains(*it)) { | |||
396 | it++; | 415 | it++; | ||
397 | continue; | 416 | continue; | ||
398 | } | 417 | } | ||
399 | DrmOutput *removed = *it; | 418 | DrmOutput *removed = *it; | ||
400 | it = m_outputs.erase(it); | 419 | it = m_outputs.erase(it); | ||
401 | m_enabledOutputs.removeOne(removed); | 420 | m_enabledOutputs.removeOne(removed); | ||
402 | emit outputRemoved(removed); | 421 | emit outputRemoved(removed); | ||
403 | delete removed; | 422 | delete removed; | ||
404 | } | 423 | } | ||
Please no static_casts. Either change the signature of outputRemoved signal or do a safe cast like qobject_cast or dynamic_cast. Static_cast is evil :-) graesslin: Please no static_casts. Either change the signature of outputRemoved signal or do a safe cast… | |||||
405 | 424 | | |||
406 | // now check new connections | 425 | // now check new connections | ||
407 | for (DrmConnector *con : qAsConst(pendingConnectors)) { | 426 | for (DrmConnector *con : qAsConst(pendingConnectors)) { | ||
408 | ScopedDrmPointer<_drmModeConnector, &drmModeFreeConnector> connector(drmModeGetConnector(m_fd, con->id())); | 427 | ScopedDrmPointer<_drmModeConnector, &drmModeFreeConnector> connector(drmModeGetConnector(m_fd, con->id())); | ||
409 | if (!connector) { | 428 | if (!connector) { | ||
410 | continue; | 429 | continue; | ||
411 | } | 430 | } | ||
412 | if (connector->count_modes == 0) { | 431 | if (connector->count_modes == 0) { | ||
Show All 11 Lines | 442 | for (DrmCrtc *crtc : qAsConst(m_crtcs)) { | |||
424 | if (!(encoder->possible_crtcs & (1 << crtc->resIndex()))) { | 443 | if (!(encoder->possible_crtcs & (1 << crtc->resIndex()))) { | ||
425 | continue; | 444 | continue; | ||
426 | } | 445 | } | ||
427 | 446 | | |||
428 | // check if crtc isn't used yet -- currently we don't allow multiple outputs on one crtc (cloned mode) | 447 | // check if crtc isn't used yet -- currently we don't allow multiple outputs on one crtc (cloned mode) | ||
429 | auto it = std::find_if(connectedOutputs.constBegin(), connectedOutputs.constEnd(), | 448 | auto it = std::find_if(connectedOutputs.constBegin(), connectedOutputs.constEnd(), | ||
430 | [crtc] (DrmOutput *o) { | 449 | [crtc] (DrmOutput *o) { | ||
431 | return o->m_crtc == crtc; | 450 | return o->m_crtc == crtc; | ||
432 | } | 451 | } | ||
If connectedOutputs would still be QVector<DrmOutput*> you would not need the cast here. graesslin: If connectedOutputs would still be QVector<DrmOutput*> you would not need the cast here. | |||||
433 | ); | 452 | ); | ||
434 | if (it != connectedOutputs.constEnd()) { | 453 | if (it != connectedOutputs.constEnd()) { | ||
435 | continue; | 454 | continue; | ||
436 | } | 455 | } | ||
437 | 456 | | |||
438 | // we found a suitable encoder+crtc | 457 | // we found a suitable encoder+crtc | ||
439 | // TODO: we could avoid these lib drm calls if we store all struct data in DrmCrtc and DrmConnector in the beginning | 458 | // TODO: we could avoid these lib drm calls if we store all struct data in DrmCrtc and DrmConnector in the beginning | ||
440 | ScopedDrmPointer<_drmModeCrtc, &drmModeFreeCrtc> modeCrtc(drmModeGetCrtc(m_fd, crtc->id())); | 459 | ScopedDrmPointer<_drmModeCrtc, &drmModeFreeCrtc> modeCrtc(drmModeGetCrtc(m_fd, crtc->id())); | ||
Show All 30 Lines | |||||
471 | outputDone = true; | 490 | outputDone = true; | ||
472 | break; | 491 | break; | ||
473 | } | 492 | } | ||
474 | if (outputDone) { | 493 | if (outputDone) { | ||
475 | break; | 494 | break; | ||
476 | } | 495 | } | ||
477 | } | 496 | } | ||
478 | } | 497 | } | ||
479 | std::sort(connectedOutputs.begin(), connectedOutputs.end(), [] (DrmOutput *a, DrmOutput *b) { return a->m_conn->id() < b->m_conn->id(); }); | 498 | std::sort(connectedOutputs.begin(), connectedOutputs.end(), [] (DrmOutput *a, DrmOutput *b) { return a->m_conn->id() < b->m_conn->id(); }); | ||
480 | m_outputs = connectedOutputs; | 499 | m_outputs = connectedOutputs; | ||
same here. The change would not be needed if the signature were not changed. graesslin: same here. The change would not be needed if the signature were not changed. | |||||
481 | m_enabledOutputs = connectedOutputs; | 500 | m_enabledOutputs = connectedOutputs; | ||
482 | readOutputsConfiguration(); | 501 | readOutputsConfiguration(); | ||
483 | if (!m_outputs.isEmpty()) { | 502 | if (!m_outputs.isEmpty()) { | ||
484 | emit screensQueried(); | 503 | emit screensQueried(); | ||
485 | } | 504 | } | ||
486 | } | 505 | } | ||
487 | 506 | | |||
488 | void DrmBackend::readOutputsConfiguration() | 507 | void DrmBackend::readOutputsConfiguration() | ||
489 | { | 508 | { | ||
490 | if (m_outputs.isEmpty()) { | 509 | if (m_outputs.isEmpty()) { | ||
491 | return; | 510 | return; | ||
492 | } | 511 | } | ||
493 | const QByteArray uuid = generateOutputConfigurationUuid(); | 512 | const QByteArray uuid = generateOutputConfigurationUuid(); | ||
494 | const auto outputGroup = kwinApp()->config()->group("DrmOutputs"); | 513 | const auto outputGroup = kwinApp()->config()->group("DrmOutputs"); | ||
495 | const auto configGroup = outputGroup.group(uuid); | 514 | const auto configGroup = outputGroup.group(uuid); | ||
496 | // default position goes from left to right | 515 | // default position goes from left to right | ||
497 | QPoint pos(0, 0); | 516 | QPoint pos(0, 0); | ||
498 | for (auto it = m_outputs.begin(); it != m_outputs.end(); ++it) { | 517 | for (auto it = m_outputs.begin(); it != m_outputs.end(); ++it) { | ||
499 | qCDebug(KWIN_DRM) << "Reading output configuration for [" << uuid << "] ["<< (*it)->uuid() << "]"; | 518 | qCDebug(KWIN_DRM) << "Reading output configuration for [" << uuid << "] ["<< (*it)->uuid() << "]"; | ||
500 | const auto outputConfig = configGroup.group((*it)->uuid()); | 519 | const auto outputConfig = configGroup.group((*it)->uuid()); | ||
501 | (*it)->setGlobalPos(outputConfig.readEntry<QPoint>("Position", pos)); | 520 | (*it)->setGlobalPos(outputConfig.readEntry<QPoint>("Position", pos)); | ||
Please don't hide pointer under auto. Make it explicit, e.g. auto *o = qobject_cast<DrmOutput*>(*it); That will improve readability a little bit. https://clang.llvm.org/extra/clang-tidy/checks/modernize-use-auto.html zzag: Please don't hide pointer under `auto`. Make it explicit, e.g.
```lang=cpp
auto *o =… | |||||
graesslin: please a safe cast like qobject_cast or dynamic_cast | |||||
502 | // TODO: add mode | 521 | // TODO: add mode | ||
503 | (*it)->setScale(outputConfig.readEntry("Scale", 1.0)); | 522 | (*it)->setScale(outputConfig.readEntry("Scale", 1.0)); | ||
504 | pos.setX(pos.x() + (*it)->geometry().width()); | 523 | pos.setX(pos.x() + (*it)->geometry().width()); | ||
505 | } | 524 | } | ||
506 | } | 525 | } | ||
507 | 526 | | |||
508 | QByteArray DrmBackend::generateOutputConfigurationUuid() const | 527 | QByteArray DrmBackend::generateOutputConfigurationUuid() const | ||
509 | { | 528 | { | ||
510 | auto it = m_outputs.constBegin(); | 529 | auto it = m_outputs.constBegin(); | ||
511 | if (m_outputs.size() == 1) { | 530 | if (m_outputs.size() == 1) { | ||
512 | // special case: one output | 531 | // special case: one output | ||
513 | return (*it)->uuid(); | 532 | return (*it)->uuid(); | ||
graesslin: same here | |||||
514 | } | 533 | } | ||
515 | QCryptographicHash hash(QCryptographicHash::Md5); | 534 | QCryptographicHash hash(QCryptographicHash::Md5); | ||
516 | for (; it != m_outputs.constEnd(); ++it) { | 535 | for (; it != m_outputs.constEnd(); ++it) { | ||
517 | hash.addData((*it)->uuid()); | 536 | hash.addData((*it)->uuid()); | ||
graesslin: and here | |||||
518 | } | 537 | } | ||
519 | return hash.result().toHex().left(10); | 538 | return hash.result().toHex().left(10); | ||
520 | } | 539 | } | ||
521 | 540 | | |||
522 | void DrmBackend::configurationChangeRequested(KWayland::Server::OutputConfigurationInterface *config) | 541 | void DrmBackend::configurationChangeRequested(KWayland::Server::OutputConfigurationInterface *config) | ||
523 | { | 542 | { | ||
524 | const auto changes = config->changes(); | 543 | const auto changes = config->changes(); | ||
525 | bool countChanged = false; | 544 | bool countChanged = false; | ||
▲ Show 20 Lines • Show All 270 Lines • Show Last 20 Lines |
static_cast? That sounds wrong. I doubt you need it. Just do: