Loading services/surfaceflinger/Scheduler/LayerHistory.cpp +14 −4 Original line number Original line Diff line number Diff line Loading @@ -280,9 +280,18 @@ void LayerHistory::partitionLayers(nsecs_t now, bool isVrrDevice) { case Layer::FrameRateCompatibility::Exact: case Layer::FrameRateCompatibility::Exact: return LayerVoteType::ExplicitExact; return LayerVoteType::ExplicitExact; case Layer::FrameRateCompatibility::Gte: case Layer::FrameRateCompatibility::Gte: if (isVrrDevice) { return LayerVoteType::ExplicitGte; return LayerVoteType::ExplicitGte; } else { // For MRR, treat GTE votes as Max because it is used for animations and // scroll. MRR cannot change frame rate without jank, so it should // prefer smoothness. return LayerVoteType::Max; } } } }(); }(); const bool isValuelessVote = voteType == LayerVoteType::NoVote || voteType == LayerVoteType::Min || voteType == LayerVoteType::Max; if (FlagManager::getInstance().game_default_frame_rate()) { if (FlagManager::getInstance().game_default_frame_rate()) { // Determine the layer frame rate considering the following priorities: // Determine the layer frame rate considering the following priorities: Loading @@ -307,7 +316,8 @@ void LayerHistory::partitionLayers(nsecs_t now, bool isVrrDevice) { gameModeFrameRateOverride.getIntValue()); gameModeFrameRateOverride.getIntValue()); } } } else if (frameRate.isValid() && frameRate.isVoteValidForMrr(isVrrDevice)) { } else if (frameRate.isValid() && frameRate.isVoteValidForMrr(isVrrDevice)) { info->setLayerVote({setFrameRateVoteType, frameRate.vote.rate, info->setLayerVote({setFrameRateVoteType, isValuelessVote ? 0_Hz : frameRate.vote.rate, frameRate.vote.seamlessness, frameRate.category}); frameRate.vote.seamlessness, frameRate.category}); if (CC_UNLIKELY(mTraceEnabled)) { if (CC_UNLIKELY(mTraceEnabled)) { trace(*info, gameFrameRateOverrideVoteType, trace(*info, gameFrameRateOverrideVoteType, Loading Loading @@ -335,8 +345,8 @@ void LayerHistory::partitionLayers(nsecs_t now, bool isVrrDevice) { } else { } else { if (frameRate.isValid() && frameRate.isVoteValidForMrr(isVrrDevice)) { if (frameRate.isValid() && frameRate.isVoteValidForMrr(isVrrDevice)) { const auto type = info->isVisible() ? voteType : LayerVoteType::NoVote; const auto type = info->isVisible() ? voteType : LayerVoteType::NoVote; info->setLayerVote({type, frameRate.vote.rate, frameRate.vote.seamlessness, info->setLayerVote({type, isValuelessVote ? 0_Hz : frameRate.vote.rate, frameRate.category}); frameRate.vote.seamlessness, frameRate.category}); } else { } else { if (!frameRate.isVoteValidForMrr(isVrrDevice)) { if (!frameRate.isVoteValidForMrr(isVrrDevice)) { ATRACE_FORMAT_INSTANT("Reset layer to ignore explicit vote on MRR %s: %s " ATRACE_FORMAT_INSTANT("Reset layer to ignore explicit vote on MRR %s: %s " Loading services/surfaceflinger/Scheduler/LayerInfo.cpp +19 −2 Original line number Original line Diff line number Diff line Loading @@ -563,8 +563,25 @@ bool LayerInfo::FrameRate::isNoVote() const { return vote.type == FrameRateCompatibility::NoVote; return vote.type == FrameRateCompatibility::NoVote; } } bool LayerInfo::FrameRate::isValuelessType() const { // For a valueless frame rate compatibility (type), the frame rate should be unspecified (0 Hz). if (!isApproxEqual(vote.rate, 0_Hz)) { return false; } switch (vote.type) { case FrameRateCompatibility::Min: case FrameRateCompatibility::NoVote: return true; case FrameRateCompatibility::Default: case FrameRateCompatibility::ExactOrMultiple: case FrameRateCompatibility::Exact: case FrameRateCompatibility::Gte: return false; } } bool LayerInfo::FrameRate::isValid() const { bool LayerInfo::FrameRate::isValid() const { return isNoVote() || vote.rate.isValid() || category != FrameRateCategory::Default; return isValuelessType() || vote.rate.isValid() || category != FrameRateCategory::Default; } } bool LayerInfo::FrameRate::isVoteValidForMrr(bool isVrrDevice) const { bool LayerInfo::FrameRate::isVoteValidForMrr(bool isVrrDevice) const { Loading @@ -572,7 +589,7 @@ bool LayerInfo::FrameRate::isVoteValidForMrr(bool isVrrDevice) const { return true; return true; } } if (category == FrameRateCategory::Default && vote.type != FrameRateCompatibility::Gte) { if (category == FrameRateCategory::Default) { return true; return true; } } Loading services/surfaceflinger/Scheduler/LayerInfo.h +3 −0 Original line number Original line Diff line number Diff line Loading @@ -146,6 +146,9 @@ public: // selection. // selection. bool isNoVote() const; bool isNoVote() const; // Returns true if the FrameRate has a valid valueless (0 Hz) frame rate type. bool isValuelessType() const; // Checks whether the given FrameRate's vote specifications is valid for MRR devices // Checks whether the given FrameRate's vote specifications is valid for MRR devices // given the current flagging. // given the current flagging. bool isVoteValidForMrr(bool isVrrDevice) const; bool isVoteValidForMrr(bool isVrrDevice) const; Loading services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +90 −6 Original line number Original line Diff line number Diff line Loading @@ -46,6 +46,7 @@ namespace android::scheduler { using MockLayer = android::mock::MockLayer; using MockLayer = android::mock::MockLayer; using android::mock::createDisplayMode; using android::mock::createDisplayMode; using android::mock::createVrrDisplayMode; // WARNING: LEGACY TESTS FOR LEGACY FRONT END // WARNING: LEGACY TESTS FOR LEGACY FRONT END // Update LayerHistoryIntegrationTest instead // Update LayerHistoryIntegrationTest instead Loading Loading @@ -138,11 +139,13 @@ protected: ASSERT_EQ(desiredRefreshRate, summary[0].desiredRefreshRate); ASSERT_EQ(desiredRefreshRate, summary[0].desiredRefreshRate); } } std::shared_ptr<RefreshRateSelector> mSelector = static constexpr auto kVrrModeId = DisplayModeId(2); std::make_shared<RefreshRateSelector>(makeModes(createDisplayMode(DisplayModeId(0), std::shared_ptr<RefreshRateSelector> mSelector = std::make_shared<RefreshRateSelector>( LO_FPS), makeModes(createDisplayMode(DisplayModeId(0), LO_FPS), createDisplayMode(DisplayModeId(1), createDisplayMode(DisplayModeId(1), HI_FPS), HI_FPS)), createVrrDisplayMode(kVrrModeId, HI_FPS, hal::VrrConfig{.minFrameIntervalNs = HI_FPS.getPeriodNsecs()})), DisplayModeId(0)); DisplayModeId(0)); mock::SchedulerCallback mSchedulerCallback; mock::SchedulerCallback mSchedulerCallback; Loading Loading @@ -548,6 +551,87 @@ TEST_F(LayerHistoryTest, oneLayerExplicitExactVote) { EXPECT_EQ(0, frequentLayerCount(time)); EXPECT_EQ(0, frequentLayerCount(time)); } } TEST_F(LayerHistoryTest, oneLayerExplicitGte_vrr) { // Set the test to be on a vrr mode. SET_FLAG_FOR_TEST(flags::vrr_config, true); mSelector->setActiveMode(kVrrModeId, HI_FPS); auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameRateForLayerTree()) .WillRepeatedly(Return(Layer::FrameRate(33_Hz, Layer::FrameRateCompatibility::Gte, Seamlessness::OnlySeamless, FrameRateCategory::Default))); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); nsecs_t time = systemTime(); for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; } ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitGte, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(33_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory); // layer became inactive, but the vote stays setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic); time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitGte, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(33_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory); } // Test for MRR device with VRR features enabled. TEST_F(LayerHistoryTest, oneLayerExplicitGte_nonVrr) { SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, true); // The vrr_config flag is explicitly not set false because this test for an MRR device // should still work in a VRR-capable world. auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameRateForLayerTree()) .WillRepeatedly(Return(Layer::FrameRate(33_Hz, Layer::FrameRateCompatibility::Gte, Seamlessness::OnlySeamless, FrameRateCategory::Default))); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); nsecs_t time = systemTime(); for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; } ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory); // layer became infrequent, but the vote stays setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic); time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory); } TEST_F(LayerHistoryTest, oneLayerExplicitVoteWithCategory_vrrFeatureOff) { TEST_F(LayerHistoryTest, oneLayerExplicitVoteWithCategory_vrrFeatureOff) { SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, false); SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, false); Loading Loading
services/surfaceflinger/Scheduler/LayerHistory.cpp +14 −4 Original line number Original line Diff line number Diff line Loading @@ -280,9 +280,18 @@ void LayerHistory::partitionLayers(nsecs_t now, bool isVrrDevice) { case Layer::FrameRateCompatibility::Exact: case Layer::FrameRateCompatibility::Exact: return LayerVoteType::ExplicitExact; return LayerVoteType::ExplicitExact; case Layer::FrameRateCompatibility::Gte: case Layer::FrameRateCompatibility::Gte: if (isVrrDevice) { return LayerVoteType::ExplicitGte; return LayerVoteType::ExplicitGte; } else { // For MRR, treat GTE votes as Max because it is used for animations and // scroll. MRR cannot change frame rate without jank, so it should // prefer smoothness. return LayerVoteType::Max; } } } }(); }(); const bool isValuelessVote = voteType == LayerVoteType::NoVote || voteType == LayerVoteType::Min || voteType == LayerVoteType::Max; if (FlagManager::getInstance().game_default_frame_rate()) { if (FlagManager::getInstance().game_default_frame_rate()) { // Determine the layer frame rate considering the following priorities: // Determine the layer frame rate considering the following priorities: Loading @@ -307,7 +316,8 @@ void LayerHistory::partitionLayers(nsecs_t now, bool isVrrDevice) { gameModeFrameRateOverride.getIntValue()); gameModeFrameRateOverride.getIntValue()); } } } else if (frameRate.isValid() && frameRate.isVoteValidForMrr(isVrrDevice)) { } else if (frameRate.isValid() && frameRate.isVoteValidForMrr(isVrrDevice)) { info->setLayerVote({setFrameRateVoteType, frameRate.vote.rate, info->setLayerVote({setFrameRateVoteType, isValuelessVote ? 0_Hz : frameRate.vote.rate, frameRate.vote.seamlessness, frameRate.category}); frameRate.vote.seamlessness, frameRate.category}); if (CC_UNLIKELY(mTraceEnabled)) { if (CC_UNLIKELY(mTraceEnabled)) { trace(*info, gameFrameRateOverrideVoteType, trace(*info, gameFrameRateOverrideVoteType, Loading Loading @@ -335,8 +345,8 @@ void LayerHistory::partitionLayers(nsecs_t now, bool isVrrDevice) { } else { } else { if (frameRate.isValid() && frameRate.isVoteValidForMrr(isVrrDevice)) { if (frameRate.isValid() && frameRate.isVoteValidForMrr(isVrrDevice)) { const auto type = info->isVisible() ? voteType : LayerVoteType::NoVote; const auto type = info->isVisible() ? voteType : LayerVoteType::NoVote; info->setLayerVote({type, frameRate.vote.rate, frameRate.vote.seamlessness, info->setLayerVote({type, isValuelessVote ? 0_Hz : frameRate.vote.rate, frameRate.category}); frameRate.vote.seamlessness, frameRate.category}); } else { } else { if (!frameRate.isVoteValidForMrr(isVrrDevice)) { if (!frameRate.isVoteValidForMrr(isVrrDevice)) { ATRACE_FORMAT_INSTANT("Reset layer to ignore explicit vote on MRR %s: %s " ATRACE_FORMAT_INSTANT("Reset layer to ignore explicit vote on MRR %s: %s " Loading
services/surfaceflinger/Scheduler/LayerInfo.cpp +19 −2 Original line number Original line Diff line number Diff line Loading @@ -563,8 +563,25 @@ bool LayerInfo::FrameRate::isNoVote() const { return vote.type == FrameRateCompatibility::NoVote; return vote.type == FrameRateCompatibility::NoVote; } } bool LayerInfo::FrameRate::isValuelessType() const { // For a valueless frame rate compatibility (type), the frame rate should be unspecified (0 Hz). if (!isApproxEqual(vote.rate, 0_Hz)) { return false; } switch (vote.type) { case FrameRateCompatibility::Min: case FrameRateCompatibility::NoVote: return true; case FrameRateCompatibility::Default: case FrameRateCompatibility::ExactOrMultiple: case FrameRateCompatibility::Exact: case FrameRateCompatibility::Gte: return false; } } bool LayerInfo::FrameRate::isValid() const { bool LayerInfo::FrameRate::isValid() const { return isNoVote() || vote.rate.isValid() || category != FrameRateCategory::Default; return isValuelessType() || vote.rate.isValid() || category != FrameRateCategory::Default; } } bool LayerInfo::FrameRate::isVoteValidForMrr(bool isVrrDevice) const { bool LayerInfo::FrameRate::isVoteValidForMrr(bool isVrrDevice) const { Loading @@ -572,7 +589,7 @@ bool LayerInfo::FrameRate::isVoteValidForMrr(bool isVrrDevice) const { return true; return true; } } if (category == FrameRateCategory::Default && vote.type != FrameRateCompatibility::Gte) { if (category == FrameRateCategory::Default) { return true; return true; } } Loading
services/surfaceflinger/Scheduler/LayerInfo.h +3 −0 Original line number Original line Diff line number Diff line Loading @@ -146,6 +146,9 @@ public: // selection. // selection. bool isNoVote() const; bool isNoVote() const; // Returns true if the FrameRate has a valid valueless (0 Hz) frame rate type. bool isValuelessType() const; // Checks whether the given FrameRate's vote specifications is valid for MRR devices // Checks whether the given FrameRate's vote specifications is valid for MRR devices // given the current flagging. // given the current flagging. bool isVoteValidForMrr(bool isVrrDevice) const; bool isVoteValidForMrr(bool isVrrDevice) const; Loading
services/surfaceflinger/tests/unittests/LayerHistoryTest.cpp +90 −6 Original line number Original line Diff line number Diff line Loading @@ -46,6 +46,7 @@ namespace android::scheduler { using MockLayer = android::mock::MockLayer; using MockLayer = android::mock::MockLayer; using android::mock::createDisplayMode; using android::mock::createDisplayMode; using android::mock::createVrrDisplayMode; // WARNING: LEGACY TESTS FOR LEGACY FRONT END // WARNING: LEGACY TESTS FOR LEGACY FRONT END // Update LayerHistoryIntegrationTest instead // Update LayerHistoryIntegrationTest instead Loading Loading @@ -138,11 +139,13 @@ protected: ASSERT_EQ(desiredRefreshRate, summary[0].desiredRefreshRate); ASSERT_EQ(desiredRefreshRate, summary[0].desiredRefreshRate); } } std::shared_ptr<RefreshRateSelector> mSelector = static constexpr auto kVrrModeId = DisplayModeId(2); std::make_shared<RefreshRateSelector>(makeModes(createDisplayMode(DisplayModeId(0), std::shared_ptr<RefreshRateSelector> mSelector = std::make_shared<RefreshRateSelector>( LO_FPS), makeModes(createDisplayMode(DisplayModeId(0), LO_FPS), createDisplayMode(DisplayModeId(1), createDisplayMode(DisplayModeId(1), HI_FPS), HI_FPS)), createVrrDisplayMode(kVrrModeId, HI_FPS, hal::VrrConfig{.minFrameIntervalNs = HI_FPS.getPeriodNsecs()})), DisplayModeId(0)); DisplayModeId(0)); mock::SchedulerCallback mSchedulerCallback; mock::SchedulerCallback mSchedulerCallback; Loading Loading @@ -548,6 +551,87 @@ TEST_F(LayerHistoryTest, oneLayerExplicitExactVote) { EXPECT_EQ(0, frequentLayerCount(time)); EXPECT_EQ(0, frequentLayerCount(time)); } } TEST_F(LayerHistoryTest, oneLayerExplicitGte_vrr) { // Set the test to be on a vrr mode. SET_FLAG_FOR_TEST(flags::vrr_config, true); mSelector->setActiveMode(kVrrModeId, HI_FPS); auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameRateForLayerTree()) .WillRepeatedly(Return(Layer::FrameRate(33_Hz, Layer::FrameRateCompatibility::Gte, Seamlessness::OnlySeamless, FrameRateCategory::Default))); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); nsecs_t time = systemTime(); for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; } ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitGte, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(33_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory); // layer became inactive, but the vote stays setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic); time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); EXPECT_EQ(LayerHistory::LayerVoteType::ExplicitGte, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(33_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory); } // Test for MRR device with VRR features enabled. TEST_F(LayerHistoryTest, oneLayerExplicitGte_nonVrr) { SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, true); // The vrr_config flag is explicitly not set false because this test for an MRR device // should still work in a VRR-capable world. auto layer = createLayer(); EXPECT_CALL(*layer, isVisible()).WillRepeatedly(Return(true)); EXPECT_CALL(*layer, getFrameRateForLayerTree()) .WillRepeatedly(Return(Layer::FrameRate(33_Hz, Layer::FrameRateCompatibility::Gte, Seamlessness::OnlySeamless, FrameRateCategory::Default))); EXPECT_EQ(1, layerCount()); EXPECT_EQ(0, activeLayerCount()); nsecs_t time = systemTime(); for (int i = 0; i < PRESENT_TIME_HISTORY_SIZE; i++) { history().record(layer->getSequence(), layer->getLayerProps(), time, time, LayerHistory::LayerUpdateType::Buffer); time += HI_FPS_PERIOD; } ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(1, frequentLayerCount(time)); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory); // layer became infrequent, but the vote stays setDefaultLayerVote(layer.get(), LayerHistory::LayerVoteType::Heuristic); time += MAX_ACTIVE_LAYER_PERIOD_NS.count(); ASSERT_EQ(1, summarizeLayerHistory(time).size()); EXPECT_EQ(1, activeLayerCount()); EXPECT_EQ(0, frequentLayerCount(time)); EXPECT_EQ(LayerHistory::LayerVoteType::Max, summarizeLayerHistory(time)[0].vote); EXPECT_EQ(0_Hz, summarizeLayerHistory(time)[0].desiredRefreshRate); EXPECT_EQ(FrameRateCategory::Default, summarizeLayerHistory(time)[0].frameRateCategory); } TEST_F(LayerHistoryTest, oneLayerExplicitVoteWithCategory_vrrFeatureOff) { TEST_F(LayerHistoryTest, oneLayerExplicitVoteWithCategory_vrrFeatureOff) { SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, false); SET_FLAG_FOR_TEST(flags::frame_rate_category_mrr, false); Loading