SurfaceFlinger: refresh rate calculation when no timestamps

Frames without presentation timestamp should be excluded from refresh
rate calculation. This changes skips these frames instead of just
declaring refresh rate unknown. This impacts scenarios that we get few
frames without presentation timestamps where the majority does include
them.

Bug: 155710271
Test: Facebook feed videos
Change-Id: Id79f4d6cb87b2fd6fb787fab2d863f50be99cac5
This commit is contained in:
Ady Abraham 2020-05-07 16:51:02 -07:00
parent 4264917141
commit 38601a9beb
2 changed files with 51 additions and 3 deletions

View file

@ -111,21 +111,28 @@ std::optional<float> LayerInfoV2::calculateRefreshRateIfPossible() {
// Calculate the refresh rate by finding the average delta between frames
nsecs_t totalPresentTimeDeltas = 0;
int numFrames = 0;
for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
// If there are no presentation timestamp provided we can't calculate the refresh rate
if (it->presetTime == 0 || (it + 1)->presetTime == 0) {
return std::nullopt;
continue;
}
totalPresentTimeDeltas +=
std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod);
numFrames++;
}
const float averageFrameTime =
static_cast<float>(totalPresentTimeDeltas) / (mFrameTimes.size() - 1);
if (numFrames == 0) {
return std::nullopt;
}
const float averageFrameTime = static_cast<float>(totalPresentTimeDeltas) / numFrames;
// Now once we calculated the refresh rate we need to make sure that all the frames we captured
// are evenly distributed and we don't calculate the average across some burst of frames.
for (auto it = mFrameTimes.begin(); it != mFrameTimes.end() - 1; ++it) {
if (it->presetTime == 0 || (it + 1)->presetTime == 0) {
continue;
}
const nsecs_t presentTimeDeltas =
std::max(((it + 1)->presetTime - it->presetTime), mHighRefreshRatePeriod);
if (std::abs(presentTimeDeltas - averageFrameTime) > 2 * averageFrameTime) {

View file

@ -512,5 +512,46 @@ TEST_F(LayerHistoryTestV2, inactiveLayers) {
EXPECT_EQ(1, frequentLayerCount(time));
}
TEST_F(LayerHistoryTestV2, calculateRefreshRate30Hz) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
nsecs_t time = systemTime();
const nsecs_t frameTime = 33'333'333;
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
time += frameTime;
history().record(layer.get(), time, time);
}
ASSERT_EQ(1, history().summarize(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[0].vote);
EXPECT_FLOAT_EQ(30.f, history().summarize(time)[0].desiredRefreshRate);
}
TEST_F(LayerHistoryTestV2, calculateRefreshRate30HzSkipTimestamp) {
const auto layer = createLayer();
EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true));
EXPECT_CALL(*layer, getFrameRateForLayerTree()).WillRepeatedly(Return(Layer::FrameRate()));
EXPECT_EQ(1, layerCount());
EXPECT_EQ(0, activeLayerCount());
nsecs_t time = systemTime();
const nsecs_t frameTime = 33'333'333;
for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) {
time += frameTime;
const auto timestamp = (i == PRESENT_TIME_HISTORY_SIZE / 2) ? 0 : time;
history().record(layer.get(), timestamp, time);
}
ASSERT_EQ(1, history().summarize(time).size());
EXPECT_EQ(LayerHistory::LayerVoteType::Heuristic, history().summarize(time)[0].vote);
EXPECT_FLOAT_EQ(30.f, history().summarize(time)[0].desiredRefreshRate);
}
} // namespace
} // namespace android::scheduler