Changeset View
Changeset View
Standalone View
Standalone View
composite.cpp
Show First 20 Lines • Show All 776 Lines • ▼ Show 20 Line(s) | 771 | { | |||
---|---|---|---|---|---|
777 | if (m_bufferSwapPending && m_composeAtSwapCompletion) | 777 | if (m_bufferSwapPending && m_composeAtSwapCompletion) | ||
778 | return; | 778 | return; | ||
779 | 779 | | |||
780 | // Don't start the timer if all outputs are disabled | 780 | // Don't start the timer if all outputs are disabled | ||
781 | if (!kwinApp()->platform()->areOutputsEnabled()) { | 781 | if (!kwinApp()->platform()->areOutputsEnabled()) { | ||
782 | return; | 782 | return; | ||
783 | } | 783 | } | ||
784 | 784 | | |||
785 | uint waitTime = 1; | 785 | uint waitTime = 1000 / refreshRate(); | ||
786 | | ||||
787 | if (m_scene->blocksForRetrace()) { | | |||
788 | | ||||
789 | // TODO: make vBlankTime dynamic?! | | |||
790 | // It's required because glXWaitVideoSync will *likely* block a full frame if one enters | | |||
791 | // a retrace pass which can last a variable amount of time, depending on the actual screen | | |||
792 | // Now, my ooold 19" CRT can do such retrace so that 2ms are entirely sufficient, | | |||
793 | // while another ooold 15" TFT requires about 6ms | | |||
794 | | ||||
795 | qint64 padding = m_timeSinceLastVBlank; | | |||
796 | if (padding > fpsInterval) { | | |||
797 | // We're at low repaints or spent more time in painting than the user wanted to wait | | |||
798 | // for that frame. Align to next vblank: | | |||
799 | padding = vBlankInterval - (padding % vBlankInterval); | | |||
800 | } else { | | |||
801 | // Align to the next maxFps tick: | | |||
802 | // "remaining time of the first vsync" + "time for the other vsyncs of the frame" | | |||
803 | padding = ((vBlankInterval - padding % vBlankInterval) + | | |||
804 | (fpsInterval / vBlankInterval - 1) * vBlankInterval); | | |||
805 | } | | |||
806 | | ||||
807 | if (padding < options->vBlankTime()) { | | |||
808 | // We'll likely miss this frame so we add one: | | |||
809 | waitTime = nanoToMilli(padding + vBlankInterval - options->vBlankTime()); | | |||
810 | } else { | | |||
811 | waitTime = nanoToMilli(padding - options->vBlankTime()); | | |||
812 | } | | |||
zzag: I think we still need some of this code. Syncing to vblank will be a problem though. | |||||
813 | } | | |||
814 | else { // w/o blocking vsync we just jump to the next demanded tick | | |||
815 | if (fpsInterval > m_timeSinceLastVBlank) { | | |||
816 | waitTime = nanoToMilli(fpsInterval - m_timeSinceLastVBlank); | | |||
817 | if (!waitTime) { | | |||
818 | // Will ensure we don't block out the eventloop - the system's just not faster ... | | |||
819 | waitTime = 1; | | |||
820 | } | | |||
821 | } | | |||
822 | /* else if (m_timeSinceLastVBlank - fpsInterval < (vBlankInterval<<1)) { | | |||
823 | // NOTICE - "for later" ------------------------------------------------------------------ | | |||
824 | // It can happen that we push two frames within one refresh cycle. | | |||
825 | // Swapping will then block even with triple buffering when the GPU does not discard but | | |||
826 | // queues frames | | |||
827 | // now here's the mean part: if we take that as "OMG, we're late - next frame ASAP", | | |||
828 | // there'll immediately be 2 frames in the pipe, swapping will block, we think we're | | |||
829 | // late ... ewww | | |||
830 | // so instead we pad to the clock again and add 2ms safety to ensure the pipe is really | | |||
831 | // free | | |||
832 | // NOTICE: obviously m_timeSinceLastVBlank can be too big because we're too slow as well | | |||
833 | // So if this code was enabled, we'd needlessly half the framerate once more (15 instead of 30) | | |||
834 | waitTime = nanoToMilli(vBlankInterval - (m_timeSinceLastVBlank - fpsInterval)%vBlankInterval) + 2; | | |||
835 | }*/ | | |||
836 | else { | | |||
837 | // "0" would be sufficient here, but the compositor isn't the WMs only task. | | |||
838 | waitTime = 1; | | |||
839 | } | | |||
840 | } | | |||
841 | // Force 4fps minimum: | 786 | // Force 4fps minimum: | ||
842 | compositeTimer.start(qMin(waitTime, 250u), this); | 787 | compositeTimer.start(qMin(waitTime, 250u), this); | ||
843 | } | 788 | } | ||
844 | 789 | | |||
845 | bool Compositor::isActive() | 790 | bool Compositor::isActive() | ||
846 | { | 791 | { | ||
847 | return m_state == State::On; | 792 | return m_state == State::On; | ||
848 | } | 793 | } | ||
Show All 12 Lines | |||||
861 | 806 | | |||
862 | void WaylandCompositor::start() | 807 | void WaylandCompositor::start() | ||
863 | { | 808 | { | ||
864 | if (!Compositor::setupStart()) { | 809 | if (!Compositor::setupStart()) { | ||
865 | // Internal setup failed, abort. | 810 | // Internal setup failed, abort. | ||
866 | return; | 811 | return; | ||
867 | } | 812 | } | ||
868 | 813 | | |||
814 | // TODO: This is problematic on Wayland. We should get the highest refresh rate | ||||
815 | // and not the one of the first output. Also on hotplug reevaluate. | ||||
816 | // On X11 do it also like this? | ||||
817 | m_refreshRate = KWin::currentRefreshRate(); | ||||
818 | | ||||
869 | if (Workspace::self()) { | 819 | if (Workspace::self()) { | ||
870 | startupWithWorkspace(); | 820 | startupWithWorkspace(); | ||
871 | } else { | 821 | } else { | ||
872 | connect(kwinApp(), &Application::workspaceCreated, | 822 | connect(kwinApp(), &Application::workspaceCreated, | ||
873 | this, &WaylandCompositor::startupWithWorkspace); | 823 | this, &WaylandCompositor::startupWithWorkspace); | ||
874 | } | 824 | } | ||
875 | } | 825 | } | ||
876 | 826 | | |||
877 | int WaylandCompositor::refreshRate() const | 827 | int WaylandCompositor::refreshRate() const | ||
878 | { | 828 | { | ||
879 | // TODO: This makes no sense on Wayland. First step would be to atleast | 829 | return m_refreshRate; | ||
880 | // set the refresh rate to the highest available one. Second step | | |||
881 | // would be to not use a uniform value at all but per screen. | | |||
882 | return KWin::currentRefreshRate(); | | |||
883 | } | 830 | } | ||
884 | 831 | | |||
885 | X11Compositor::X11Compositor(QObject *parent) | 832 | X11Compositor::X11Compositor(QObject *parent) | ||
886 | : Compositor(parent) | 833 | : Compositor(parent) | ||
887 | , m_suspended(options->isUseCompositing() ? NoReasonSuspend : UserSuspend) | 834 | , m_suspended(options->isUseCompositing() ? NoReasonSuspend : UserSuspend) | ||
888 | , m_xrrRefreshRate(0) | 835 | , m_xrrRefreshRate(0) | ||
889 | { | 836 | { | ||
890 | qRegisterMetaType<X11Compositor::SuspendReason>("X11Compositor::SuspendReason"); | 837 | qRegisterMetaType<X11Compositor::SuspendReason>("X11Compositor::SuspendReason"); | ||
▲ Show 20 Lines • Show All 160 Lines • Show Last 20 Lines |
I think we still need some of this code. Syncing to vblank will be a problem though.