diff options
author | Ram Indani <ramindani@google.com> | 2023-12-14 01:49:53 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2023-12-14 01:49:53 +0000 |
commit | b507b71cc52f9203657f221808eef04d58dd6398 (patch) | |
tree | 97545cb0c6680ddfbf054106babc9bfe618d29c3 /services | |
parent | 749423a1b9055d66fab5b610739ffe252a14f24d (diff) | |
parent | c67d22c8b485dcdd95714fb3e1fed6a3b0d29672 (diff) | |
download | native-b507b71cc52f9203657f221808eef04d58dd6398.tar.gz |
Merge "[SF] Move the notifyExpectedPresentHint call to SF" into main
Diffstat (limited to 'services')
9 files changed, 328 insertions, 277 deletions
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h index 8b736be5e9..9e35717c95 100644 --- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h +++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h @@ -148,8 +148,7 @@ public: MOCK_METHOD(const aidl::android::hardware::graphics::composer3::OverlayProperties&, getOverlaySupport, (), (const, override)); MOCK_METHOD(status_t, setRefreshRateChangedCallbackDebugEnabled, (PhysicalDisplayId, bool)); - MOCK_METHOD(status_t, notifyExpectedPresentIfRequired, - (PhysicalDisplayId, Period, TimePoint, Fps, std::optional<Period>)); + MOCK_METHOD(status_t, notifyExpectedPresent, (PhysicalDisplayId, TimePoint, Fps)); }; } // namespace mock diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp index 2e8ecba8be..3ffd8ea316 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp +++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp @@ -15,6 +15,7 @@ */ // TODO(b/129481165): remove the #pragma below and fix conversion issues +#include <chrono> #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wconversion" @@ -78,59 +79,6 @@ using aidl::android::hardware::graphics::composer3::Capability; using aidl::android::hardware::graphics::composer3::DisplayCapability; namespace hal = android::hardware::graphics::composer::hal; -namespace { -bool isFrameIntervalOnCadence(android::TimePoint expectedPresentTime, - android::TimePoint lastExpectedPresentTimestamp, - android::Fps lastFrameInterval, android::Period timeout, - android::Duration threshold) { - if (lastFrameInterval.getPeriodNsecs() == 0) { - return false; - } - - const auto expectedPresentTimeDeltaNs = - expectedPresentTime.ns() - lastExpectedPresentTimestamp.ns(); - - if (expectedPresentTimeDeltaNs > timeout.ns()) { - return false; - } - - const auto expectedPresentPeriods = static_cast<nsecs_t>( - std::round(static_cast<float>(expectedPresentTimeDeltaNs) / - static_cast<float>(lastFrameInterval.getPeriodNsecs()))); - const auto calculatedPeriodsOutNs = lastFrameInterval.getPeriodNsecs() * expectedPresentPeriods; - const auto calculatedExpectedPresentTimeNs = - lastExpectedPresentTimestamp.ns() + calculatedPeriodsOutNs; - const auto presentTimeDelta = - std::abs(expectedPresentTime.ns() - calculatedExpectedPresentTimeNs); - return presentTimeDelta < threshold.ns(); -} - -bool isExpectedPresentWithinTimeout(android::TimePoint expectedPresentTime, - android::TimePoint lastExpectedPresentTimestamp, - std::optional<android::Period> timeoutOpt, - android::Duration threshold) { - if (!timeoutOpt) { - // Always within timeout if timeoutOpt is absent and don't send hint - // for the timeout - return true; - } - - if (timeoutOpt->ns() == 0) { - // Always outside timeout if timeoutOpt is 0 and always send - // the hint for the timeout. - return false; - } - - if (expectedPresentTime.ns() < lastExpectedPresentTimestamp.ns() + timeoutOpt->ns()) { - return true; - } - - // Check if within the threshold as it can be just outside the timeout - return std::abs(expectedPresentTime.ns() - - (lastExpectedPresentTimestamp.ns() + timeoutOpt->ns())) < threshold.ns(); -} -} // namespace - namespace android { HWComposer::~HWComposer() = default; @@ -538,13 +486,6 @@ status_t HWComposer::getDeviceCompositionChanges( }(); displayData.validateWasSkipped = false; - { - std::scoped_lock lock{displayData.expectedPresentLock}; - if (expectedPresentTime > displayData.lastExpectedPresentTimestamp.ns()) { - displayData.lastExpectedPresentTimestamp = TimePoint::fromNs(expectedPresentTime); - } - } - ATRACE_FORMAT("NextFrameInterval %d_Hz", frameInterval.getIntValue()); if (canSkipValidate) { sp<Fence> outPresentFence = Fence::NO_FENCE; @@ -939,55 +880,15 @@ status_t HWComposer::setRefreshRateChangedCallbackDebugEnabled(PhysicalDisplayId return NO_ERROR; } -status_t HWComposer::notifyExpectedPresentIfRequired(PhysicalDisplayId displayId, - Period vsyncPeriod, - TimePoint expectedPresentTime, - Fps frameInterval, - std::optional<Period> timeoutOpt) { +status_t HWComposer::notifyExpectedPresent(PhysicalDisplayId displayId, + TimePoint expectedPresentTime, Fps frameInterval) { RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX); - auto& displayData = mDisplayData[displayId]; - if (!displayData.hwcDisplay) { - // Display setup has not completed yet - return BAD_INDEX; - } - { - std::scoped_lock lock{displayData.expectedPresentLock}; - const auto lastExpectedPresentTimestamp = displayData.lastExpectedPresentTimestamp; - const auto lastFrameInterval = displayData.lastFrameInterval; - displayData.lastFrameInterval = frameInterval; - const auto threshold = Duration::fromNs(vsyncPeriod.ns() / 2); - - const constexpr nsecs_t kOneSecondNs = - std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count(); - const bool frameIntervalIsOnCadence = - isFrameIntervalOnCadence(expectedPresentTime, lastExpectedPresentTimestamp, - lastFrameInterval, - Period::fromNs(timeoutOpt && timeoutOpt->ns() > 0 - ? timeoutOpt->ns() - : kOneSecondNs), - threshold); - - const bool expectedPresentWithinTimeout = - isExpectedPresentWithinTimeout(expectedPresentTime, lastExpectedPresentTimestamp, - timeoutOpt, threshold); - - using fps_approx_ops::operator!=; - if (frameIntervalIsOnCadence && frameInterval != lastFrameInterval) { - displayData.lastExpectedPresentTimestamp = expectedPresentTime; - } - - if (expectedPresentWithinTimeout && frameIntervalIsOnCadence) { - return NO_ERROR; - } - - displayData.lastExpectedPresentTimestamp = expectedPresentTime; - } - ATRACE_FORMAT("%s ExpectedPresentTime %" PRId64 " frameIntervalNs %d", __func__, - expectedPresentTime, frameInterval.getPeriodNsecs()); - const auto error = mComposer->notifyExpectedPresent(displayData.hwcDisplay->getId(), + ATRACE_FORMAT("%s ExpectedPresentTime in %.2fms frameInterval %.2fms", __func__, + ticks<std::milli, float>(expectedPresentTime - TimePoint::now()), + ticks<std::milli, float>(Duration::fromNs(frameInterval.getPeriodNsecs()))); + const auto error = mComposer->notifyExpectedPresent(mDisplayData[displayId].hwcDisplay->getId(), expectedPresentTime.ns(), frameInterval.getPeriodNsecs()); - if (error != hal::Error::NONE) { ALOGE("Error in notifyExpectedPresent call %s", to_string(error).c_str()); return INVALID_OPERATION; diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h index af62731a41..4ca528a6e7 100644 --- a/services/surfaceflinger/DisplayHardware/HWComposer.h +++ b/services/surfaceflinger/DisplayHardware/HWComposer.h @@ -303,10 +303,8 @@ public: aidl::android::hardware::graphics::common::HdrConversionStrategy, aidl::android::hardware::graphics::common::Hdr*) = 0; virtual status_t setRefreshRateChangedCallbackDebugEnabled(PhysicalDisplayId, bool enabled) = 0; - virtual status_t notifyExpectedPresentIfRequired(PhysicalDisplayId, Period vsyncPeriod, - TimePoint expectedPresentTime, - Fps frameInterval, - std::optional<Period> timeoutOpt) = 0; + virtual status_t notifyExpectedPresent(PhysicalDisplayId, TimePoint expectedPresentTime, + Fps frameInterval) = 0; }; static inline bool operator==(const android::HWComposer::DeviceRequestedChanges& lhs, @@ -466,9 +464,8 @@ public: aidl::android::hardware::graphics::common::HdrConversionStrategy, aidl::android::hardware::graphics::common::Hdr*) override; status_t setRefreshRateChangedCallbackDebugEnabled(PhysicalDisplayId, bool enabled) override; - status_t notifyExpectedPresentIfRequired(PhysicalDisplayId, Period vsyncPeriod, - TimePoint expectedPresentTime, Fps frameInterval, - std::optional<Period> timeoutOpt) override; + status_t notifyExpectedPresent(PhysicalDisplayId, TimePoint expectedPresentTime, + Fps frameInterval) override; // for debugging ---------------------------------------------------------- void dump(std::string& out) const override; @@ -494,7 +491,6 @@ public: private: // For unit tests friend TestableSurfaceFlinger; - friend HWComposerTest; struct DisplayData { std::unique_ptr<HWC2::Display> hwcDisplay; @@ -502,11 +498,6 @@ private: sp<Fence> lastPresentFence = Fence::NO_FENCE; // signals when the last set op retires nsecs_t lastPresentTimestamp = 0; - std::mutex expectedPresentLock; - TimePoint lastExpectedPresentTimestamp GUARDED_BY(expectedPresentLock) = - TimePoint::fromNs(0); - Fps lastFrameInterval GUARDED_BY(expectedPresentLock) = Fps::fromValue(0); - std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences; bool validateWasSkipped; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 1f8f2d6c94..c56dc83412 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -318,6 +318,53 @@ bool fileNewerThan(const std::string& path, std::chrono::minutes duration) { return duration > (Clock::now() - updateTime); } +bool isFrameIntervalOnCadence(TimePoint expectedPresentTime, TimePoint lastExpectedPresentTimestamp, + Fps lastFrameInterval, Period timeout, Duration threshold) { + if (lastFrameInterval.getPeriodNsecs() == 0) { + return false; + } + + const auto expectedPresentTimeDeltaNs = + expectedPresentTime.ns() - lastExpectedPresentTimestamp.ns(); + + if (expectedPresentTimeDeltaNs > timeout.ns()) { + return false; + } + + const auto expectedPresentPeriods = static_cast<nsecs_t>( + std::round(static_cast<float>(expectedPresentTimeDeltaNs) / + static_cast<float>(lastFrameInterval.getPeriodNsecs()))); + const auto calculatedPeriodsOutNs = lastFrameInterval.getPeriodNsecs() * expectedPresentPeriods; + const auto calculatedExpectedPresentTimeNs = + lastExpectedPresentTimestamp.ns() + calculatedPeriodsOutNs; + const auto presentTimeDelta = + std::abs(expectedPresentTime.ns() - calculatedExpectedPresentTimeNs); + return presentTimeDelta < threshold.ns(); +} + +bool isExpectedPresentWithinTimeout(TimePoint expectedPresentTime, + TimePoint lastExpectedPresentTimestamp, + std::optional<Period> timeoutOpt, Duration threshold) { + if (!timeoutOpt) { + // Always within timeout if timeoutOpt is absent and don't send hint + // for the timeout + return true; + } + + if (timeoutOpt->ns() == 0) { + // Always outside timeout if timeoutOpt is 0 and always send + // the hint for the timeout. + return false; + } + + if (expectedPresentTime.ns() < lastExpectedPresentTimestamp.ns() + timeoutOpt->ns()) { + return true; + } + + // Check if within the threshold as it can be just outside the timeout + return std::abs(expectedPresentTime.ns() - + (lastExpectedPresentTimestamp.ns() + timeoutOpt->ns())) < threshold.ns(); +} } // namespace anonymous // --------------------------------------------------------------------------- @@ -2707,7 +2754,18 @@ CompositeResultsPerDisplay SurfaceFlinger::composite( refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime(); refreshArgs.expectedPresentTime = expectedPresentTime.ns(); refreshArgs.hasTrustedPresentationListener = mNumTrustedPresentationListeners > 0; - + { + auto& notifyExpectedPresentData = mNotifyExpectedPresentMap[pacesetterId]; + auto lastExpectedPresentTimestamp = TimePoint::fromNs( + notifyExpectedPresentData.lastExpectedPresentTimestamp.load().ns()); + if (expectedPresentTime > lastExpectedPresentTimestamp) { + // If the values are not same, then hint is sent with newer value. + // And because composition always follows the notifyExpectedPresentIfRequired, we can + // skip updating the lastExpectedPresentTimestamp in this case. + notifyExpectedPresentData.lastExpectedPresentTimestamp + .compare_exchange_weak(lastExpectedPresentTimestamp, expectedPresentTime); + } + } // Store the present time just before calling to the composition engine so we could notify // the scheduler. const auto presentTime = systemTime(); @@ -4061,7 +4119,7 @@ void SurfaceFlinger::onChoreographerAttached() { void SurfaceFlinger::onVsyncGenerated(TimePoint expectedPresentTime, ftl::NonNull<DisplayModePtr> modePtr, Fps renderRate) { const auto vsyncPeriod = modePtr->getVsyncRate().getPeriod(); - const auto timeout = [&]() -> std::optional<Period> { + const auto timeoutOpt = [&]() -> std::optional<Period> { const auto vrrConfig = modePtr->getVrrConfig(); if (!vrrConfig) return std::nullopt; @@ -4071,14 +4129,54 @@ void SurfaceFlinger::onVsyncGenerated(TimePoint expectedPresentTime, return Period::fromNs(notifyExpectedPresentConfig->notifyExpectedPresentTimeoutNs); }(); - const auto displayId = modePtr->getPhysicalDisplayId(); - const auto status = getHwComposer().notifyExpectedPresentIfRequired(displayId, vsyncPeriod, - expectedPresentTime, - renderRate, timeout); - if (status != NO_ERROR) { - ALOGE("%s failed to notifyExpectedPresentHint for display %" PRId64, __func__, - displayId.value); + notifyExpectedPresentIfRequired(modePtr->getPhysicalDisplayId(), vsyncPeriod, + expectedPresentTime, renderRate, timeoutOpt); +} + +void SurfaceFlinger::notifyExpectedPresentIfRequired(PhysicalDisplayId displayId, + Period vsyncPeriod, + TimePoint expectedPresentTime, + Fps frameInterval, + std::optional<Period> timeoutOpt) { + { + auto& data = mNotifyExpectedPresentMap[displayId]; + const auto lastExpectedPresentTimestamp = data.lastExpectedPresentTimestamp.load(); + const auto lastFrameInterval = data.lastFrameInterval; + data.lastFrameInterval = frameInterval; + const auto threshold = Duration::fromNs(vsyncPeriod.ns() / 2); + + const constexpr nsecs_t kOneSecondNs = + std::chrono::duration_cast<std::chrono::nanoseconds>(1s).count(); + const auto timeout = Period::fromNs(timeoutOpt && timeoutOpt->ns() > 0 ? timeoutOpt->ns() + : kOneSecondNs); + const bool frameIntervalIsOnCadence = + isFrameIntervalOnCadence(expectedPresentTime, lastExpectedPresentTimestamp, + lastFrameInterval, timeout, threshold); + + const bool expectedPresentWithinTimeout = + isExpectedPresentWithinTimeout(expectedPresentTime, lastExpectedPresentTimestamp, + timeoutOpt, threshold); + + using fps_approx_ops::operator!=; + if (frameIntervalIsOnCadence && frameInterval != lastFrameInterval) { + data.lastExpectedPresentTimestamp = expectedPresentTime; + } + + if (expectedPresentWithinTimeout && frameIntervalIsOnCadence) { + return; + } + data.lastExpectedPresentTimestamp = expectedPresentTime; } + + const char* const whence = __func__; + static_cast<void>(mScheduler->schedule([=, this]() FTL_FAKE_GUARD(kMainThreadContext) { + const auto status = getHwComposer().notifyExpectedPresent(displayId, expectedPresentTime, + frameInterval); + if (status != NO_ERROR) { + ALOGE("%s failed to notifyExpectedPresentHint for display %" PRId64, whence, + displayId.value); + } + })); } void SurfaceFlinger::initScheduler(const sp<const DisplayDevice>& display) { diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 6a7b3220b3..6b4440193b 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -1490,6 +1490,19 @@ private: // Map of displayid to mirrorRoot ftl::SmallMap<int64_t, sp<SurfaceControl>, 3> mMirrorMapForDebug; + // NotifyExpectedPresentHint + struct NotifyExpectedPresentData { + // lastExpectedPresentTimestamp is read and write from multiple threads such as + // main thread, EventThread, MessageQueue. And is atomic for that reason. + std::atomic<TimePoint> lastExpectedPresentTimestamp{}; + Fps lastFrameInterval{}; + }; + std::unordered_map<PhysicalDisplayId, NotifyExpectedPresentData> mNotifyExpectedPresentMap; + + void notifyExpectedPresentIfRequired(PhysicalDisplayId, Period vsyncPeriod, + TimePoint expectedPresentTime, Fps frameInterval, + std::optional<Period> timeoutOpt); + void sfdo_enableRefreshRateOverlay(bool active); void sfdo_setDebugFlash(int delay); void sfdo_scheduleComposite(); diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp index dea019431b..c75f90222a 100644 --- a/services/surfaceflinger/tests/unittests/Android.bp +++ b/services/surfaceflinger/tests/unittests/Android.bp @@ -106,6 +106,7 @@ cc_test { "SurfaceFlinger_HdrOutputControlTest.cpp", "SurfaceFlinger_HotplugTest.cpp", "SurfaceFlinger_InitializeDisplaysTest.cpp", + "SurfaceFlinger_NotifyExpectedPresentTest.cpp", "SurfaceFlinger_NotifyPowerBoostTest.cpp", "SurfaceFlinger_PowerHintTest.cpp", "SurfaceFlinger_SetDisplayStateTest.cpp", diff --git a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp index c5e179fb4c..6edecff6a6 100644 --- a/services/surfaceflinger/tests/unittests/HWComposerTest.cpp +++ b/services/surfaceflinger/tests/unittests/HWComposerTest.cpp @@ -82,15 +82,6 @@ struct HWComposerTest : testing::Test { EXPECT_CALL(*mHal, setVsyncEnabled(hwcDisplayId, Hwc2::IComposerClient::Vsync::DISABLE)); EXPECT_CALL(*mHal, onHotplugConnect(hwcDisplayId)); } - - void setDisplayData(HalDisplayId displayId, TimePoint lastExpectedPresentTimestamp, - Fps lastFrameInterval) { - ASSERT_TRUE(mHwc.mDisplayData.find(displayId) != mHwc.mDisplayData.end()); - auto& displayData = mHwc.mDisplayData.at(displayId); - std::scoped_lock lock{displayData.expectedPresentLock}; - displayData.lastExpectedPresentTimestamp = lastExpectedPresentTimestamp; - displayData.lastFrameInterval = lastFrameInterval; - } }; TEST_F(HWComposerTest, isHeadless) { @@ -417,144 +408,6 @@ TEST_F(HWComposerTest, onVsyncInvalid) { EXPECT_FALSE(displayIdOpt); } -TEST_F(HWComposerTest, notifyExpectedPresentTimeout) { - constexpr hal::HWDisplayId kHwcDisplayId = 2; - expectHotplugConnect(kHwcDisplayId); - const auto info = mHwc.onHotplug(kHwcDisplayId, hal::Connection::CONNECTED); - ASSERT_TRUE(info); - - auto expectedPresentTime = systemTime() + ms2ns(10); - static constexpr Fps Fps60Hz = 60_Hz; - static constexpr int32_t kFrameInterval5HzNs = static_cast<Fps>(5_Hz).getPeriodNsecs(); - static constexpr int32_t kFrameInterval60HzNs = Fps60Hz.getPeriodNsecs(); - static constexpr int32_t kFrameInterval120HzNs = static_cast<Fps>(120_Hz).getPeriodNsecs(); - static constexpr Period kVsyncPeriod = - Period::fromNs(static_cast<Fps>(240_Hz).getPeriodNsecs()); - static constexpr Period kTimeoutNs = Period::fromNs(kFrameInterval5HzNs); - static constexpr auto kLastExpectedPresentTimestamp = TimePoint::fromNs(0); - - ASSERT_NO_FATAL_FAILURE(setDisplayData(info->id, kLastExpectedPresentTimestamp, Fps60Hz)); - - { - // Very first ExpectedPresent after idle, no previous timestamp - EXPECT_CALL(*mHal, - notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs)) - .WillOnce(Return(HalError::NONE)); - mHwc.notifyExpectedPresentIfRequired(info->id, kVsyncPeriod, - TimePoint::fromNs(expectedPresentTime), Fps60Hz, - kTimeoutNs); - } - { - // Absent timeoutNs - expectedPresentTime += 2 * kFrameInterval5HzNs; - EXPECT_CALL(*mHal, notifyExpectedPresent(kHwcDisplayId, _, _)).Times(0); - mHwc.notifyExpectedPresentIfRequired(info->id, kVsyncPeriod, - TimePoint::fromNs(expectedPresentTime), Fps60Hz, - /*timeoutOpt*/ std::nullopt); - } - { - // Timeout is 0 - expectedPresentTime += kFrameInterval60HzNs; - EXPECT_CALL(*mHal, - notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs)) - .WillOnce(Return(HalError::NONE)); - mHwc.notifyExpectedPresentIfRequired(info->id, kVsyncPeriod, - TimePoint::fromNs(expectedPresentTime), Fps60Hz, - Period::fromNs(0)); - } - { - // ExpectedPresent is after the timeoutNs - expectedPresentTime += 2 * kFrameInterval5HzNs; - EXPECT_CALL(*mHal, - notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs)) - .WillOnce(Return(HalError::NONE)); - mHwc.notifyExpectedPresentIfRequired(info->id, kVsyncPeriod, - TimePoint::fromNs(expectedPresentTime), Fps60Hz, - kTimeoutNs); - } - { - // ExpectedPresent has not changed - EXPECT_CALL(*mHal, notifyExpectedPresent(kHwcDisplayId, _, _)).Times(0); - mHwc.notifyExpectedPresentIfRequired(info->id, kVsyncPeriod, - TimePoint::fromNs(expectedPresentTime), Fps60Hz, - kTimeoutNs); - } - { - // ExpectedPresent is after the last reported ExpectedPresent. - expectedPresentTime += kFrameInterval60HzNs; - EXPECT_CALL(*mHal, notifyExpectedPresent(kHwcDisplayId, _, _)).Times(0); - mHwc.notifyExpectedPresentIfRequired(info->id, kVsyncPeriod, - TimePoint::fromNs(expectedPresentTime), Fps60Hz, - kTimeoutNs); - } - { - // ExpectedPresent is before the last reported ExpectedPresent but after the timeoutNs, - // representing we changed our decision and want to present earlier than previously - // reported. - expectedPresentTime -= kFrameInterval120HzNs; - EXPECT_CALL(*mHal, - notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, kFrameInterval60HzNs)) - .WillOnce(Return(HalError::NONE)); - mHwc.notifyExpectedPresentIfRequired(info->id, kVsyncPeriod, - TimePoint::fromNs(expectedPresentTime), Fps60Hz, - kTimeoutNs); - } -} - -TEST_F(HWComposerTest, notifyExpectedPresentRenderRateChanged) { - constexpr hal::HWDisplayId kHwcDisplayId = 2; - expectHotplugConnect(kHwcDisplayId); - const auto info = mHwc.onHotplug(kHwcDisplayId, hal::Connection::CONNECTED); - ASSERT_TRUE(info); - - const auto now = systemTime(); - auto expectedPresentTime = now; - static constexpr Period kTimeoutNs = Period::fromNs(static_cast<Fps>(1_Hz).getPeriodNsecs()); - - ASSERT_NO_FATAL_FAILURE(setDisplayData(info->id, TimePoint::fromNs(now), Fps::fromValue(0))); - static constexpr int32_t kFrameIntervalNs120Hz = static_cast<Fps>(120_Hz).getPeriodNsecs(); - static constexpr int32_t kFrameIntervalNs96Hz = static_cast<Fps>(96_Hz).getPeriodNsecs(); - static constexpr int32_t kFrameIntervalNs80Hz = static_cast<Fps>(80_Hz).getPeriodNsecs(); - static constexpr int32_t kFrameIntervalNs60Hz = static_cast<Fps>(60_Hz).getPeriodNsecs(); - static constexpr int32_t kFrameIntervalNs40Hz = static_cast<Fps>(40_Hz).getPeriodNsecs(); - static constexpr int32_t kFrameIntervalNs30Hz = static_cast<Fps>(30_Hz).getPeriodNsecs(); - static constexpr int32_t kFrameIntervalNs24Hz = static_cast<Fps>(24_Hz).getPeriodNsecs(); - static constexpr int32_t kFrameIntervalNs20Hz = static_cast<Fps>(20_Hz).getPeriodNsecs(); - static constexpr Period kVsyncPeriod = - Period::fromNs(static_cast<Fps>(240_Hz).getPeriodNsecs()); - - struct FrameRateIntervalTestData { - int32_t frameIntervalNs; - bool callExpectedPresent; - }; - const std::vector<FrameRateIntervalTestData> frameIntervals = { - {kFrameIntervalNs60Hz, true}, {kFrameIntervalNs96Hz, true}, - {kFrameIntervalNs80Hz, true}, {kFrameIntervalNs120Hz, true}, - {kFrameIntervalNs80Hz, true}, {kFrameIntervalNs60Hz, true}, - {kFrameIntervalNs60Hz, false}, {kFrameIntervalNs30Hz, false}, - {kFrameIntervalNs24Hz, true}, {kFrameIntervalNs40Hz, true}, - {kFrameIntervalNs20Hz, false}, {kFrameIntervalNs60Hz, true}, - {kFrameIntervalNs20Hz, false}, {kFrameIntervalNs120Hz, true}, - }; - - for (const auto& [frameIntervalNs, callExpectedPresent] : frameIntervals) { - { - expectedPresentTime += frameIntervalNs; - if (callExpectedPresent) { - EXPECT_CALL(*mHal, - notifyExpectedPresent(kHwcDisplayId, expectedPresentTime, - frameIntervalNs)) - .WillOnce(Return(HalError::NONE)); - } else { - EXPECT_CALL(*mHal, notifyExpectedPresent(kHwcDisplayId, _, _)).Times(0); - } - mHwc.notifyExpectedPresentIfRequired(info->id, kVsyncPeriod, - TimePoint::fromNs(expectedPresentTime), - Fps::fromPeriodNsecs(frameIntervalNs), kTimeoutNs); - } - } -} - struct MockHWC2ComposerCallback final : StrictMock<HWC2::ComposerCallback> { MOCK_METHOD(void, onComposerHalHotplugEvent, (hal::HWDisplayId, DisplayHotplugEvent), (override)); diff --git a/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp new file mode 100644 index 0000000000..7206e2977d --- /dev/null +++ b/services/surfaceflinger/tests/unittests/SurfaceFlinger_NotifyExpectedPresentTest.cpp @@ -0,0 +1,180 @@ +/* + * Copyright 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#undef LOG_TAG +#define LOG_TAG "LibSurfaceFlingerUnittests" + +#include "DisplayTransactionTestHelpers.h" + +namespace android { + +using FakeHwcDisplayInjector = TestableSurfaceFlinger::FakeHwcDisplayInjector; + +class NotifyExpectedPresentTest : public DisplayTransactionTest { +public: + void SetUp() override { + mDisplay = PrimaryDisplayVariant::makeFakeExistingDisplayInjector(this).inject(); + FakeHwcDisplayInjector(mDisplay->getPhysicalId(), hal::DisplayType::PHYSICAL, kIsPrimary) + .setPowerMode(hal::PowerMode::ON) + .inject(&mFlinger, mComposer); + } + +protected: + sp<DisplayDevice> mDisplay; + static constexpr bool kIsPrimary = true; + static constexpr hal::HWDisplayId HWC_DISPLAY_ID = + FakeHwcDisplayInjector::DEFAULT_HWC_DISPLAY_ID; +}; + +TEST_F(NotifyExpectedPresentTest, notifyExpectedPresentTimeout) { + const auto physicDisplayId = mDisplay->getPhysicalId(); + auto expectedPresentTime = systemTime() + ms2ns(10); + static constexpr Fps kFps60Hz = 60_Hz; + static constexpr int32_t kFrameInterval5HzNs = static_cast<Fps>(5_Hz).getPeriodNsecs(); + static constexpr int32_t kFrameInterval60HzNs = kFps60Hz.getPeriodNsecs(); + static constexpr int32_t kFrameInterval120HzNs = static_cast<Fps>(120_Hz).getPeriodNsecs(); + static constexpr Period kVsyncPeriod = + Period::fromNs(static_cast<Fps>(240_Hz).getPeriodNsecs()); + static constexpr Period kTimeoutNs = Period::fromNs(kFrameInterval5HzNs); + static constexpr auto kLastExpectedPresentTimestamp = TimePoint::fromNs(0); + + ASSERT_NO_FATAL_FAILURE(mFlinger.setNotifyExpectedPresentData(physicDisplayId, + kLastExpectedPresentTimestamp, + kFps60Hz)); + + { + // Very first ExpectedPresent after idle, no previous timestamp + EXPECT_CALL(*mComposer, + notifyExpectedPresent(HWC_DISPLAY_ID, expectedPresentTime, + kFrameInterval60HzNs)) + .WillOnce(Return(Error::NONE)); + mFlinger.notifyExpectedPresentIfRequired(physicDisplayId, kVsyncPeriod, + TimePoint::fromNs(expectedPresentTime), kFps60Hz, + kTimeoutNs); + } + { + // Absent timeoutNs + expectedPresentTime += 2 * kFrameInterval5HzNs; + EXPECT_CALL(*mComposer, notifyExpectedPresent(HWC_DISPLAY_ID, _, _)).Times(0); + mFlinger.notifyExpectedPresentIfRequired(physicDisplayId, kVsyncPeriod, + TimePoint::fromNs(expectedPresentTime), kFps60Hz, + /*timeoutOpt*/ std::nullopt); + } + { + // Timeout is 0 + expectedPresentTime += kFrameInterval60HzNs; + EXPECT_CALL(*mComposer, + notifyExpectedPresent(HWC_DISPLAY_ID, expectedPresentTime, + kFrameInterval60HzNs)) + .WillOnce(Return(Error::NONE)); + mFlinger.notifyExpectedPresentIfRequired(physicDisplayId, kVsyncPeriod, + TimePoint::fromNs(expectedPresentTime), kFps60Hz, + Period::fromNs(0)); + } + { + // ExpectedPresent is after the timeoutNs + expectedPresentTime += 2 * kFrameInterval5HzNs; + EXPECT_CALL(*mComposer, + notifyExpectedPresent(HWC_DISPLAY_ID, expectedPresentTime, + kFrameInterval60HzNs)) + .WillOnce(Return(Error::NONE)); + mFlinger.notifyExpectedPresentIfRequired(physicDisplayId, kVsyncPeriod, + TimePoint::fromNs(expectedPresentTime), kFps60Hz, + kTimeoutNs); + } + { + // ExpectedPresent has not changed + EXPECT_CALL(*mComposer, notifyExpectedPresent(HWC_DISPLAY_ID, _, _)).Times(0); + mFlinger.notifyExpectedPresentIfRequired(physicDisplayId, kVsyncPeriod, + TimePoint::fromNs(expectedPresentTime), kFps60Hz, + kTimeoutNs); + } + { + // ExpectedPresent is after the last reported ExpectedPresent. + expectedPresentTime += kFrameInterval60HzNs; + EXPECT_CALL(*mComposer, notifyExpectedPresent(HWC_DISPLAY_ID, _, _)).Times(0); + mFlinger.notifyExpectedPresentIfRequired(physicDisplayId, kVsyncPeriod, + TimePoint::fromNs(expectedPresentTime), kFps60Hz, + kTimeoutNs); + } + { + // ExpectedPresent is before the last reported ExpectedPresent but after the timeoutNs, + // representing we changed our decision and want to present earlier than previously + // reported. + expectedPresentTime -= kFrameInterval120HzNs; + EXPECT_CALL(*mComposer, + notifyExpectedPresent(HWC_DISPLAY_ID, expectedPresentTime, + kFrameInterval60HzNs)) + .WillOnce(Return(Error::NONE)); + mFlinger.notifyExpectedPresentIfRequired(physicDisplayId, kVsyncPeriod, + TimePoint::fromNs(expectedPresentTime), kFps60Hz, + kTimeoutNs); + } +} + +TEST_F(NotifyExpectedPresentTest, notifyExpectedPresentRenderRateChanged) { + const auto physicDisplayId = mDisplay->getPhysicalId(); + const auto now = systemTime(); + auto expectedPresentTime = now; + static constexpr Period kTimeoutNs = Period::fromNs(static_cast<Fps>(1_Hz).getPeriodNsecs()); + + ASSERT_NO_FATAL_FAILURE(mFlinger.setNotifyExpectedPresentData(physicDisplayId, + TimePoint::fromNs(now), + Fps::fromValue(0))); + static constexpr int32_t kFrameIntervalNs120Hz = static_cast<Fps>(120_Hz).getPeriodNsecs(); + static constexpr int32_t kFrameIntervalNs96Hz = static_cast<Fps>(96_Hz).getPeriodNsecs(); + static constexpr int32_t kFrameIntervalNs80Hz = static_cast<Fps>(80_Hz).getPeriodNsecs(); + static constexpr int32_t kFrameIntervalNs60Hz = static_cast<Fps>(60_Hz).getPeriodNsecs(); + static constexpr int32_t kFrameIntervalNs40Hz = static_cast<Fps>(40_Hz).getPeriodNsecs(); + static constexpr int32_t kFrameIntervalNs30Hz = static_cast<Fps>(30_Hz).getPeriodNsecs(); + static constexpr int32_t kFrameIntervalNs24Hz = static_cast<Fps>(24_Hz).getPeriodNsecs(); + static constexpr int32_t kFrameIntervalNs20Hz = static_cast<Fps>(20_Hz).getPeriodNsecs(); + static constexpr Period kVsyncPeriod = + Period::fromNs(static_cast<Fps>(240_Hz).getPeriodNsecs()); + + struct FrameRateIntervalTestData { + int32_t frameIntervalNs; + bool callExpectedPresent; + }; + const std::vector<FrameRateIntervalTestData> frameIntervals = { + {kFrameIntervalNs60Hz, true}, {kFrameIntervalNs96Hz, true}, + {kFrameIntervalNs80Hz, true}, {kFrameIntervalNs120Hz, true}, + {kFrameIntervalNs80Hz, true}, {kFrameIntervalNs60Hz, true}, + {kFrameIntervalNs60Hz, false}, {kFrameIntervalNs30Hz, false}, + {kFrameIntervalNs24Hz, true}, {kFrameIntervalNs40Hz, true}, + {kFrameIntervalNs20Hz, false}, {kFrameIntervalNs60Hz, true}, + {kFrameIntervalNs20Hz, false}, {kFrameIntervalNs120Hz, true}, + }; + + for (const auto& [frameIntervalNs, callExpectedPresent] : frameIntervals) { + { + expectedPresentTime += frameIntervalNs; + if (callExpectedPresent) { + EXPECT_CALL(*mComposer, + notifyExpectedPresent(HWC_DISPLAY_ID, expectedPresentTime, + frameIntervalNs)) + .WillOnce(Return(Error::NONE)); + } else { + EXPECT_CALL(*mComposer, notifyExpectedPresent(HWC_DISPLAY_ID, _, _)).Times(0); + } + mFlinger.notifyExpectedPresentIfRequired(physicDisplayId, kVsyncPeriod, + TimePoint::fromNs(expectedPresentTime), + Fps::fromPeriodNsecs(frameIntervalNs), + kTimeoutNs); + } + } +} +} // namespace android
\ No newline at end of file diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h index 8ba6bf87e2..22cb24bb6f 100644 --- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h +++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h @@ -695,6 +695,21 @@ public: mFlinger->mLegacyFrontEndEnabled = false; } + void notifyExpectedPresentIfRequired(PhysicalDisplayId displayId, Period vsyncPeriod, + TimePoint expectedPresentTime, Fps frameInterval, + std::optional<Period> timeoutOpt) { + mFlinger->notifyExpectedPresentIfRequired(displayId, vsyncPeriod, expectedPresentTime, + frameInterval, timeoutOpt); + } + + void setNotifyExpectedPresentData(PhysicalDisplayId displayId, + TimePoint lastExpectedPresentTimestamp, + Fps lastFrameInterval) { + auto& displayData = mFlinger->mNotifyExpectedPresentMap[displayId]; + displayData.lastExpectedPresentTimestamp = lastExpectedPresentTimestamp; + displayData.lastFrameInterval = lastFrameInterval; + } + ~TestableSurfaceFlinger() { // All these pointer and container clears help ensure that GMock does // not report a leaked object, since the SurfaceFlinger instance may |