Loading services/surfaceflinger/DisplayHardware/HWComposer.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -545,6 +545,7 @@ status_t HWComposer::getDeviceCompositionChanges( } } ATRACE_FORMAT("NextFrameInterval %d_Hz", frameInterval.getIntValue()); if (canSkipValidate) { sp<Fence> outPresentFence = Fence::NO_FENCE; uint32_t state = UINT32_MAX; Loading services/surfaceflinger/Scheduler/Scheduler.cpp +18 −0 Original line number Diff line number Diff line Loading @@ -579,6 +579,24 @@ void Scheduler::setRenderRate(PhysicalDisplayId id, Fps renderFrameRate) { display.schedulePtr->getTracker().setRenderRate(renderFrameRate); } Fps Scheduler::getNextFrameInterval(PhysicalDisplayId id, TimePoint currentExpectedPresentTime) const { std::scoped_lock lock(mDisplayLock); ftl::FakeGuard guard(kMainThreadContext); const auto displayOpt = mDisplays.get(id); if (!displayOpt) { ALOGW("%s: Invalid display %s!", __func__, to_string(id).c_str()); return Fps{}; } const Display& display = *displayOpt; const nsecs_t threshold = display.selectorPtr->getActiveMode().modePtr->getVsyncRate().getPeriodNsecs() / 2; const nsecs_t nextVsyncTime = display.schedulePtr->getTracker().nextAnticipatedVSyncTimeFrom( currentExpectedPresentTime.ns() + threshold); return Fps::fromPeriodNsecs(nextVsyncTime - currentExpectedPresentTime.ns()); } void Scheduler::resync() { static constexpr nsecs_t kIgnoreDelay = ms2ns(750); Loading services/surfaceflinger/Scheduler/Scheduler.h +3 −0 Original line number Diff line number Diff line Loading @@ -313,6 +313,9 @@ public: return pacesetterSelectorPtr()->getActiveMode().fps; } Fps getNextFrameInterval(PhysicalDisplayId, TimePoint currentExpectedPresentTime) const EXCLUDES(mDisplayLock); // Returns the framerate of the layer with the given sequence ID float getLayerFramerate(nsecs_t now, int32_t id) const { return mLayerHistory.getLayerFramerate(now, id); Loading services/surfaceflinger/SurfaceFlinger.cpp +4 −5 Original line number Diff line number Diff line Loading @@ -2619,10 +2619,6 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( refreshArgs.outputs.push_back(display->getCompositionDisplay()); } } if (display->getId() == pacesetterId) { // TODO(b/255601557) Update frameInterval per display refreshArgs.frameInterval = display->refreshRateSelector().getActiveMode().fps; } } mPowerAdvisor->setDisplays(displayIds); Loading Loading @@ -2687,8 +2683,11 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( pacesetterTarget.previousFrameVsyncTime(minFramePeriod) - hwcMinWorkDuration; } const TimePoint expectedPresentTime = pacesetterTarget.expectedPresentTime(); // TODO(b/255601557) Update frameInterval per display refreshArgs.frameInterval = mScheduler->getNextFrameInterval(pacesetterId, expectedPresentTime); refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime(); refreshArgs.expectedPresentTime = pacesetterTarget.expectedPresentTime().ns(); refreshArgs.expectedPresentTime = expectedPresentTime.ns(); refreshArgs.hasTrustedPresentationListener = mNumTrustedPresentationListeners > 0; // Store the present time just before calling to the composition engine so we could notify Loading services/surfaceflinger/tests/unittests/SchedulerTest.cpp +60 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ * limitations under the License. */ #include <common/test/FlagUtils.h> #include <ftl/fake_guard.h> #include <gmock/gmock.h> #include <gtest/gtest.h> Loading @@ -23,6 +24,7 @@ #include "Scheduler/EventThread.h" #include "Scheduler/RefreshRateSelector.h" #include "Scheduler/VSyncPredictor.h" #include "TestableScheduler.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockDisplayMode.h" Loading @@ -32,11 +34,15 @@ #include <FrontEnd/LayerHierarchy.h> #include <com_android_graphics_surfaceflinger_flags.h> #include "FpsOps.h" using namespace com::android::graphics::surfaceflinger; namespace android::scheduler { using android::mock::createDisplayMode; using android::mock::createVrrDisplayMode; using testing::_; using testing::Return; Loading Loading @@ -548,6 +554,60 @@ TEST_F(SchedulerTest, onFrameSignalMultipleDisplays) { EXPECT_EQ(makeVsyncIds(VsyncId(44), true), compositor.vsyncIds.composite); } TEST_F(SchedulerTest, nextFrameIntervalTest) { SET_FLAG_FOR_TEST(flags::vrr_config, true); static constexpr size_t kHistorySize = 10; static constexpr size_t kMinimumSamplesForPrediction = 6; static constexpr size_t kOutlierTolerancePercent = 25; const auto refreshRate = Fps::fromPeriodNsecs(500); auto frameRate = Fps::fromPeriodNsecs(1000); const ftl::NonNull<DisplayModePtr> kMode = ftl::as_non_null( createVrrDisplayMode(DisplayModeId(0), refreshRate, hal::VrrConfig{.minFrameIntervalNs = static_cast<int32_t>( frameRate.getPeriodNsecs())})); std::shared_ptr<VSyncPredictor> vrrTracker = std::make_shared<VSyncPredictor>(kMode, kHistorySize, kMinimumSamplesForPrediction, kOutlierTolerancePercent, mVsyncTrackerCallback); std::shared_ptr<RefreshRateSelector> vrrSelectorPtr = std::make_shared<RefreshRateSelector>(makeModes(kMode), kMode->getId()); TestableScheduler scheduler{std::make_unique<android::mock::VsyncController>(), vrrTracker, vrrSelectorPtr, sp<VsyncModulator>::make(VsyncConfigSet{}), mSchedulerCallback, mVsyncTrackerCallback}; scheduler.registerDisplay(kMode->getPhysicalDisplayId(), vrrSelectorPtr, vrrTracker); vrrSelectorPtr->setActiveMode(kMode->getId(), frameRate); scheduler.setRenderRate(kMode->getPhysicalDisplayId(), frameRate); vrrTracker->addVsyncTimestamp(0); // Next frame at refresh rate as no previous frame EXPECT_EQ(refreshRate, scheduler.getNextFrameInterval(kMode->getPhysicalDisplayId(), TimePoint::fromNs(0))); EXPECT_EQ(Fps::fromPeriodNsecs(1000), scheduler.getNextFrameInterval(kMode->getPhysicalDisplayId(), TimePoint::fromNs(500))); EXPECT_EQ(Fps::fromPeriodNsecs(1000), scheduler.getNextFrameInterval(kMode->getPhysicalDisplayId(), TimePoint::fromNs(1500))); // Change render rate frameRate = Fps::fromPeriodNsecs(2000); vrrSelectorPtr->setActiveMode(kMode->getId(), frameRate); scheduler.setRenderRate(kMode->getPhysicalDisplayId(), frameRate); EXPECT_EQ(Fps::fromPeriodNsecs(2000), scheduler.getNextFrameInterval(kMode->getPhysicalDisplayId(), TimePoint::fromNs(2500))); EXPECT_EQ(Fps::fromPeriodNsecs(2000), scheduler.getNextFrameInterval(kMode->getPhysicalDisplayId(), TimePoint::fromNs(4500))); } class AttachedChoreographerTest : public SchedulerTest { protected: void frameRateTestScenario(Fps layerFps, int8_t frameRateCompatibility, Fps displayFps, Loading Loading
services/surfaceflinger/DisplayHardware/HWComposer.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -545,6 +545,7 @@ status_t HWComposer::getDeviceCompositionChanges( } } ATRACE_FORMAT("NextFrameInterval %d_Hz", frameInterval.getIntValue()); if (canSkipValidate) { sp<Fence> outPresentFence = Fence::NO_FENCE; uint32_t state = UINT32_MAX; Loading
services/surfaceflinger/Scheduler/Scheduler.cpp +18 −0 Original line number Diff line number Diff line Loading @@ -579,6 +579,24 @@ void Scheduler::setRenderRate(PhysicalDisplayId id, Fps renderFrameRate) { display.schedulePtr->getTracker().setRenderRate(renderFrameRate); } Fps Scheduler::getNextFrameInterval(PhysicalDisplayId id, TimePoint currentExpectedPresentTime) const { std::scoped_lock lock(mDisplayLock); ftl::FakeGuard guard(kMainThreadContext); const auto displayOpt = mDisplays.get(id); if (!displayOpt) { ALOGW("%s: Invalid display %s!", __func__, to_string(id).c_str()); return Fps{}; } const Display& display = *displayOpt; const nsecs_t threshold = display.selectorPtr->getActiveMode().modePtr->getVsyncRate().getPeriodNsecs() / 2; const nsecs_t nextVsyncTime = display.schedulePtr->getTracker().nextAnticipatedVSyncTimeFrom( currentExpectedPresentTime.ns() + threshold); return Fps::fromPeriodNsecs(nextVsyncTime - currentExpectedPresentTime.ns()); } void Scheduler::resync() { static constexpr nsecs_t kIgnoreDelay = ms2ns(750); Loading
services/surfaceflinger/Scheduler/Scheduler.h +3 −0 Original line number Diff line number Diff line Loading @@ -313,6 +313,9 @@ public: return pacesetterSelectorPtr()->getActiveMode().fps; } Fps getNextFrameInterval(PhysicalDisplayId, TimePoint currentExpectedPresentTime) const EXCLUDES(mDisplayLock); // Returns the framerate of the layer with the given sequence ID float getLayerFramerate(nsecs_t now, int32_t id) const { return mLayerHistory.getLayerFramerate(now, id); Loading
services/surfaceflinger/SurfaceFlinger.cpp +4 −5 Original line number Diff line number Diff line Loading @@ -2619,10 +2619,6 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( refreshArgs.outputs.push_back(display->getCompositionDisplay()); } } if (display->getId() == pacesetterId) { // TODO(b/255601557) Update frameInterval per display refreshArgs.frameInterval = display->refreshRateSelector().getActiveMode().fps; } } mPowerAdvisor->setDisplays(displayIds); Loading Loading @@ -2687,8 +2683,11 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( pacesetterTarget.previousFrameVsyncTime(minFramePeriod) - hwcMinWorkDuration; } const TimePoint expectedPresentTime = pacesetterTarget.expectedPresentTime(); // TODO(b/255601557) Update frameInterval per display refreshArgs.frameInterval = mScheduler->getNextFrameInterval(pacesetterId, expectedPresentTime); refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime(); refreshArgs.expectedPresentTime = pacesetterTarget.expectedPresentTime().ns(); refreshArgs.expectedPresentTime = expectedPresentTime.ns(); refreshArgs.hasTrustedPresentationListener = mNumTrustedPresentationListeners > 0; // Store the present time just before calling to the composition engine so we could notify Loading
services/surfaceflinger/tests/unittests/SchedulerTest.cpp +60 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,7 @@ * limitations under the License. */ #include <common/test/FlagUtils.h> #include <ftl/fake_guard.h> #include <gmock/gmock.h> #include <gtest/gtest.h> Loading @@ -23,6 +24,7 @@ #include "Scheduler/EventThread.h" #include "Scheduler/RefreshRateSelector.h" #include "Scheduler/VSyncPredictor.h" #include "TestableScheduler.h" #include "TestableSurfaceFlinger.h" #include "mock/DisplayHardware/MockDisplayMode.h" Loading @@ -32,11 +34,15 @@ #include <FrontEnd/LayerHierarchy.h> #include <com_android_graphics_surfaceflinger_flags.h> #include "FpsOps.h" using namespace com::android::graphics::surfaceflinger; namespace android::scheduler { using android::mock::createDisplayMode; using android::mock::createVrrDisplayMode; using testing::_; using testing::Return; Loading Loading @@ -548,6 +554,60 @@ TEST_F(SchedulerTest, onFrameSignalMultipleDisplays) { EXPECT_EQ(makeVsyncIds(VsyncId(44), true), compositor.vsyncIds.composite); } TEST_F(SchedulerTest, nextFrameIntervalTest) { SET_FLAG_FOR_TEST(flags::vrr_config, true); static constexpr size_t kHistorySize = 10; static constexpr size_t kMinimumSamplesForPrediction = 6; static constexpr size_t kOutlierTolerancePercent = 25; const auto refreshRate = Fps::fromPeriodNsecs(500); auto frameRate = Fps::fromPeriodNsecs(1000); const ftl::NonNull<DisplayModePtr> kMode = ftl::as_non_null( createVrrDisplayMode(DisplayModeId(0), refreshRate, hal::VrrConfig{.minFrameIntervalNs = static_cast<int32_t>( frameRate.getPeriodNsecs())})); std::shared_ptr<VSyncPredictor> vrrTracker = std::make_shared<VSyncPredictor>(kMode, kHistorySize, kMinimumSamplesForPrediction, kOutlierTolerancePercent, mVsyncTrackerCallback); std::shared_ptr<RefreshRateSelector> vrrSelectorPtr = std::make_shared<RefreshRateSelector>(makeModes(kMode), kMode->getId()); TestableScheduler scheduler{std::make_unique<android::mock::VsyncController>(), vrrTracker, vrrSelectorPtr, sp<VsyncModulator>::make(VsyncConfigSet{}), mSchedulerCallback, mVsyncTrackerCallback}; scheduler.registerDisplay(kMode->getPhysicalDisplayId(), vrrSelectorPtr, vrrTracker); vrrSelectorPtr->setActiveMode(kMode->getId(), frameRate); scheduler.setRenderRate(kMode->getPhysicalDisplayId(), frameRate); vrrTracker->addVsyncTimestamp(0); // Next frame at refresh rate as no previous frame EXPECT_EQ(refreshRate, scheduler.getNextFrameInterval(kMode->getPhysicalDisplayId(), TimePoint::fromNs(0))); EXPECT_EQ(Fps::fromPeriodNsecs(1000), scheduler.getNextFrameInterval(kMode->getPhysicalDisplayId(), TimePoint::fromNs(500))); EXPECT_EQ(Fps::fromPeriodNsecs(1000), scheduler.getNextFrameInterval(kMode->getPhysicalDisplayId(), TimePoint::fromNs(1500))); // Change render rate frameRate = Fps::fromPeriodNsecs(2000); vrrSelectorPtr->setActiveMode(kMode->getId(), frameRate); scheduler.setRenderRate(kMode->getPhysicalDisplayId(), frameRate); EXPECT_EQ(Fps::fromPeriodNsecs(2000), scheduler.getNextFrameInterval(kMode->getPhysicalDisplayId(), TimePoint::fromNs(2500))); EXPECT_EQ(Fps::fromPeriodNsecs(2000), scheduler.getNextFrameInterval(kMode->getPhysicalDisplayId(), TimePoint::fromNs(4500))); } class AttachedChoreographerTest : public SchedulerTest { protected: void frameRateTestScenario(Fps layerFps, int8_t frameRateCompatibility, Fps displayFps, Loading