Changeset View
Changeset View
Standalone View
Standalone View
plugins/platforms/drm/drm_output.cpp
Show First 20 Lines • Show All 57 Lines • ▼ Show 20 Line(s) | 56 | DrmOutput::DrmOutput(DrmBackend *backend) | |||
---|---|---|---|---|---|
58 | , m_backend(backend) | 58 | , m_backend(backend) | ||
59 | { | 59 | { | ||
60 | } | 60 | } | ||
61 | 61 | | |||
62 | DrmOutput::~DrmOutput() | 62 | DrmOutput::~DrmOutput() | ||
63 | { | 63 | { | ||
64 | hideCursor(); | 64 | hideCursor(); | ||
65 | m_crtc->blank(); | 65 | m_crtc->blank(); | ||
66 | | ||||
67 | if (m_primaryPlane) { | ||||
68 | // TODO: when having multiple planes, also clean up these | ||||
69 | m_primaryPlane->setOutput(nullptr); | ||||
70 | | ||||
71 | if (m_backend->deleteBufferAfterPageFlip()) { | ||||
72 | delete m_primaryPlane->current(); | ||||
73 | } | ||||
74 | m_primaryPlane->setCurrent(nullptr); | ||||
75 | } | ||||
76 | | ||||
77 | m_crtc->setOutput(nullptr); | ||||
78 | m_conn->setOutput(nullptr); | ||||
79 | | ||||
66 | delete m_waylandOutput.data(); | 80 | delete m_waylandOutput.data(); | ||
67 | delete m_waylandOutputDevice.data(); | 81 | delete m_waylandOutputDevice.data(); | ||
68 | } | 82 | } | ||
69 | 83 | | |||
70 | void DrmOutput::releaseGbm() | 84 | void DrmOutput::releaseGbm() | ||
71 | { | 85 | { | ||
72 | if (DrmBuffer *b = m_crtc->current()) { | 86 | if (DrmBuffer *b = m_crtc->current()) { | ||
73 | b->releaseGbm(); | 87 | b->releaseGbm(); | ||
74 | } | 88 | } | ||
75 | if (m_primaryPlane) { | 89 | if (m_primaryPlane && m_primaryPlane->current()) { | ||
76 | if (m_primaryPlane->current()) { | | |||
77 | m_primaryPlane->current()->releaseGbm(); | 90 | m_primaryPlane->current()->releaseGbm(); | ||
78 | } | 91 | } | ||
79 | } | 92 | } | ||
80 | } | | |||
81 | 93 | | |||
82 | void DrmOutput::hideCursor() | 94 | void DrmOutput::hideCursor() | ||
83 | { | 95 | { | ||
84 | drmModeSetCursor(m_backend->fd(), m_crtc->id(), 0, 0, 0); | 96 | drmModeSetCursor(m_backend->fd(), m_crtc->id(), 0, 0, 0); | ||
85 | } | 97 | } | ||
86 | 98 | | |||
87 | void DrmOutput::showCursor(DrmDumbBuffer *c) | 99 | void DrmOutput::showCursor(DrmDumbBuffer *c) | ||
88 | { | 100 | { | ||
▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Line(s) | |||||
171 | { | 183 | { | ||
172 | initEdid(connector); | 184 | initEdid(connector); | ||
173 | initDpms(connector); | 185 | initDpms(connector); | ||
174 | initUuid(); | 186 | initUuid(); | ||
175 | if (m_backend->atomicModeSetting()) { | 187 | if (m_backend->atomicModeSetting()) { | ||
176 | if (!initPrimaryPlane()) { | 188 | if (!initPrimaryPlane()) { | ||
177 | return false; | 189 | return false; | ||
178 | } | 190 | } | ||
179 | } | 191 | } else if (!m_crtc->blank()) { | ||
180 | if (!m_crtc->blank()) { | | |||
181 | return false; | 192 | return false; | ||
182 | } | 193 | } | ||
194 | | ||||
183 | setDpms(DpmsMode::On); | 195 | setDpms(DpmsMode::On); | ||
184 | if (!m_waylandOutput.isNull()) { | 196 | if (!m_waylandOutput.isNull()) { | ||
185 | delete m_waylandOutput.data(); | 197 | delete m_waylandOutput.data(); | ||
186 | m_waylandOutput.clear(); | 198 | m_waylandOutput.clear(); | ||
187 | } | 199 | } | ||
188 | m_waylandOutput = waylandServer()->display()->createOutput(); | 200 | m_waylandOutput = waylandServer()->display()->createOutput(); | ||
189 | if (!m_waylandOutputDevice.isNull()) { | 201 | if (!m_waylandOutputDevice.isNull()) { | ||
190 | delete m_waylandOutputDevice.data(); | 202 | delete m_waylandOutputDevice.data(); | ||
▲ Show 20 Lines • Show All 300 Lines • ▼ Show 20 Line(s) | 502 | if (p->type() != DrmPlane::TypeIndex::Primary) { | |||
491 | continue; | 503 | continue; | ||
492 | } | 504 | } | ||
493 | if (p->output()) { // Plane already has an output | 505 | if (p->output()) { // Plane already has an output | ||
494 | continue; | 506 | continue; | ||
495 | } | 507 | } | ||
496 | if (m_primaryPlane) { // Output already has a primary plane | 508 | if (m_primaryPlane) { // Output already has a primary plane | ||
497 | continue; | 509 | continue; | ||
498 | } | 510 | } | ||
499 | if (!p->isCrtcSupported(m_crtc->id())) { | 511 | if (!p->isCrtcSupported(m_crtc->resIndex())) { | ||
500 | continue; | 512 | continue; | ||
501 | } | 513 | } | ||
502 | p->setOutput(this); | 514 | p->setOutput(this); | ||
503 | m_primaryPlane = p; | 515 | m_primaryPlane = p; | ||
504 | qCDebug(KWIN_DRM) << "Initialized primary plane" << p->id() << "on CRTC" << m_crtc->id(); | 516 | qCDebug(KWIN_DRM) << "Initialized primary plane" << p->id() << "on CRTC" << m_crtc->id(); | ||
505 | return true; | 517 | return true; | ||
506 | } | 518 | } | ||
507 | qCCritical(KWIN_DRM) << "Failed to initialize primary plane."; | 519 | qCCritical(KWIN_DRM) << "Failed to initialize primary plane."; | ||
Show All 11 Lines | 530 | if (p->type() != DrmPlane::TypeIndex::Cursor) { | |||
519 | continue; | 531 | continue; | ||
520 | } | 532 | } | ||
521 | if (p->output()) { // Plane already has an output | 533 | if (p->output()) { // Plane already has an output | ||
522 | continue; | 534 | continue; | ||
523 | } | 535 | } | ||
524 | if (m_cursorPlane) { // Output already has a cursor plane | 536 | if (m_cursorPlane) { // Output already has a cursor plane | ||
525 | continue; | 537 | continue; | ||
526 | } | 538 | } | ||
527 | if (!p->isCrtcSupported(m_crtc->id())) { | 539 | if (!p->isCrtcSupported(m_crtc->resIndex())) { | ||
528 | continue; | 540 | continue; | ||
529 | } | 541 | } | ||
530 | p->setOutput(this); | 542 | p->setOutput(this); | ||
531 | m_cursorPlane = p; | 543 | m_cursorPlane = p; | ||
532 | qCDebug(KWIN_DRM) << "Initialized cursor plane" << p->id() << "on CRTC" << m_crtc->id(); | 544 | qCDebug(KWIN_DRM) << "Initialized cursor plane" << p->id() << "on CRTC" << m_crtc->id(); | ||
533 | return true; | 545 | return true; | ||
534 | } | 546 | } | ||
535 | return false; | 547 | return false; | ||
Show All 13 Lines | 551 | { | |||
549 | } | 561 | } | ||
550 | } | 562 | } | ||
551 | 563 | | |||
552 | void DrmOutput::setDpms(DrmOutput::DpmsMode mode) | 564 | void DrmOutput::setDpms(DrmOutput::DpmsMode mode) | ||
553 | { | 565 | { | ||
554 | if (m_dpms.isNull()) { | 566 | if (m_dpms.isNull()) { | ||
555 | return; | 567 | return; | ||
556 | } | 568 | } | ||
557 | if (mode == m_dpmsMode) { | 569 | if (mode == m_dpmsModePending) { | ||
558 | qCDebug(KWIN_DRM) << "New DPMS mode equals old mode. DPMS unchanged."; | 570 | qCDebug(KWIN_DRM) << "New DPMS mode equals old mode. DPMS unchanged."; | ||
559 | return; | 571 | return; | ||
560 | } | 572 | } | ||
561 | 573 | | |||
562 | if (m_backend->atomicModeSetting()) { | 574 | m_dpmsModePending = mode; | ||
563 | drmModeAtomicReq *req = drmModeAtomicAlloc(); | | |||
564 | 575 | | |||
565 | if (atomicReqModesetPopulate(req, mode == DpmsMode::On) == DrmObject::AtomicReturn::Error) { | 576 | if (m_backend->atomicModeSetting()) { | ||
566 | qCWarning(KWIN_DRM) << "Failed to populate atomic request for output" << m_crtc->id(); | 577 | m_modesetRequested = true; | ||
567 | return; | 578 | if (mode == DpmsMode::On) { | ||
579 | if (m_pageFlipPending) { | ||||
580 | m_pageFlipPending = false; | ||||
581 | Compositor::self()->bufferSwapComplete(); | ||||
568 | } | 582 | } | ||
569 | if (drmModeAtomicCommit(m_backend->fd(), req, DRM_MODE_ATOMIC_ALLOW_MODESET, this)) { | 583 | dpmsOnHandler(); | ||
570 | qCWarning(KWIN_DRM) << "Failed to commit atomic request for output" << m_crtc->id(); | | |||
571 | } else { | 584 | } else { | ||
572 | qCDebug(KWIN_DRM) << "DPMS set for output" << m_crtc->id(); | 585 | m_dpmsAtomicOffPending = true; | ||
586 | if (!m_pageFlipPending) { | ||||
587 | dpmsAtomicOff(); | ||||
588 | } | ||||
573 | } | 589 | } | ||
574 | drmModeAtomicFree(req); | | |||
575 | } else { | 590 | } else { | ||
576 | if (drmModeConnectorSetProperty(m_backend->fd(), m_conn->id(), m_dpms->prop_id, uint64_t(mode)) < 0) { | 591 | if (drmModeConnectorSetProperty(m_backend->fd(), m_conn->id(), m_dpms->prop_id, uint64_t(mode)) < 0) { | ||
592 | m_dpmsModePending = m_dpmsMode; | ||||
577 | qCWarning(KWIN_DRM) << "Setting DPMS failed"; | 593 | qCWarning(KWIN_DRM) << "Setting DPMS failed"; | ||
578 | return; | 594 | return; | ||
579 | } | 595 | } | ||
596 | if (mode == DpmsMode::On) { | ||||
597 | dpmsOnHandler(); | ||||
598 | } else { | ||||
599 | dpmsOffHandler(); | ||||
600 | } | ||||
601 | m_dpmsMode = m_dpmsModePending; | ||||
602 | } | ||||
580 | } | 603 | } | ||
581 | 604 | | |||
582 | m_dpmsMode = mode; | 605 | void DrmOutput::dpmsOnHandler() | ||
606 | { | ||||
607 | qCDebug(KWIN_DRM) << "DPMS mode set for output" << m_crtc->id() << "to On."; | ||||
608 | | ||||
583 | if (m_waylandOutput) { | 609 | if (m_waylandOutput) { | ||
584 | m_waylandOutput->setDpmsMode(toWaylandDpmsMode(m_dpmsMode)); | 610 | m_waylandOutput->setDpmsMode(toWaylandDpmsMode(m_dpmsModePending)); | ||
585 | } | 611 | } | ||
586 | emit dpmsChanged(); | 612 | emit dpmsChanged(); | ||
587 | if (m_dpmsMode != DpmsMode::On) { | 613 | | ||
588 | m_backend->outputWentOff(); | | |||
589 | } else { | | |||
590 | m_backend->checkOutputsAreOn(); | 614 | m_backend->checkOutputsAreOn(); | ||
615 | if (!m_backend->atomicModeSetting()) { | ||||
591 | m_crtc->blank(); | 616 | m_crtc->blank(); | ||
617 | } | ||||
592 | if (Compositor *compositor = Compositor::self()) { | 618 | if (Compositor *compositor = Compositor::self()) { | ||
593 | compositor->addRepaintFull(); | 619 | compositor->addRepaintFull(); | ||
594 | } | 620 | } | ||
595 | } | 621 | } | ||
622 | | ||||
623 | void DrmOutput::dpmsOffHandler() | ||||
624 | { | ||||
625 | qCDebug(KWIN_DRM) << "DPMS mode set for output" << m_crtc->id() << "to Off."; | ||||
626 | | ||||
627 | if (m_waylandOutput) { | ||||
628 | m_waylandOutput->setDpmsMode(toWaylandDpmsMode(m_dpmsModePending)); | ||||
629 | } | ||||
630 | emit dpmsChanged(); | ||||
631 | | ||||
632 | m_backend->outputWentOff(); | ||||
596 | } | 633 | } | ||
597 | 634 | | |||
598 | QString DrmOutput::name() const | 635 | QString DrmOutput::name() const | ||
599 | { | 636 | { | ||
600 | if (!m_waylandOutput) { | 637 | if (!m_waylandOutput) { | ||
601 | return i18n("unknown"); | 638 | return i18n("unknown"); | ||
602 | } | 639 | } | ||
603 | return QStringLiteral("%1 %2").arg(m_waylandOutput->manufacturer()).arg(m_waylandOutput->model()); | 640 | return QStringLiteral("%1 %2").arg(m_waylandOutput->manufacturer()).arg(m_waylandOutput->model()); | ||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Line(s) | 712 | if (m_changeset->scaleChanged()) { | |||
676 | qCDebug(KWIN_DRM) << "Setting scale:" << m_changeset->scale(); | 713 | qCDebug(KWIN_DRM) << "Setting scale:" << m_changeset->scale(); | ||
677 | setScale(m_changeset->scale()); | 714 | setScale(m_changeset->scale()); | ||
678 | } | 715 | } | ||
679 | return true; | 716 | return true; | ||
680 | } | 717 | } | ||
681 | 718 | | |||
682 | void DrmOutput::pageFlipped() | 719 | void DrmOutput::pageFlipped() | ||
683 | { | 720 | { | ||
721 | m_pageFlipPending = false; | ||||
722 | | ||||
684 | if (!m_crtc) { | 723 | if (!m_crtc) { | ||
685 | return; | 724 | return; | ||
686 | } | 725 | } | ||
726 | // Egl based surface buffers get destroyed, QPainter based dumb buffers not | ||||
727 | // TODO: split up DrmOutput in two for dumb and egl/gbm surface buffer compatible subclasses completely? | ||||
728 | if (m_backend->deleteBufferAfterPageFlip()) { | ||||
687 | if (m_backend->atomicModeSetting()){ | 729 | if (m_backend->atomicModeSetting()) { | ||
688 | foreach (DrmPlane *p, m_planesFlipList) { | 730 | if (!m_primaryPlane->next()) { | ||
689 | pageFlippedBufferRemover(p->current(), p->next()); | 731 | // on manual vt switch | ||
690 | p->setCurrent(p->next()); | 732 | // TODO: when we later use overlay planes it might happen, that we have a page flip with only | ||
691 | p->setNext(nullptr); | 733 | // damage on one of these, and therefore the primary plane has no next buffer | ||
734 | // -> Then we don't want to return here! | ||||
735 | if (m_primaryPlane->current()) { | ||||
736 | m_primaryPlane->current()->releaseGbm(); | ||||
692 | } | 737 | } | ||
693 | m_planesFlipList.clear(); | 738 | return; | ||
694 | 739 | } | |||
740 | for (DrmPlane *p : m_nextPlanesFlipList) { | ||||
741 | p->flipBufferWithDelete(); | ||||
742 | } | ||||
743 | m_nextPlanesFlipList.clear(); | ||||
695 | } else { | 744 | } else { | ||
696 | if (!m_crtc->next()) { | 745 | if (!m_crtc->next()) { | ||
697 | // on manual vt switch | 746 | // on manual vt switch | ||
698 | if (DrmBuffer *b = m_crtc->current()) { | 747 | if (DrmBuffer *b = m_crtc->current()) { | ||
699 | b->releaseGbm(); | 748 | b->releaseGbm(); | ||
700 | } | 749 | } | ||
701 | return; | | |||
702 | } | 750 | } | ||
703 | m_crtc->flipBuffer(); | 751 | m_crtc->flipBuffer(); | ||
704 | } | 752 | } | ||
753 | } else { | ||||
754 | if (m_backend->atomicModeSetting()){ | ||||
755 | for (DrmPlane *p : m_nextPlanesFlipList) { | ||||
756 | p->flipBuffer(); | ||||
705 | } | 757 | } | ||
706 | 758 | m_nextPlanesFlipList.clear(); | |||
707 | void DrmOutput::pageFlippedBufferRemover(DrmBuffer *oldbuffer, DrmBuffer *newbuffer) | 759 | } else { | ||
708 | { | 760 | m_crtc->flipBuffer(); | ||
709 | if (oldbuffer && m_backend->deleteBufferAfterPageFlip() && oldbuffer != newbuffer) { | 761 | } | ||
710 | delete oldbuffer; | 762 | m_crtc->flipBuffer(); | ||
711 | } | 763 | } | ||
712 | } | 764 | } | ||
713 | 765 | | |||
714 | bool DrmOutput::present(DrmBuffer *buffer) | 766 | bool DrmOutput::present(DrmBuffer *buffer) | ||
715 | { | 767 | { | ||
716 | if (!buffer || buffer->bufferId() == 0) { | 768 | if (!buffer || buffer->bufferId() == 0) { | ||
717 | return false; | 769 | return false; | ||
718 | } | 770 | } | ||
719 | if (m_backend->atomicModeSetting()) { | 771 | if (m_backend->atomicModeSetting()) { | ||
720 | return presentAtomically(buffer); | 772 | return presentAtomically(buffer); | ||
721 | } else { | 773 | } else { | ||
722 | return presentLegacy(buffer); | 774 | return presentLegacy(buffer); | ||
723 | } | 775 | } | ||
724 | } | 776 | } | ||
725 | 777 | | |||
726 | bool DrmOutput::presentAtomically(DrmBuffer *buffer) | 778 | bool DrmOutput::dpmsAtomicOff() | ||
727 | { | 779 | { | ||
728 | if (!LogindIntegration::self()->isActiveSession()) { | 780 | m_dpmsAtomicOffPending = false; | ||
729 | qCWarning(KWIN_DRM) << "Logind session not active."; | 781 | | ||
730 | return false; | 782 | // TODO: With multiple planes: deactivate all of them here | ||
731 | } | 783 | delete m_primaryPlane->next(); | ||
732 | if (m_dpmsMode != DpmsMode::On) { | 784 | m_primaryPlane->setNext(nullptr); | ||
733 | qCWarning(KWIN_DRM) << "No present() while screen off."; | 785 | m_nextPlanesFlipList << m_primaryPlane; | ||
786 | | ||||
787 | if (!doAtomicCommit(AtomicCommitMode::Test)) { | ||||
788 | qCDebug(KWIN_DRM) << "Atomic test commit to Dpms Off failed. Aborting."; | ||||
734 | return false; | 789 | return false; | ||
735 | } | 790 | } | ||
736 | if (m_primaryPlane->next()) { | 791 | if (!doAtomicCommit(AtomicCommitMode::Real)) { | ||
737 | qCWarning(KWIN_DRM) << "Page not yet flipped."; | 792 | qCDebug(KWIN_DRM) << "Atomic commit to Dpms Off failed. This should have never happened! Aborting."; | ||
738 | return false; | 793 | return false; | ||
739 | } | 794 | } | ||
795 | m_nextPlanesFlipList.clear(); | ||||
796 | dpmsOffHandler(); | ||||
740 | 797 | | |||
741 | DrmObject::AtomicReturn ret; | 798 | return true; | ||
742 | uint32_t flags = DRM_MODE_ATOMIC_NONBLOCK | DRM_MODE_PAGE_FLIP_EVENT; | | |||
743 | 799 | | |||
744 | // TODO: throwing an exception would be really handy here! (would mean change of compile options) | | |||
745 | drmModeAtomicReq *req = drmModeAtomicAlloc(); | | |||
746 | if (!req) { | | |||
747 | qCWarning(KWIN_DRM) << "DRM: couldn't allocate atomic request"; | | |||
748 | delete buffer; | | |||
749 | return false; | | |||
750 | } | 800 | } | ||
751 | 801 | | |||
752 | // Do we need to set a new mode first? | 802 | bool DrmOutput::presentAtomically(DrmBuffer *buffer) | ||
753 | bool doModeset = !m_primaryPlane->current(); | 803 | { | ||
754 | if (doModeset) { | 804 | if (!LogindIntegration::self()->isActiveSession()) { | ||
755 | qCDebug(KWIN_DRM) << "Atomic Modeset requested"; | 805 | qCWarning(KWIN_DRM) << "Logind session not active."; | ||
756 | | ||||
757 | if (drmModeCreatePropertyBlob(m_backend->fd(), &m_mode, sizeof(m_mode), &m_blobId)) { | | |||
758 | qCWarning(KWIN_DRM) << "Failed to create property blob"; | | |||
759 | delete buffer; | | |||
760 | return false; | 806 | return false; | ||
761 | } | 807 | } | ||
762 | 808 | | |||
763 | ret = atomicReqModesetPopulate(req, true); | 809 | if (m_pageFlipPending) { | ||
764 | if (ret == DrmObject::AtomicReturn::Error){ | 810 | qCWarning(KWIN_DRM) << "Page not yet flipped."; | ||
765 | drmModeAtomicFree(req); | | |||
766 | delete buffer; | | |||
767 | return false; | 811 | return false; | ||
768 | } | 812 | } | ||
769 | if (ret == DrmObject::AtomicReturn::Success) { | | |||
770 | flags |= DRM_MODE_ATOMIC_ALLOW_MODESET; | | |||
771 | } | | |||
772 | } | | |||
773 | 813 | | |||
774 | m_primaryPlane->setNext(buffer); // TODO: Later not only use the primary plane for the buffer! | 814 | m_primaryPlane->setNext(buffer); | ||
775 | // i.e.: Assign planes | 815 | m_nextPlanesFlipList << m_primaryPlane; | ||
776 | bool anyDamage = false; | | |||
777 | foreach (DrmPlane* p, m_backend->planes()){ | | |||
778 | if (p->output() != this) { | | |||
779 | continue; | | |||
780 | } | | |||
781 | ret = p->atomicReqPlanePopulate(req); | | |||
782 | if (ret == DrmObject::AtomicReturn::Error) { | | |||
783 | drmModeAtomicFree(req); | | |||
784 | m_primaryPlane->setNext(nullptr); | | |||
785 | m_planesFlipList.clear(); | | |||
786 | delete buffer; | | |||
787 | return false; | | |||
788 | } | | |||
789 | if (ret == DrmObject::AtomicReturn::Success) { | | |||
790 | anyDamage = true; | | |||
791 | m_planesFlipList << p; | | |||
792 | } | | |||
793 | } | | |||
794 | 816 | | |||
795 | // no damage but force flip for atleast the primary plane anyway | 817 | if (!doAtomicCommit(AtomicCommitMode::Test)) { | ||
796 | if (!anyDamage) { | 818 | //TODO: When we use planes for layered rendering, fallback to renderer instead. Also for direct scanout? | ||
797 | m_primaryPlane->setPropsValid(0); | 819 | qCDebug(KWIN_DRM) << "Atomic test commit failed. Aborting present."; | ||
798 | if (m_primaryPlane->atomicReqPlanePopulate(req) == DrmObject::AtomicReturn::Error) { | 820 | if (this->m_backend->deleteBufferAfterPageFlip()) { | ||
799 | drmModeAtomicFree(req); | | |||
800 | m_primaryPlane->setNext(nullptr); | | |||
801 | m_planesFlipList.clear(); | | |||
802 | delete buffer; | 821 | delete buffer; | ||
803 | return false; | | |||
804 | } | | |||
805 | m_planesFlipList << m_primaryPlane; | | |||
806 | } | 822 | } | ||
807 | | ||||
808 | if (drmModeAtomicCommit(m_backend->fd(), req, flags, this)) { | | |||
809 | qCWarning(KWIN_DRM) << "Atomic request failed to commit:" << strerror(errno); | | |||
810 | drmModeAtomicFree(req); | | |||
811 | m_primaryPlane->setNext(nullptr); | | |||
812 | m_planesFlipList.clear(); | | |||
813 | delete buffer; | | |||
814 | return false; | 823 | return false; | ||
815 | } | 824 | } | ||
816 | 825 | if (!doAtomicCommit(AtomicCommitMode::Real)) { | |||
817 | if (doModeset) { | 826 | qCDebug(KWIN_DRM) << "Atomic commit failed. This should have never happened! Aborting present."; | ||
818 | m_crtc->setPropsValid(m_crtc->propsValid() | m_crtc->propsPending()); | 827 | return false; | ||
819 | m_conn->setPropsValid(m_conn->propsValid() | m_conn->propsPending()); | | |||
820 | } | | |||
821 | foreach (DrmPlane* p, m_planesFlipList) { | | |||
822 | p->setPropsValid(p->propsValid() | p->propsPending()); | | |||
823 | } | 828 | } | ||
824 | 829 | m_pageFlipPending = true; | |||
825 | drmModeAtomicFree(req); | | |||
826 | return true; | 830 | return true; | ||
827 | } | 831 | } | ||
828 | 832 | | |||
829 | | ||||
830 | bool DrmOutput::presentLegacy(DrmBuffer *buffer) | 833 | bool DrmOutput::presentLegacy(DrmBuffer *buffer) | ||
831 | { | 834 | { | ||
832 | if (m_crtc->next()) { | 835 | if (m_crtc->next()) { | ||
833 | return false; | 836 | return false; | ||
834 | } | 837 | } | ||
835 | if (!LogindIntegration::self()->isActiveSession()) { | 838 | if (!LogindIntegration::self()->isActiveSession()) { | ||
836 | m_crtc->setNext(buffer); | 839 | m_crtc->setNext(buffer); | ||
837 | return false; | 840 | return false; | ||
Show All 26 Lines | 865 | { | |||
864 | if (drmModeSetCrtc(m_backend->fd(), m_crtc->id(), buffer->bufferId(), 0, 0, &connId, 1, &m_mode) == 0) { | 867 | if (drmModeSetCrtc(m_backend->fd(), m_crtc->id(), buffer->bufferId(), 0, 0, &connId, 1, &m_mode) == 0) { | ||
865 | return true; | 868 | return true; | ||
866 | } else { | 869 | } else { | ||
867 | qCWarning(KWIN_DRM) << "Mode setting failed"; | 870 | qCWarning(KWIN_DRM) << "Mode setting failed"; | ||
868 | return false; | 871 | return false; | ||
869 | } | 872 | } | ||
870 | } | 873 | } | ||
871 | 874 | | |||
872 | DrmObject::AtomicReturn DrmOutput::atomicReqModesetPopulate(drmModeAtomicReq *req, bool enable) | 875 | bool DrmOutput::doAtomicCommit(AtomicCommitMode mode) | ||
873 | { | 876 | { | ||
874 | if (enable) { | 877 | drmModeAtomicReq *req = drmModeAtomicAlloc(); | ||
875 | m_primaryPlane->setPropValue(int(DrmPlane::PropertyIndex::SrcW), m_mode.hdisplay << 16); | 878 | | ||
876 | m_primaryPlane->setPropValue(int(DrmPlane::PropertyIndex::SrcH), m_mode.vdisplay << 16); | 879 | auto errorHandler = [this, mode, req] () { | ||
877 | m_primaryPlane->setPropValue(int(DrmPlane::PropertyIndex::CrtcW), m_mode.hdisplay); | 880 | if (mode == AtomicCommitMode::Test) { | ||
878 | m_primaryPlane->setPropValue(int(DrmPlane::PropertyIndex::CrtcH), m_mode.vdisplay); | 881 | // TODO: when we later test overlay planes, make sure we change only the right stuff back | ||
879 | } else { | 882 | } | ||
880 | m_primaryPlane->setPropValue(int(DrmPlane::PropertyIndex::SrcW), 0); | 883 | if (req) { | ||
881 | m_primaryPlane->setPropValue(int(DrmPlane::PropertyIndex::SrcH), 0); | 884 | drmModeAtomicFree(req); | ||
882 | m_primaryPlane->setPropValue(int(DrmPlane::PropertyIndex::CrtcW), 0); | | |||
883 | m_primaryPlane->setPropValue(int(DrmPlane::PropertyIndex::CrtcH), 0); | | |||
884 | } | 885 | } | ||
885 | 886 | | |||
886 | bool ret = true; | 887 | if (m_dpmsMode != m_dpmsModePending) { | ||
888 | qCWarning(KWIN_DRM) << "Setting DPMS failed"; | ||||
889 | m_dpmsModePending = m_dpmsMode; | ||||
890 | if (m_dpmsMode != DpmsMode::On) { | ||||
891 | dpmsOffHandler(); | ||||
892 | } | ||||
893 | } | ||||
887 | 894 | | |||
888 | m_crtc->setPropsPending(0); | 895 | // TODO: see above, rework later for overlay planes! | ||
889 | m_conn->setPropsPending(0); | 896 | for (DrmPlane *p : m_nextPlanesFlipList) { | ||
897 | p->setNext(nullptr); | ||||
898 | } | ||||
899 | m_nextPlanesFlipList.clear(); | ||||
890 | 900 | | |||
891 | ret &= m_conn->atomicAddProperty(req, int(DrmConnector::PropertyIndex::CrtcId), enable ? m_crtc->id() : 0); | 901 | }; | ||
892 | ret &= m_crtc->atomicAddProperty(req, int(DrmCrtc::PropertyIndex::ModeId), enable ? m_blobId : 0); | 902 | | ||
893 | ret &= m_crtc->atomicAddProperty(req, int(DrmCrtc::PropertyIndex::Active), enable); | 903 | if (!req) { | ||
904 | qCWarning(KWIN_DRM) << "DRM: couldn't allocate atomic request"; | ||||
905 | errorHandler(); | ||||
906 | return false; | ||||
907 | } | ||||
908 | | ||||
909 | uint32_t flags = 0; | ||||
910 | | ||||
911 | // Do we need to set a new mode? | ||||
912 | if (m_modesetRequested) { | ||||
913 | if (m_dpmsModePending == DpmsMode::On) { | ||||
914 | if (drmModeCreatePropertyBlob(m_backend->fd(), &m_mode, sizeof(m_mode), &m_blobId) != 0) { | ||||
915 | qCWarning(KWIN_DRM) << "Failed to create property blob"; | ||||
916 | errorHandler(); | ||||
917 | return false; | ||||
918 | } | ||||
919 | } | ||||
920 | if (!atomicReqModesetPopulate(req, m_dpmsModePending == DpmsMode::On)){ | ||||
921 | qCWarning(KWIN_DRM) << "Failed to populate Atomic Modeset"; | ||||
922 | errorHandler(); | ||||
923 | return false; | ||||
924 | } | ||||
925 | flags |= DRM_MODE_ATOMIC_ALLOW_MODESET; | ||||
926 | } | ||||
927 | | ||||
928 | if (mode == AtomicCommitMode::Real) { | ||||
929 | if (m_dpmsModePending == DpmsMode::On) { | ||||
930 | if (!(flags & DRM_MODE_ATOMIC_ALLOW_MODESET)) { | ||||
931 | // TODO: Evaluating this condition should only be necessary, as long as we expect older kernels than 4.10. | ||||
932 | flags |= DRM_MODE_ATOMIC_NONBLOCK; | ||||
933 | } | ||||
934 | flags |= DRM_MODE_PAGE_FLIP_EVENT; | ||||
935 | } | ||||
936 | } else { | ||||
937 | flags |= DRM_MODE_ATOMIC_TEST_ONLY; | ||||
938 | } | ||||
939 | | ||||
940 | bool ret = true; | ||||
941 | // TODO: Make sure when we use more than one plane at a time, that we go through this list in the right order. | ||||
942 | for (int i = m_nextPlanesFlipList.size() - 1; 0 <= i; i-- ) { | ||||
943 | DrmPlane *p = m_nextPlanesFlipList[i]; | ||||
944 | ret &= p->atomicPopulate(req); | ||||
945 | } | ||||
894 | 946 | | |||
895 | if (!ret) { | 947 | if (!ret) { | ||
896 | qCWarning(KWIN_DRM) << "Failed to populate atomic modeset"; | 948 | qCWarning(KWIN_DRM) << "Failed to populate atomic planes. Abort atomic commit!"; | ||
897 | return DrmObject::AtomicReturn::Error; | 949 | errorHandler(); | ||
950 | return false; | ||||
898 | } | 951 | } | ||
899 | if (!m_crtc->propsPending() && !m_conn->propsPending()) { | 952 | | ||
900 | return DrmObject::AtomicReturn::NoChange; | 953 | if (drmModeAtomicCommit(m_backend->fd(), req, flags, this)) { | ||
954 | qCWarning(KWIN_DRM) << "Atomic request failed to commit:" << strerror(errno); | ||||
955 | errorHandler(); | ||||
956 | return false; | ||||
957 | } | ||||
958 | | ||||
959 | if (mode == AtomicCommitMode::Real && (flags & DRM_MODE_ATOMIC_ALLOW_MODESET)) { | ||||
960 | qCDebug(KWIN_DRM) << "Atomic Modeset successful."; | ||||
961 | m_modesetRequested = false; | ||||
962 | m_dpmsMode = m_dpmsModePending; | ||||
963 | } | ||||
964 | | ||||
965 | drmModeAtomicFree(req); | ||||
966 | return true; | ||||
901 | } | 967 | } | ||
902 | return DrmObject::AtomicReturn::Success; | 968 | | ||
969 | bool DrmOutput::atomicReqModesetPopulate(drmModeAtomicReq *req, bool enable) | ||||
970 | { | ||||
971 | if (enable) { | ||||
972 | m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::SrcX), 0); | ||||
973 | m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::SrcY), 0); | ||||
974 | m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::SrcW), m_mode.hdisplay << 16); | ||||
975 | m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::SrcH), m_mode.vdisplay << 16); | ||||
976 | m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::CrtcW), m_mode.hdisplay); | ||||
977 | m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::CrtcH), m_mode.vdisplay); | ||||
978 | m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::CrtcId), m_crtc->id()); | ||||
979 | } else { | ||||
980 | if (m_backend->deleteBufferAfterPageFlip()) { | ||||
981 | delete m_primaryPlane->current(); | ||||
982 | delete m_primaryPlane->next(); | ||||
983 | } | ||||
984 | m_primaryPlane->setCurrent(nullptr); | ||||
985 | m_primaryPlane->setNext(nullptr); | ||||
986 | | ||||
987 | m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::SrcX), 0); | ||||
988 | m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::SrcY), 0); | ||||
989 | m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::SrcW), 0); | ||||
990 | m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::SrcH), 0); | ||||
991 | m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::CrtcW), 0); | ||||
992 | m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::CrtcH), 0); | ||||
993 | m_primaryPlane->setValue(int(DrmPlane::PropertyIndex::CrtcId), 0); | ||||
994 | } | ||||
995 | m_conn->setValue(int(DrmConnector::PropertyIndex::CrtcId), enable ? m_crtc->id() : 0); | ||||
996 | m_crtc->setValue(int(DrmCrtc::PropertyIndex::ModeId), enable ? m_blobId : 0); | ||||
997 | m_crtc->setValue(int(DrmCrtc::PropertyIndex::Active), enable); | ||||
998 | | ||||
999 | bool ret = true; | ||||
1000 | ret &= m_conn->atomicPopulate(req); | ||||
1001 | ret &= m_crtc->atomicPopulate(req); | ||||
1002 | | ||||
1003 | return ret; | ||||
903 | } | 1004 | } | ||
904 | 1005 | | |||
905 | } | 1006 | } |