Update FrameInterval using next vsync generated
use the expectedPresentTime + threshold to get
the next frames interval.
Test: atrace and atest libsurfaceflinger_unittest --test-filter="SchedulerTest*"
BUG: 296636176
Change-Id: I9eb0d2784a81491028ec13d579356da2f34b85df
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 26c0d67..10df216 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -545,6 +545,7 @@
}
}
+ ATRACE_FORMAT("NextFrameInterval %d_Hz", frameInterval.getIntValue());
if (canSkipValidate) {
sp<Fence> outPresentFence = Fence::NO_FENCE;
uint32_t state = UINT32_MAX;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 6437b4e..1b51c86 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -579,6 +579,24 @@
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);
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index 0615b31..0f2364e 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -312,6 +312,9 @@
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);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 6e6229a..f219942 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -2619,10 +2619,6 @@
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);
@@ -2687,8 +2683,11 @@
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
diff --git a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
index b5eb777..d46f9fc 100644
--- a/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
+++ b/services/surfaceflinger/tests/unittests/SchedulerTest.cpp
@@ -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>
@@ -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"
@@ -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;
@@ -503,6 +509,60 @@
EXPECT_EQ(makeVsyncIds(VsyncId(43)), compositor.vsyncIds);
}
+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,
diff --git a/services/surfaceflinger/tests/unittests/TestableScheduler.h b/services/surfaceflinger/tests/unittests/TestableScheduler.h
index 8b6f0f1..b036e99 100644
--- a/services/surfaceflinger/tests/unittests/TestableScheduler.h
+++ b/services/surfaceflinger/tests/unittests/TestableScheduler.h
@@ -78,10 +78,11 @@
auto refreshRateSelector() { return pacesetterSelectorPtr(); }
- void registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr) {
+ void registerDisplay(
+ PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr,
+ std::shared_ptr<VSyncTracker> vsyncTracker = std::make_shared<mock::VSyncTracker>()) {
registerDisplay(displayId, std::move(selectorPtr),
- std::make_unique<mock::VsyncController>(),
- std::make_shared<mock::VSyncTracker>());
+ std::make_unique<mock::VsyncController>(), vsyncTracker);
}
void registerDisplay(PhysicalDisplayId displayId, RefreshRateSelectorPtr selectorPtr,