Changeset View
Changeset View
Standalone View
Standalone View
plugins/platforms/drm/drm_backend.cpp
Show First 20 Lines • Show All 81 Lines • ▼ Show 20 Line(s) | 81 | if (m_gbmDevice) { | |||
---|---|---|---|---|---|
82 | gbm_device_destroy(m_gbmDevice); | 82 | gbm_device_destroy(m_gbmDevice); | ||
83 | } | 83 | } | ||
84 | #endif | 84 | #endif | ||
85 | if (m_fd >= 0) { | 85 | if (m_fd >= 0) { | ||
86 | // wait for pageflips | 86 | // wait for pageflips | ||
87 | while (m_pageFlipsPending != 0) { | 87 | while (m_pageFlipsPending != 0) { | ||
88 | QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents); | 88 | QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents); | ||
89 | } | 89 | } | ||
90 | qDeleteAll(m_planes); | | |||
91 | qDeleteAll(m_outputs); | 90 | qDeleteAll(m_outputs); | ||
91 | qDeleteAll(m_planes); | ||||
92 | qDeleteAll(m_crtcs); | ||||
93 | qDeleteAll(m_connectors); | ||||
92 | delete m_cursor[0]; | 94 | delete m_cursor[0]; | ||
93 | delete m_cursor[1]; | 95 | delete m_cursor[1]; | ||
94 | close(m_fd); | 96 | close(m_fd); | ||
95 | } | 97 | } | ||
96 | } | 98 | } | ||
97 | 99 | | |||
98 | void DrmBackend::init() | 100 | void DrmBackend::init() | ||
99 | { | 101 | { | ||
▲ Show 20 Lines • Show All 63 Lines • ▼ Show 20 Line(s) | 162 | { | |||
163 | } | 165 | } | ||
164 | m_active = true; | 166 | m_active = true; | ||
165 | if (!usesSoftwareCursor()) { | 167 | if (!usesSoftwareCursor()) { | ||
166 | DrmBuffer *c = m_cursor[(m_cursorIndex + 1) % 2]; | 168 | DrmBuffer *c = m_cursor[(m_cursorIndex + 1) % 2]; | ||
167 | const QPoint cp = Cursor::pos() - softwareCursorHotspot(); | 169 | const QPoint cp = Cursor::pos() - softwareCursorHotspot(); | ||
168 | for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { | 170 | for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { | ||
169 | DrmOutput *o = *it; | 171 | DrmOutput *o = *it; | ||
170 | o->pageFlipped(); | 172 | o->pageFlipped(); | ||
171 | o->blank(); | 173 | o->m_crtc->blank(); | ||
172 | o->showCursor(c); | 174 | o->showCursor(c); | ||
173 | o->moveCursor(cp); | 175 | o->moveCursor(cp); | ||
174 | } | 176 | } | ||
175 | } | 177 | } | ||
176 | // restart compositor | 178 | // restart compositor | ||
177 | m_pageFlipsPending = 0; | 179 | m_pageFlipsPending = 0; | ||
178 | if (Compositor *compositor = Compositor::self()) { | 180 | if (Compositor *compositor = Compositor::self()) { | ||
179 | compositor->bufferSwapComplete(); | 181 | compositor->bufferSwapComplete(); | ||
Show All 9 Lines | 187 | { | |||
189 | // block compositor | 191 | // block compositor | ||
190 | if (m_pageFlipsPending == 0 && Compositor::self()) { | 192 | if (m_pageFlipsPending == 0 && Compositor::self()) { | ||
191 | Compositor::self()->aboutToSwapBuffers(); | 193 | Compositor::self()->aboutToSwapBuffers(); | ||
192 | } | 194 | } | ||
193 | // hide cursor and disable | 195 | // hide cursor and disable | ||
194 | for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { | 196 | for (auto it = m_outputs.constBegin(); it != m_outputs.constEnd(); ++it) { | ||
195 | DrmOutput *o = *it; | 197 | DrmOutput *o = *it; | ||
196 | o->hideCursor(); | 198 | o->hideCursor(); | ||
197 | o->restoreSaved(); | | |||
198 | } | 199 | } | ||
199 | m_active = false; | 200 | m_active = false; | ||
200 | } | 201 | } | ||
201 | 202 | | |||
202 | void DrmBackend::pageFlipHandler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data) | 203 | void DrmBackend::pageFlipHandler(int fd, unsigned int frame, unsigned int sec, unsigned int usec, void *data) | ||
203 | { | 204 | { | ||
204 | Q_UNUSED(fd) | 205 | Q_UNUSED(fd) | ||
205 | Q_UNUSED(frame) | 206 | Q_UNUSED(frame) | ||
▲ Show 20 Lines • Show All 75 Lines • ▼ Show 20 Line(s) | 280 | if (m_planes.isEmpty()) { | |||
281 | m_atomicModeSetting = false; | 282 | m_atomicModeSetting = false; | ||
282 | } | 283 | } | ||
283 | } | 284 | } | ||
284 | } else { | 285 | } else { | ||
285 | qCWarning(KWIN_DRM) << "drmSetClientCap for Atomic Mode Setting failed. Using legacy mode."; | 286 | qCWarning(KWIN_DRM) << "drmSetClientCap for Atomic Mode Setting failed. Using legacy mode."; | ||
286 | } | 287 | } | ||
287 | } | 288 | } | ||
288 | 289 | | |||
290 | ScopedDrmPointer<_drmModeRes, &drmModeFreeResources> resources(drmModeGetResources(m_fd)); | ||||
291 | drmModeRes *res = resources.data(); | ||||
292 | if (!resources) { | ||||
293 | qCWarning(KWIN_DRM) << "drmModeGetResources failed"; | ||||
294 | return; | ||||
295 | } | ||||
296 | | ||||
297 | for (int i = 0; i < res->count_connectors; ++i) { | ||||
298 | m_connectors << new DrmConnector(res->connectors[i], m_fd); | ||||
299 | } | ||||
300 | for (int i = 0; i < res->count_crtcs; ++i) { | ||||
301 | m_crtcs << new DrmCrtc(res->crtcs[i], m_fd, i); | ||||
302 | } | ||||
303 | | ||||
304 | if (m_atomicModeSetting) { | ||||
305 | auto tryInit = [] (DrmObject *o) -> bool { | ||||
306 | if (o->init()) { | ||||
307 | return false; | ||||
308 | } else { | ||||
309 | delete o; | ||||
310 | return true; | ||||
311 | } | ||||
312 | }; | ||||
313 | std::remove_if(m_connectors.begin(), m_connectors.end(), tryInit); | ||||
314 | std::remove_if(m_crtcs.begin(), m_crtcs.end(), tryInit); | ||||
anthonyfieroni: You mean std::erase(std::remove_if(...), ....end()) otherwise you have dangling pointer(s) in… | |||||
If remove_if is true, the object already got deleted in tryInit. remove_if then just removes the dangling pointer entry from the QVector. Afterwards everything is supposed to be clean, is it? romangg: If remove_if is true, the object already got deleted in tryInit. remove_if then just removes… | |||||
http://www.cplusplus.com/reference/algorithm/remove_if/ anthonyfieroni: http://www.cplusplus.com/reference/algorithm/remove_if/
remove_if does not remove anything from… | |||||
Thanks! So like this? m_connectors.erase(std::remove_if(m_connectors.begin(), m_connectors.end(), tryInit), m_connectors.end()); m_crtcs.erase(std::remove_if(m_crtcs.begin(), m_crtcs.end(), tryInit), m_crtcs.end()); romangg: Thanks! So like this?
```
m_connectors.erase(std::remove_if(m_connectors.begin(), m_connectors. | |||||
anthonyfieroni: Yes. | |||||
315 | } | ||||
316 | | ||||
289 | queryResources(); | 317 | queryResources(); | ||
318 | | ||||
290 | if (m_outputs.isEmpty()) { | 319 | if (m_outputs.isEmpty()) { | ||
291 | qCWarning(KWIN_DRM) << "No outputs, cannot render, will terminate now"; | 320 | qCWarning(KWIN_DRM) << "No outputs, cannot render, will terminate now"; | ||
292 | emit initFailed(); | 321 | emit initFailed(); | ||
293 | return; | 322 | return; | ||
294 | } | 323 | } | ||
295 | 324 | | |||
296 | // setup udevMonitor | 325 | // setup udevMonitor | ||
297 | if (m_udevMonitor) { | 326 | if (m_udevMonitor) { | ||
Show All 26 Lines | |||||
324 | initCursor(); | 353 | initCursor(); | ||
325 | } | 354 | } | ||
326 | 355 | | |||
327 | void DrmBackend::queryResources() | 356 | void DrmBackend::queryResources() | ||
328 | { | 357 | { | ||
329 | if (m_fd < 0) { | 358 | if (m_fd < 0) { | ||
330 | return; | 359 | return; | ||
331 | } | 360 | } | ||
361 | | ||||
332 | ScopedDrmPointer<_drmModeRes, &drmModeFreeResources> resources(drmModeGetResources(m_fd)); | 362 | ScopedDrmPointer<_drmModeRes, &drmModeFreeResources> resources(drmModeGetResources(m_fd)); | ||
333 | if (!resources) { | 363 | if (!resources) { | ||
334 | qCWarning(KWIN_DRM) << "drmModeGetResources failed"; | 364 | qCWarning(KWIN_DRM) << "drmModeGetResources failed"; | ||
335 | return; | 365 | return; | ||
336 | } | 366 | } | ||
337 | 367 | | |||
338 | QVector<DrmOutput*> connectedOutputs; | 368 | QVector<DrmOutput*> connectedOutputs; | ||
339 | for (int i = 0; i < resources->count_connectors; ++i) { | 369 | QVector<DrmConnector*> pendingConnectors; | ||
340 | const auto id = resources->connectors[i]; | 370 | | ||
341 | ScopedDrmPointer<_drmModeConnector, &drmModeFreeConnector> connector(drmModeGetConnector(m_fd, id)); | 371 | // split up connected connectors in already or not yet assigned ones | ||
342 | if (!connector) { | 372 | for (DrmConnector *con : m_connectors) { | ||
graesslin: qAsConst(m_connectors) | |||||
373 | if (!con->isConnected()) { | ||||
343 | continue; | 374 | continue; | ||
344 | } | 375 | } | ||
345 | if (connector->connection != DRM_MODE_CONNECTED) { | 376 | | ||
377 | if (DrmOutput *o = findOutput(con->id())) { | ||||
378 | connectedOutputs << o; | ||||
379 | } else { | ||||
380 | pendingConnectors << con; | ||||
381 | } | ||||
382 | } | ||||
383 | | ||||
384 | // check for outputs which got removed | ||||
385 | auto it = m_outputs.begin(); | ||||
386 | while (it != m_outputs.end()) { | ||||
387 | if (connectedOutputs.contains(*it)) { | ||||
388 | it++; | ||||
346 | continue; | 389 | continue; | ||
347 | } | 390 | } | ||
348 | if (connector->count_modes == 0) { | 391 | DrmOutput *removed = *it; | ||
392 | it = m_outputs.erase(it); | ||||
393 | emit outputRemoved(removed); | ||||
394 | delete removed; | ||||
395 | } | ||||
396 | | ||||
397 | // now check new connections | ||||
398 | for (DrmConnector *con : pendingConnectors) { | ||||
399 | ScopedDrmPointer<_drmModeConnector, &drmModeFreeConnector> connector(drmModeGetConnector(m_fd, con->id())); | ||||
400 | if (!connector) { | ||||
349 | continue; | 401 | continue; | ||
350 | } | 402 | } | ||
351 | if (DrmOutput *o = findOutput(connector->connector_id)) { | 403 | if (connector->count_modes == 0) { | ||
352 | connectedOutputs << o; | | |||
353 | continue; | 404 | continue; | ||
354 | } | 405 | } | ||
355 | bool crtcFound = false; | 406 | bool outputDone = false; | ||
356 | const quint32 crtcId = findCrtc(resources.data(), connector.data(), &crtcFound); | 407 | | ||
357 | if (!crtcFound) { | 408 | for (auto encId : con->encoders()) { | ||
graesslin: qAsConst in case encoders() doesn't return a const ref. | |||||
409 | ScopedDrmPointer<_drmModeEncoder, &drmModeFreeEncoder> encoder(drmModeGetEncoder(m_fd, encId)); | ||||
410 | if (!encoder) { | ||||
358 | continue; | 411 | continue; | ||
359 | } | 412 | } | ||
360 | ScopedDrmPointer<_drmModeCrtc, &drmModeFreeCrtc> crtc(drmModeGetCrtc(m_fd, crtcId)); | 413 | for (DrmCrtc *crtc : m_crtcs) { | ||
graesslin: qAsConst | |||||
361 | if (!crtc) { | 414 | if (!(encoder->possible_crtcs & (1 << crtc->resIndex()))) { | ||
362 | continue; | 415 | continue; | ||
363 | } | 416 | } | ||
364 | DrmOutput *drmOutput = new DrmOutput(this); | | |||
365 | connect(drmOutput, &DrmOutput::dpmsChanged, this, &DrmBackend::outputDpmsChanged); | | |||
366 | drmOutput->m_crtcId = crtcId; | | |||
367 | drmOutput->m_connector = connector->connector_id; | | |||
368 | 417 | | |||
369 | if (m_atomicModeSetting) { | 418 | // check if crtc isn't used yet -- currently we don't allow multiple outputs on one crtc (cloned mode) | ||
370 | drmOutput->m_crtc = new DrmCrtc(crtcId, m_fd); | 419 | auto it = std::find_if(connectedOutputs.constBegin(), connectedOutputs.constEnd(), | ||
371 | if (drmOutput->m_crtc->init()) { | 420 | [crtc] (DrmOutput *o) { | ||
372 | drmOutput->m_crtc->setOutput(drmOutput); | 421 | return o->m_crtc == crtc; | ||
373 | } else { | 422 | } | ||
374 | qCWarning(KWIN_DRM) << "Crtc object failed, skipping output on connector" << connector->connector_id; | 423 | ); | ||
375 | delete drmOutput->m_crtc; | 424 | if (it != connectedOutputs.constEnd()) { | ||
376 | delete drmOutput; | | |||
377 | continue; | 425 | continue; | ||
378 | } | 426 | } | ||
379 | 427 | | |||
380 | drmOutput->m_conn = new DrmConnector(connector->connector_id, m_fd); | 428 | // we found a suitable encoder+crtc | ||
381 | if (drmOutput->m_conn->init()) { | 429 | // TODO: we could avoid these lib drm calls if we store all struct data in DrmCrtc and DrmConnector in the beginning | ||
382 | drmOutput->m_conn->setOutput(drmOutput); | 430 | ScopedDrmPointer<_drmModeCrtc, &drmModeFreeCrtc> modeCrtc(drmModeGetCrtc(m_fd, crtc->id())); | ||
383 | } else { | 431 | if (!modeCrtc) { | ||
384 | qCWarning(KWIN_DRM) << "Connector object failed, skipping output on connector" << connector->connector_id; | | |||
385 | delete drmOutput->m_conn; | | |||
386 | delete drmOutput; | | |||
387 | continue; | 432 | continue; | ||
388 | } | 433 | } | ||
389 | } | | |||
390 | 434 | | |||
391 | if (crtc->mode_valid) { | 435 | DrmOutput *output = new DrmOutput(this); | ||
392 | drmOutput->m_mode = crtc->mode; | 436 | con->setOutput(output); | ||
437 | output->m_conn = con; | ||||
438 | crtc->setOutput(output); | ||||
439 | output->m_crtc = crtc; | ||||
440 | connect(output, &DrmOutput::dpmsChanged, this, &DrmBackend::outputDpmsChanged); | ||||
441 | | ||||
442 | if (modeCrtc->mode_valid) { | ||||
443 | output->m_mode = modeCrtc->mode; | ||||
393 | } else { | 444 | } else { | ||
394 | drmOutput->m_mode = connector->modes[0]; | 445 | output->m_mode = connector->modes[0]; | ||
395 | } | 446 | } | ||
396 | qCDebug(KWIN_DRM) << "For new output use mode " << drmOutput->m_mode.name; | 447 | qCDebug(KWIN_DRM) << "For new output use mode " << output->m_mode.name; | ||
397 | 448 | | |||
398 | if (!drmOutput->init(connector.data())) { | 449 | if (!output->init(connector.data())) { | ||
399 | qCWarning(KWIN_DRM) << "Failed to create output for connector " << connector->connector_id; | 450 | qCWarning(KWIN_DRM) << "Failed to create output for connector " << con->id(); | ||
400 | delete drmOutput; | 451 | delete output; | ||
401 | continue; | 452 | continue; | ||
This part looks incorrect to me, you need to set m_crtc and m_conn for init but if it fails then you go to outer loop it leave con and crtc with dangling output. anthonyfieroni: This part looks incorrect to me, you need to set m_crtc and m_conn for init but if it fails… | |||||
402 | } | 453 | } | ||
403 | qCDebug(KWIN_DRM) << "Found new output with uuid" << drmOutput->uuid(); | 454 | qCDebug(KWIN_DRM) << "Found new output with uuid" << output->uuid(); | ||
404 | connectedOutputs << drmOutput; | 455 | | ||
405 | } | 456 | connectedOutputs << output; | ||
406 | std::sort(connectedOutputs.begin(), connectedOutputs.end(), [] (DrmOutput *a, DrmOutput *b) { return a->m_connector < b->m_connector; }); | 457 | emit outputAdded(output); | ||
407 | // check for outputs which got removed | 458 | outputDone = true; | ||
408 | auto it = m_outputs.begin(); | 459 | break; | ||
409 | while (it != m_outputs.end()) { | | |||
410 | if (connectedOutputs.contains(*it)) { | | |||
411 | it++; | | |||
412 | continue; | | |||
413 | } | 460 | } | ||
414 | DrmOutput *removed = *it; | 461 | if (outputDone) { | ||
415 | it = m_outputs.erase(it); | 462 | break; | ||
416 | emit outputRemoved(removed); | | |||
417 | delete removed; | | |||
418 | } | 463 | } | ||
419 | for (auto it = connectedOutputs.constBegin(); it != connectedOutputs.constEnd(); ++it) { | | |||
420 | if (!m_outputs.contains(*it)) { | | |||
421 | emit outputAdded(*it); | | |||
422 | } | 464 | } | ||
423 | } | 465 | } | ||
466 | std::sort(connectedOutputs.begin(), connectedOutputs.end(), [] (DrmOutput *a, DrmOutput *b) { return a->m_conn->id() < b->m_conn->id(); }); | ||||
424 | m_outputs = connectedOutputs; | 467 | m_outputs = connectedOutputs; | ||
425 | readOutputsConfiguration(); | 468 | readOutputsConfiguration(); | ||
426 | if (!m_outputs.isEmpty()) { | 469 | if (!m_outputs.isEmpty()) { | ||
427 | emit screensQueried(); | 470 | emit screensQueried(); | ||
428 | } | 471 | } | ||
429 | } | 472 | } | ||
430 | 473 | | |||
431 | void DrmBackend::readOutputsConfiguration() | 474 | void DrmBackend::readOutputsConfiguration() | ||
▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Line(s) | 510 | for (auto it = changes.begin(); it != changes.end(); it++) { | |||
476 | drmoutput->setChanges(changeset); | 519 | drmoutput->setChanges(changeset); | ||
477 | } | 520 | } | ||
478 | emit screens()->changed(); | 521 | emit screens()->changed(); | ||
479 | } | 522 | } | ||
480 | 523 | | |||
481 | DrmOutput *DrmBackend::findOutput(quint32 connector) | 524 | DrmOutput *DrmBackend::findOutput(quint32 connector) | ||
482 | { | 525 | { | ||
483 | auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(), [connector] (DrmOutput *o) { | 526 | auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(), [connector] (DrmOutput *o) { | ||
484 | return o->m_connector == connector; | 527 | return o->m_conn->id() == connector; | ||
485 | }); | 528 | }); | ||
486 | if (it != m_outputs.constEnd()) { | 529 | if (it != m_outputs.constEnd()) { | ||
487 | return *it; | 530 | return *it; | ||
488 | } | 531 | } | ||
489 | return nullptr; | 532 | return nullptr; | ||
490 | } | 533 | } | ||
491 | 534 | | |||
492 | DrmOutput *DrmBackend::findOutput(const QByteArray &uuid) | 535 | DrmOutput *DrmBackend::findOutput(const QByteArray &uuid) | ||
493 | { | 536 | { | ||
494 | auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(), [uuid] (DrmOutput *o) { | 537 | auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(), [uuid] (DrmOutput *o) { | ||
495 | return o->m_uuid == uuid; | 538 | return o->m_uuid == uuid; | ||
496 | }); | 539 | }); | ||
497 | if (it != m_outputs.constEnd()) { | 540 | if (it != m_outputs.constEnd()) { | ||
498 | return *it; | 541 | return *it; | ||
499 | } | 542 | } | ||
500 | return nullptr; | 543 | return nullptr; | ||
501 | } | 544 | } | ||
502 | 545 | | |||
503 | quint32 DrmBackend::findCrtc(drmModeRes *res, drmModeConnector *connector, bool *ok) | | |||
504 | { | | |||
505 | if (ok) { | | |||
506 | *ok = false; | | |||
507 | } | | |||
508 | ScopedDrmPointer<_drmModeEncoder, &drmModeFreeEncoder> encoder(drmModeGetEncoder(m_fd, connector->encoder_id)); | | |||
509 | if (encoder) { | | |||
510 | if (!crtcIsUsed(encoder->crtc_id)) { | | |||
511 | if (ok) { | | |||
512 | *ok = true; | | |||
513 | } | | |||
514 | return encoder->crtc_id; | | |||
515 | } | | |||
516 | } | | |||
517 | // let's iterate over all encoders to find a suitable crtc | | |||
518 | for (int i = 0; i < connector->count_encoders; ++i) { | | |||
519 | ScopedDrmPointer<_drmModeEncoder, &drmModeFreeEncoder> encoder(drmModeGetEncoder(m_fd, connector->encoders[i])); | | |||
520 | if (!encoder) { | | |||
521 | continue; | | |||
522 | } | | |||
523 | for (int j = 0; j < res->count_crtcs; ++j) { | | |||
524 | if (!(encoder->possible_crtcs & (1 << j))) { | | |||
525 | continue; | | |||
526 | } | | |||
527 | if (!crtcIsUsed(res->crtcs[j])) { | | |||
528 | if (ok) { | | |||
529 | *ok = true; | | |||
530 | } | | |||
531 | return res->crtcs[j]; | | |||
532 | } | | |||
533 | } | | |||
534 | } | | |||
535 | return 0; | | |||
536 | } | | |||
537 | | ||||
538 | bool DrmBackend::crtcIsUsed(quint32 crtc) | | |||
539 | { | | |||
540 | auto it = std::find_if(m_outputs.constBegin(), m_outputs.constEnd(), | | |||
541 | [crtc] (DrmOutput *o) { | | |||
542 | return o->m_crtcId == crtc; | | |||
543 | } | | |||
544 | ); | | |||
545 | return it != m_outputs.constEnd(); | | |||
546 | } | | |||
547 | | ||||
548 | void DrmBackend::present(DrmBuffer *buffer, DrmOutput *output) | 546 | void DrmBackend::present(DrmBuffer *buffer, DrmOutput *output) | ||
549 | { | 547 | { | ||
550 | if (output->present(buffer)) { | 548 | if (output->present(buffer)) { | ||
551 | m_pageFlipsPending++; | 549 | m_pageFlipsPending++; | ||
552 | if (m_pageFlipsPending == 1 && Compositor::self()) { | 550 | if (m_pageFlipsPending == 1 && Compositor::self()) { | ||
553 | Compositor::self()->aboutToSwapBuffers(); | 551 | Compositor::self()->aboutToSwapBuffers(); | ||
554 | } | 552 | } | ||
555 | } | 553 | } | ||
▲ Show 20 Lines • Show All 168 Lines • Show Last 20 Lines |
You mean std::erase(std::remove_if(...), ....end()) otherwise you have dangling pointer(s) in conllection