Add ADPF GPU duration reporting for SurfaceFlinger
Gated the new GPU implementation behind the adpf_gpu_sf
flag. Changes below are not gated:
Changed to check if RenderEngine is used instead of
client composition as the latter doesn't always
trigger GPU composition (cache). And we should not set
the flag early in chooseCompositionStrategy, since if
HWC fails, it will get reset and still run on GPU.
Fixed PowerAdvisor::setGpuFenceTime code to truely
respect other displays' delay on start time
Bug: 284324521
Test: atest libcompositionengine_test PowerAdvisorTest
Change-Id: I498401d18d9886cda5c6e82243fe7cdad46e091f
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index f1d6f52..e7d0afc 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -321,7 +321,9 @@
const Region& flashRegion,
std::vector<LayerFE::LayerSettings>& clientCompositionLayers) = 0;
virtual void setExpensiveRenderingExpected(bool enabled) = 0;
+ virtual void setHintSessionGpuStart(TimePoint startTime) = 0;
virtual void setHintSessionGpuFence(std::unique_ptr<FenceTime>&& gpuFence) = 0;
+ virtual void setHintSessionRequiresRenderEngine(bool requiresRenderEngine) = 0;
virtual bool isPowerHintSessionEnabled() = 0;
virtual void cacheClientCompositionRequests(uint32_t cacheSize) = 0;
virtual bool canPredictCompositionStrategy(const CompositionRefreshArgs&) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 2dc9a1a..eaffa9e 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -93,7 +93,9 @@
private:
bool isPowerHintSessionEnabled() override;
+ void setHintSessionGpuStart(TimePoint startTime) override;
void setHintSessionGpuFence(std::unique_ptr<FenceTime>&& gpuFence) override;
+ void setHintSessionRequiresRenderEngine(bool requiresRenderEngine) override;
DisplayId mId;
bool mIsDisconnected = false;
Hwc2::PowerAdvisor* mPowerAdvisor = nullptr;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 911d67b..d35e24a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -144,7 +144,9 @@
std::vector<LayerFE*>& outLayerFEs) override;
void appendRegionFlashRequests(const Region&, std::vector<LayerFE::LayerSettings>&) override;
void setExpensiveRenderingExpected(bool enabled) override;
+ void setHintSessionGpuStart(TimePoint startTime) override;
void setHintSessionGpuFence(std::unique_ptr<FenceTime>&& gpuFence) override;
+ void setHintSessionRequiresRenderEngine(bool requiresRenderEngine) override;
bool isPowerHintSessionEnabled() override;
void dumpBase(std::string&) const;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 95ea3a4..019a058 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -134,7 +134,9 @@
MOCK_METHOD1(canPredictCompositionStrategy, bool(const CompositionRefreshArgs&));
MOCK_METHOD1(setPredictCompositionStrategy, void(bool));
MOCK_METHOD1(setTreat170mAsSrgb, void(bool));
+ MOCK_METHOD(void, setHintSessionGpuStart, (TimePoint startTime));
MOCK_METHOD(void, setHintSessionGpuFence, (std::unique_ptr<FenceTime> && gpuFence));
+ MOCK_METHOD(void, setHintSessionRequiresRenderEngine, (bool requiresRenderEngine));
MOCK_METHOD(bool, isPowerHintSessionEnabled, ());
};
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 6428d08..3d35704 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -252,10 +252,6 @@
auto& hwc = getCompositionEngine().getHwComposer();
const bool requiresClientComposition = anyLayersRequireClientComposition();
- if (isPowerHintSessionEnabled()) {
- mPowerAdvisor->setRequiresClientComposition(mId, requiresClientComposition);
- }
-
const TimePoint hwcValidateStartTime = TimePoint::now();
if (status_t result = hwc.getDeviceCompositionChanges(*halDisplayId, requiresClientComposition,
@@ -416,10 +412,20 @@
return mPowerAdvisor != nullptr && mPowerAdvisor->usePowerHintSession();
}
+// For ADPF GPU v0 this is expected to set start time to when the GPU commands are submitted with
+// fence returned, i.e. when RenderEngine flushes the commands and returns the draw fence.
+void Display::setHintSessionGpuStart(TimePoint startTime) {
+ mPowerAdvisor->setGpuStartTime(mId, startTime);
+}
+
void Display::setHintSessionGpuFence(std::unique_ptr<FenceTime>&& gpuFence) {
mPowerAdvisor->setGpuFenceTime(mId, std::move(gpuFence));
}
+void Display::setHintSessionRequiresRenderEngine(bool requiresRenderEngine) {
+ mPowerAdvisor->setRequiresRenderEngine(mId, requiresRenderEngine);
+}
+
void Display::finishFrame(GpuCompositionResult&& result) {
// We only need to actually compose the display if:
// 1) It is being handled by hardware composer, which may need this to
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 7b5b49d..91f51e9 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -464,6 +464,10 @@
setColorTransform(refreshArgs);
beginFrame();
+ if (isPowerHintSessionEnabled()) {
+ // always reset the flag before the composition prediction
+ setHintSessionRequiresRenderEngine(false);
+ }
GpuCompositionResult result;
const bool predictCompositionStrategy = canPredictCompositionStrategy(refreshArgs);
if (predictCompositionStrategy) {
@@ -1248,8 +1252,7 @@
if (!optReadyFence) {
return;
}
-
- if (isPowerHintSessionEnabled()) {
+ if (isPowerHintSessionEnabled() && !FlagManager::getInstance().adpf_gpu_sf()) {
// get fence end time to know when gpu is complete in display
setHintSessionGpuFence(
std::make_unique<FenceTime>(sp<Fence>::make(dup(optReadyFence->get()))));
@@ -1393,8 +1396,20 @@
// If rendering was not successful, remove the request from the cache.
mClientCompositionRequestCache->remove(tex->getBuffer()->getId());
}
-
const auto fence = std::move(fenceResult).value_or(Fence::NO_FENCE);
+ if (isPowerHintSessionEnabled()) {
+ if (fence != Fence::NO_FENCE && fence->isValid() &&
+ !outputCompositionState.reusedClientComposition) {
+ setHintSessionRequiresRenderEngine(true);
+ if (FlagManager::getInstance().adpf_gpu_sf()) {
+ // the order of the two calls here matters as we should check if the previously
+ // tracked fence has signaled first and archive the previous start time
+ setHintSessionGpuStart(TimePoint::now());
+ setHintSessionGpuFence(
+ std::make_unique<FenceTime>(sp<Fence>::make(dup(fence->get()))));
+ }
+ }
+ }
if (auto timeStats = getCompositionEngine().getTimeStats()) {
if (fence->isValid()) {
@@ -1577,10 +1592,18 @@
// The base class does nothing with this call.
}
+void Output::setHintSessionGpuStart(TimePoint) {
+ // The base class does nothing with this call.
+}
+
void Output::setHintSessionGpuFence(std::unique_ptr<FenceTime>&&) {
// The base class does nothing with this call.
}
+void Output::setHintSessionRequiresRenderEngine(bool) {
+ // The base class does nothing with this call.
+}
+
bool Output::isPowerHintSessionEnabled() {
return false;
}
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
index 7253354..d0843a2 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockPowerAdvisor.h
@@ -42,6 +42,7 @@
MOCK_METHOD(void, reportActualWorkDuration, (), (override));
MOCK_METHOD(void, enablePowerHintSession, (bool enabled), (override));
MOCK_METHOD(bool, startPowerHintSession, (std::vector<int32_t> && threadIds), (override));
+ MOCK_METHOD(void, setGpuStartTime, (DisplayId displayId, TimePoint startTime), (override));
MOCK_METHOD(void, setGpuFenceTime,
(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime), (override));
MOCK_METHOD(void, setHwcValidateTiming,
@@ -51,8 +52,8 @@
(DisplayId displayId, TimePoint presentStartTime, TimePoint presentEndTime),
(override));
MOCK_METHOD(void, setSkippedValidate, (DisplayId displayId, bool skipped), (override));
- MOCK_METHOD(void, setRequiresClientComposition,
- (DisplayId displayId, bool requiresClientComposition), (override));
+ MOCK_METHOD(void, setRequiresRenderEngine, (DisplayId displayId, bool requiresRenderEngine),
+ (override));
MOCK_METHOD(void, setExpectedPresentTime, (TimePoint expectedPresentTime), (override));
MOCK_METHOD(void, setSfPresentTiming, (TimePoint presentFenceTime, TimePoint presentEndTime),
(override));
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index ea1d8e8..b4789f1 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -2017,8 +2017,15 @@
MOCK_METHOD0(presentFrameAndReleaseLayers, void());
MOCK_METHOD1(renderCachedSets, void(const compositionengine::CompositionRefreshArgs&));
MOCK_METHOD1(canPredictCompositionStrategy, bool(const CompositionRefreshArgs&));
+ MOCK_METHOD(void, setHintSessionRequiresRenderEngine, (bool requiresRenderEngine),
+ (override));
+ MOCK_METHOD(bool, isPowerHintSessionEnabled, (), (override));
};
+ OutputPresentTest() {
+ EXPECT_CALL(mOutput, isPowerHintSessionEnabled()).WillRepeatedly(Return(true));
+ }
+
StrictMock<OutputPartialMock> mOutput;
};
@@ -2032,6 +2039,7 @@
EXPECT_CALL(mOutput, writeCompositionState(Ref(args)));
EXPECT_CALL(mOutput, setColorTransform(Ref(args)));
EXPECT_CALL(mOutput, beginFrame());
+ EXPECT_CALL(mOutput, setHintSessionRequiresRenderEngine(false));
EXPECT_CALL(mOutput, canPredictCompositionStrategy(Ref(args))).WillOnce(Return(false));
EXPECT_CALL(mOutput, prepareFrame());
EXPECT_CALL(mOutput, devOptRepaintFlash(Ref(args)));
@@ -2052,6 +2060,7 @@
EXPECT_CALL(mOutput, writeCompositionState(Ref(args)));
EXPECT_CALL(mOutput, setColorTransform(Ref(args)));
EXPECT_CALL(mOutput, beginFrame());
+ EXPECT_CALL(mOutput, setHintSessionRequiresRenderEngine(false));
EXPECT_CALL(mOutput, canPredictCompositionStrategy(Ref(args))).WillOnce(Return(true));
EXPECT_CALL(mOutput, prepareFrameAsync());
EXPECT_CALL(mOutput, devOptRepaintFlash(Ref(args)));
@@ -2989,6 +2998,9 @@
MOCK_METHOD0(updateProtectedContentState, void());
MOCK_METHOD2(dequeueRenderBuffer,
bool(base::unique_fd*, std::shared_ptr<renderengine::ExternalTexture>*));
+ MOCK_METHOD(void, setHintSessionGpuFence, (std::unique_ptr<FenceTime> && gpuFence),
+ (override));
+ MOCK_METHOD(bool, isPowerHintSessionEnabled, (), (override));
};
OutputFinishFrameTest() {
@@ -2997,6 +3009,8 @@
mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
EXPECT_CALL(mOutput, getCompositionEngine()).WillRepeatedly(ReturnRef(mCompositionEngine));
EXPECT_CALL(mCompositionEngine, getRenderEngine()).WillRepeatedly(ReturnRef(mRenderEngine));
+ EXPECT_CALL(mOutput, isPowerHintSessionEnabled()).WillRepeatedly(Return(true));
+ SET_FLAG_FOR_TEST(flags::adpf_gpu_sf, false);
}
StrictMock<OutputPartialMock> mOutput;
@@ -3031,6 +3045,23 @@
EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(true));
EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _, _))
.WillOnce(Return(ByMove(base::unique_fd())));
+ EXPECT_CALL(mOutput, setHintSessionGpuFence(_));
+ EXPECT_CALL(*mRenderSurface, queueBuffer(_, 1.f));
+
+ impl::GpuCompositionResult result;
+ mOutput.finishFrame(std::move(result));
+}
+
+TEST_F(OutputFinishFrameTest, queuesBufferIfComposeSurfacesReturnsAFenceWithAdpfGpuOn) {
+ SET_FLAG_FOR_TEST(flags::adpf_gpu_sf, true);
+ mOutput.mState.isEnabled = true;
+
+ InSequence seq;
+ EXPECT_CALL(mOutput, updateProtectedContentState());
+ EXPECT_CALL(mOutput, dequeueRenderBuffer(_, _)).WillOnce(Return(true));
+ EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _, _))
+ .WillOnce(Return(ByMove(base::unique_fd())));
+ EXPECT_CALL(mOutput, setHintSessionGpuFence(_)).Times(0);
EXPECT_CALL(*mRenderSurface, queueBuffer(_, 1.f));
impl::GpuCompositionResult result;
@@ -3058,6 +3089,7 @@
.WillOnce(DoAll(SetArgPointee<1>(texture), Return(true)));
EXPECT_CALL(mOutput, composeSurfaces(RegionEq(Region::INVALID_REGION), _, _))
.WillOnce(Return(ByMove(base::unique_fd())));
+ EXPECT_CALL(mOutput, setHintSessionGpuFence(_));
EXPECT_CALL(*mRenderSurface, queueBuffer(_, 2.f));
impl::GpuCompositionResult result;
@@ -3068,6 +3100,7 @@
mOutput.mState.isEnabled = true;
mOutput.mState.strategyPrediction = CompositionStrategyPredictionState::SUCCESS;
InSequence seq;
+ EXPECT_CALL(mOutput, setHintSessionGpuFence(_));
EXPECT_CALL(*mRenderSurface, queueBuffer(_, 1.f));
impl::GpuCompositionResult result;
@@ -3090,6 +3123,7 @@
composeSurfaces(RegionEq(Region::INVALID_REGION), result.buffer,
Eq(ByRef(result.fence))))
.WillOnce(Return(ByMove(base::unique_fd())));
+ EXPECT_CALL(mOutput, setHintSessionGpuFence(_));
EXPECT_CALL(*mRenderSurface, queueBuffer(_, 1.f));
mOutput.finishFrame(std::move(result));
}
@@ -3415,8 +3449,10 @@
MOCK_METHOD2(appendRegionFlashRequests,
void(const Region&, std::vector<LayerFE::LayerSettings>&));
MOCK_METHOD1(setExpensiveRenderingExpected, void(bool));
+ MOCK_METHOD(void, setHintSessionGpuStart, (TimePoint startTime), (override));
MOCK_METHOD(void, setHintSessionGpuFence, (std::unique_ptr<FenceTime> && gpuFence),
(override));
+ MOCK_METHOD(void, setHintSessionRequiresRenderEngine, (bool), (override));
MOCK_METHOD(bool, isPowerHintSessionEnabled, (), (override));
};
@@ -3447,6 +3483,8 @@
EXPECT_CALL(mCompositionEngine, getTimeStats()).WillRepeatedly(Return(mTimeStats.get()));
EXPECT_CALL(*mDisplayColorProfile, getHdrCapabilities())
.WillRepeatedly(ReturnRef(kHdrCapabilities));
+ EXPECT_CALL(mOutput, isPowerHintSessionEnabled()).WillRepeatedly(Return(true));
+ SET_FLAG_FOR_TEST(flags::adpf_gpu_sf, false);
}
struct ExecuteState : public CallOrderStateMachineHelper<TestType, ExecuteState> {
@@ -3712,6 +3750,9 @@
EXPECT_FALSE(mOutput.mState.reusedClientComposition);
// We do not expect another call to draw layers.
+ EXPECT_CALL(mOutput, setHintSessionRequiresRenderEngine(_)).Times(0);
+ EXPECT_CALL(mOutput, setHintSessionGpuStart(_)).Times(0);
+ EXPECT_CALL(mOutput, setHintSessionGpuFence(_)).Times(0);
verify().execute().expectAFenceWasReturned();
EXPECT_TRUE(mOutput.mState.reusedClientComposition);
}
@@ -3740,14 +3781,62 @@
EXPECT_CALL(*mRenderSurface, dequeueBuffer(_))
.WillOnce(Return(mOutputBuffer))
.WillOnce(Return(otherOutputBuffer));
+ base::unique_fd fd(open("/dev/null", O_RDONLY));
EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, _))
.WillRepeatedly([&](const renderengine::DisplaySettings&,
const std::vector<renderengine::LayerSettings>&,
const std::shared_ptr<renderengine::ExternalTexture>&,
base::unique_fd&&) -> ftl::Future<FenceResult> {
- return ftl::yield<FenceResult>(Fence::NO_FENCE);
+ return ftl::yield<FenceResult>(sp<Fence>::make(std::move(fd)));
});
+ EXPECT_CALL(mOutput, setHintSessionRequiresRenderEngine(true));
+ EXPECT_CALL(mOutput, setHintSessionGpuStart(_)).Times(0);
+ EXPECT_CALL(mOutput, setHintSessionGpuFence(_)).Times(0);
+ verify().execute().expectAFenceWasReturned();
+ EXPECT_FALSE(mOutput.mState.reusedClientComposition);
+
+ verify().execute().expectAFenceWasReturned();
+ EXPECT_FALSE(mOutput.mState.reusedClientComposition);
+}
+
+TEST_F(OutputComposeSurfacesTest, clientCompositionIfBufferChangesWithAdpfGpuOn) {
+ SET_FLAG_FOR_TEST(flags::adpf_gpu_sf, true);
+ LayerFE::LayerSettings r1;
+ LayerFE::LayerSettings r2;
+
+ r1.geometry.boundaries = FloatRect{1, 2, 3, 4};
+ r2.geometry.boundaries = FloatRect{5, 6, 7, 8};
+
+ EXPECT_CALL(mOutput, getSkipColorTransform()).WillRepeatedly(Return(false));
+ EXPECT_CALL(*mDisplayColorProfile, hasWideColorGamut()).WillRepeatedly(Return(true));
+ EXPECT_CALL(mRenderEngine, supportsProtectedContent()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mRenderEngine, isProtected()).WillRepeatedly(Return(false));
+ EXPECT_CALL(mOutput, generateClientCompositionRequests(_, kDefaultOutputDataspace, _))
+ .WillRepeatedly(Return(std::vector<LayerFE::LayerSettings>{r1, r2}));
+ EXPECT_CALL(mOutput, appendRegionFlashRequests(RegionEq(kDebugRegion), _))
+ .WillRepeatedly(Return());
+
+ const auto otherOutputBuffer = std::make_shared<
+ renderengine::impl::
+ ExternalTexture>(sp<GraphicBuffer>::make(), mRenderEngine,
+ renderengine::impl::ExternalTexture::Usage::READABLE |
+ renderengine::impl::ExternalTexture::Usage::WRITEABLE);
+ EXPECT_CALL(*mRenderSurface, dequeueBuffer(_))
+ .WillOnce(Return(mOutputBuffer))
+ .WillOnce(Return(otherOutputBuffer));
+ base::unique_fd fd(open("/dev/null", O_RDONLY));
+ EXPECT_CALL(mRenderEngine, drawLayers(_, ElementsAre(r1, r2), _, _))
+ .WillRepeatedly([&](const renderengine::DisplaySettings&,
+ const std::vector<renderengine::LayerSettings>&,
+ const std::shared_ptr<renderengine::ExternalTexture>&,
+ base::unique_fd&&) -> ftl::Future<FenceResult> {
+ return ftl::yield<FenceResult>(sp<Fence>::make(std::move(fd)));
+ });
+
+ EXPECT_CALL(mOutput, setHintSessionRequiresRenderEngine(true));
+ EXPECT_CALL(mOutput, setHintSessionGpuStart(_));
+ EXPECT_CALL(mOutput, setHintSessionGpuFence(_));
verify().execute().expectAFenceWasReturned();
EXPECT_FALSE(mOutput.mState.reusedClientComposition);
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
index faa5197..4f377eb 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.cpp
@@ -270,27 +270,30 @@
return;
}
ATRACE_CALL();
- std::optional<Duration> actualDuration = estimateWorkDuration();
- if (!actualDuration.has_value() || actualDuration < 0ns) {
+ std::optional<WorkDuration> actualDuration = estimateWorkDuration();
+ if (!actualDuration.has_value() || actualDuration->durationNanos < 0) {
ALOGV("Failed to send actual work duration, skipping");
return;
}
- actualDuration = std::make_optional(*actualDuration + sTargetSafetyMargin);
- mActualDuration = actualDuration;
-
+ actualDuration->durationNanos += sTargetSafetyMargin.ns();
if (sTraceHintSessionData) {
- ATRACE_INT64("Measured duration", actualDuration->ns());
- ATRACE_INT64("Target error term", Duration{*actualDuration - mTargetDuration}.ns());
- ATRACE_INT64("Reported duration", actualDuration->ns());
+ ATRACE_INT64("Measured duration", actualDuration->durationNanos);
+ ATRACE_INT64("Target error term", actualDuration->durationNanos - mTargetDuration.ns());
+ ATRACE_INT64("Reported duration", actualDuration->durationNanos);
+ if (FlagManager::getInstance().adpf_gpu_sf()) {
+ ATRACE_INT64("Reported cpu duration", actualDuration->cpuDurationNanos);
+ ATRACE_INT64("Reported gpu duration", actualDuration->gpuDurationNanos);
+ }
ATRACE_INT64("Reported target", mLastTargetDurationSent.ns());
ATRACE_INT64("Reported target error term",
- Duration{*actualDuration - mLastTargetDurationSent}.ns());
+ actualDuration->durationNanos - mLastTargetDurationSent.ns());
}
- ALOGV("Sending actual work duration of: %" PRId64 " on reported target: %" PRId64
- " with error: %" PRId64,
- actualDuration->ns(), mLastTargetDurationSent.ns(),
- Duration{*actualDuration - mLastTargetDurationSent}.ns());
+ ALOGV("Sending actual work duration of: %" PRId64 " with cpu: %" PRId64 " and gpu: %" PRId64
+ " on reported target: %" PRId64 " with error: %" PRId64,
+ actualDuration->durationNanos, actualDuration->cpuDurationNanos,
+ actualDuration->gpuDurationNanos, mLastTargetDurationSent.ns(),
+ actualDuration->durationNanos - mLastTargetDurationSent.ns());
if (mTimingTestingMode) {
mDelayReportActualMutexAcquisitonPromise.get_future().wait();
@@ -303,17 +306,7 @@
ALOGV("Hint session not running and could not be started, skipping");
return;
}
-
- WorkDuration duration{
- .timeStampNanos = TimePoint::now().ns(),
- // TODO(b/284324521): Correctly calculate total duration.
- .durationNanos = actualDuration->ns(),
- .workPeriodStartTimestampNanos = mCommitStartTimes[0].ns(),
- .cpuDurationNanos = actualDuration->ns(),
- // TODO(b/284324521): Calculate RenderEngine GPU time.
- .gpuDurationNanos = 0,
- };
- mHintSessionQueue.push_back(duration);
+ mHintSessionQueue.push_back(*actualDuration);
auto ret = mHintSession->reportActualWorkDuration(mHintSessionQueue);
if (!ret.isOk()) {
@@ -348,11 +341,36 @@
return ensurePowerHintSessionRunning();
}
-void PowerAdvisor::setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime) {
+void PowerAdvisor::setGpuStartTime(DisplayId displayId, TimePoint startTime) {
DisplayTimingData& displayData = mDisplayTimingData[displayId];
if (displayData.gpuEndFenceTime) {
nsecs_t signalTime = displayData.gpuEndFenceTime->getSignalTime();
if (signalTime != Fence::SIGNAL_TIME_INVALID && signalTime != Fence::SIGNAL_TIME_PENDING) {
+ displayData.lastValidGpuStartTime = displayData.gpuStartTime;
+ displayData.lastValidGpuEndTime = TimePoint::fromNs(signalTime);
+ for (auto&& [_, otherDisplayData] : mDisplayTimingData) {
+ if (!otherDisplayData.lastValidGpuStartTime.has_value() ||
+ !otherDisplayData.lastValidGpuEndTime.has_value())
+ continue;
+ if ((*otherDisplayData.lastValidGpuStartTime < *displayData.gpuStartTime) &&
+ (*otherDisplayData.lastValidGpuEndTime > *displayData.gpuStartTime)) {
+ displayData.lastValidGpuStartTime = *otherDisplayData.lastValidGpuEndTime;
+ break;
+ }
+ }
+ }
+ displayData.gpuEndFenceTime = nullptr;
+ }
+ displayData.gpuStartTime = startTime;
+}
+
+void PowerAdvisor::setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime) {
+ DisplayTimingData& displayData = mDisplayTimingData[displayId];
+ if (displayData.gpuEndFenceTime && !FlagManager::getInstance().adpf_gpu_sf()) {
+ nsecs_t signalTime = displayData.gpuEndFenceTime->getSignalTime();
+ if (signalTime != Fence::SIGNAL_TIME_INVALID && signalTime != Fence::SIGNAL_TIME_PENDING) {
+ displayData.lastValidGpuStartTime = displayData.gpuStartTime;
+ displayData.lastValidGpuEndTime = TimePoint::fromNs(signalTime);
for (auto&& [_, otherDisplayData] : mDisplayTimingData) {
// If the previous display started before us but ended after we should have
// started, then it likely delayed our start time and we must compensate for that.
@@ -365,12 +383,12 @@
break;
}
}
- displayData.lastValidGpuStartTime = displayData.gpuStartTime;
- displayData.lastValidGpuEndTime = TimePoint::fromNs(signalTime);
}
}
displayData.gpuEndFenceTime = std::move(fenceTime);
- displayData.gpuStartTime = TimePoint::now();
+ if (!FlagManager::getInstance().adpf_gpu_sf()) {
+ displayData.gpuStartTime = TimePoint::now();
+ }
}
void PowerAdvisor::setHwcValidateTiming(DisplayId displayId, TimePoint validateStartTime,
@@ -391,9 +409,8 @@
mDisplayTimingData[displayId].skippedValidate = skipped;
}
-void PowerAdvisor::setRequiresClientComposition(DisplayId displayId,
- bool requiresClientComposition) {
- mDisplayTimingData[displayId].usedClientComposition = requiresClientComposition;
+void PowerAdvisor::setRequiresRenderEngine(DisplayId displayId, bool requiresRenderEngine) {
+ mDisplayTimingData[displayId].requiresRenderEngine = requiresRenderEngine;
}
void PowerAdvisor::setExpectedPresentTime(TimePoint expectedPresentTime) {
@@ -401,8 +418,8 @@
}
void PowerAdvisor::setSfPresentTiming(TimePoint presentFenceTime, TimePoint presentEndTime) {
- mLastSfPresentEndTime = presentEndTime;
mLastPresentFenceTime = presentFenceTime;
+ mLastSfPresentEndTime = presentEndTime;
}
void PowerAdvisor::setFrameDelay(Duration frameDelayDuration) {
@@ -443,7 +460,7 @@
return sortedDisplays;
}
-std::optional<Duration> PowerAdvisor::estimateWorkDuration() {
+std::optional<WorkDuration> PowerAdvisor::estimateWorkDuration() {
if (!mExpectedPresentTimes.isFull() || !mCommitStartTimes.isFull()) {
return std::nullopt;
}
@@ -462,11 +479,10 @@
// used to accumulate gpu time as we iterate over the active displays
std::optional<TimePoint> estimatedGpuEndTime;
- // The timing info for the previously calculated display, if there was one
- std::optional<DisplayTimeline> previousDisplayTiming;
std::vector<DisplayId>&& displayIds =
getOrderedDisplayIds(&DisplayTimingData::hwcPresentStartTime);
DisplayTimeline displayTiming;
+ std::optional<GpuTimeline> firstGpuTimeline;
// Iterate over the displays that use hwc in the same order they are presented
for (DisplayId displayId : displayIds) {
@@ -478,14 +494,6 @@
displayTiming = displayData.calculateDisplayTimeline(mLastPresentFenceTime);
- // If this is the first display, include the duration before hwc present starts
- if (!previousDisplayTiming.has_value()) {
- estimatedHwcEndTime += displayTiming.hwcPresentStartTime - mCommitStartTimes[0];
- } else { // Otherwise add the time since last display's hwc present finished
- estimatedHwcEndTime +=
- displayTiming.hwcPresentStartTime - previousDisplayTiming->hwcPresentEndTime;
- }
-
// Update predicted present finish time with this display's present time
estimatedHwcEndTime = displayTiming.hwcPresentEndTime;
@@ -500,6 +508,9 @@
// Estimate the reference frame's gpu timing
auto gpuTiming = displayData.estimateGpuTiming(previousValidGpuEndTime);
if (gpuTiming.has_value()) {
+ if (!firstGpuTimeline.has_value()) {
+ firstGpuTimeline = gpuTiming;
+ }
previousValidGpuEndTime = gpuTiming->startTime + gpuTiming->duration;
// Estimate the prediction frame's gpu end time from the reference frame
@@ -507,9 +518,7 @@
estimatedGpuEndTime.value_or(TimePoint{0ns})) +
gpuTiming->duration;
}
- previousDisplayTiming = displayTiming;
}
- ATRACE_INT64("Idle duration", idleDuration.ns());
TimePoint estimatedFlingerEndTime = mLastSfPresentEndTime;
@@ -522,15 +531,36 @@
Duration totalDuration = mFrameDelayDuration +
std::max(estimatedHwcEndTime, estimatedGpuEndTime.value_or(TimePoint{0ns})) -
mCommitStartTimes[0];
+ Duration totalDurationWithoutGpu =
+ mFrameDelayDuration + estimatedHwcEndTime - mCommitStartTimes[0];
// We finish SurfaceFlinger when post-composition finishes, so add that in here
Duration flingerDuration =
estimatedFlingerEndTime + mLastPostcompDuration - mCommitStartTimes[0];
+ Duration estimatedGpuDuration = firstGpuTimeline.has_value()
+ ? estimatedGpuEndTime.value_or(TimePoint{0ns}) - firstGpuTimeline->startTime
+ : Duration::fromNs(0);
// Combine the two timings into a single normalized one
Duration combinedDuration = combineTimingEstimates(totalDuration, flingerDuration);
+ Duration cpuDuration = combineTimingEstimates(totalDurationWithoutGpu, flingerDuration);
- return std::make_optional(combinedDuration);
+ WorkDuration duration{
+ .timeStampNanos = TimePoint::now().ns(),
+ .durationNanos = combinedDuration.ns(),
+ .workPeriodStartTimestampNanos = mCommitStartTimes[0].ns(),
+ .cpuDurationNanos = FlagManager::getInstance().adpf_gpu_sf() ? cpuDuration.ns() : 0,
+ .gpuDurationNanos =
+ FlagManager::getInstance().adpf_gpu_sf() ? estimatedGpuDuration.ns() : 0,
+ };
+ if (sTraceHintSessionData) {
+ ATRACE_INT64("Idle duration", idleDuration.ns());
+ ATRACE_INT64("First GPU start", firstGpuTimeline->startTime.ns());
+ ATRACE_INT64("First GPU duration", firstGpuTimeline->duration.ns());
+ ATRACE_INT64("Total duration", totalDuration.ns());
+ ATRACE_INT64("Flinger duration", flingerDuration.ns());
+ }
+ return std::make_optional(duration);
}
Duration PowerAdvisor::combineTimingEstimates(Duration totalDuration, Duration flingerDuration) {
@@ -581,7 +611,7 @@
std::optional<PowerAdvisor::GpuTimeline> PowerAdvisor::DisplayTimingData::estimateGpuTiming(
std::optional<TimePoint> previousEndTime) {
- if (!(usedClientComposition && lastValidGpuStartTime.has_value() && gpuEndFenceTime)) {
+ if (!(requiresRenderEngine && lastValidGpuStartTime.has_value() && gpuEndFenceTime)) {
return std::nullopt;
}
const TimePoint latestGpuStartTime =
@@ -606,7 +636,7 @@
}
const bool PowerAdvisor::sTraceHintSessionData =
- base::GetBoolProperty(std::string("debug.sf.trace_hint_sessions"), false);
+ base::GetBoolProperty(std::string("debug.sf.trace_hint_sessions"), true);
const Duration PowerAdvisor::sTargetSafetyMargin = std::chrono::microseconds(
base::GetIntProperty<int64_t>("debug.sf.hint_margin_us",
diff --git a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
index 13e1263..60967b0 100644
--- a/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
+++ b/services/surfaceflinger/DisplayHardware/PowerAdvisor.h
@@ -68,6 +68,8 @@
virtual void enablePowerHintSession(bool enabled) = 0;
// Initializes the power hint session
virtual bool startPowerHintSession(std::vector<int32_t>&& threadIds) = 0;
+ // Provides PowerAdvisor with gpu start time
+ virtual void setGpuStartTime(DisplayId displayId, TimePoint startTime) = 0;
// Provides PowerAdvisor with a copy of the gpu fence so it can determine the gpu end time
virtual void setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime) = 0;
// Reports the start and end times of a hwc validate call this frame for a given display
@@ -80,9 +82,8 @@
virtual void setExpectedPresentTime(TimePoint expectedPresentTime) = 0;
// Reports the most recent present fence time and end time once known
virtual void setSfPresentTiming(TimePoint presentFenceTime, TimePoint presentEndTime) = 0;
- // Reports whether a display used client composition this frame
- virtual void setRequiresClientComposition(DisplayId displayId,
- bool requiresClientComposition) = 0;
+ // Reports whether a display requires RenderEngine to draw
+ virtual void setRequiresRenderEngine(DisplayId displayId, bool requiresRenderEngine) = 0;
// Reports whether a given display skipped validation this frame
virtual void setSkippedValidate(DisplayId displayId, bool skipped) = 0;
// Reports when a hwc present is delayed, and the time that it will resume
@@ -125,13 +126,14 @@
void reportActualWorkDuration() override;
void enablePowerHintSession(bool enabled) override;
bool startPowerHintSession(std::vector<int32_t>&& threadIds) override;
+ void setGpuStartTime(DisplayId displayId, TimePoint startTime) override;
void setGpuFenceTime(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime) override;
void setHwcValidateTiming(DisplayId displayId, TimePoint validateStartTime,
TimePoint validateEndTime) override;
void setHwcPresentTiming(DisplayId displayId, TimePoint presentStartTime,
TimePoint presentEndTime) override;
void setSkippedValidate(DisplayId displayId, bool skipped) override;
- void setRequiresClientComposition(DisplayId displayId, bool requiresClientComposition) override;
+ void setRequiresRenderEngine(DisplayId displayId, bool requiresRenderEngine);
void setExpectedPresentTime(TimePoint expectedPresentTime) override;
void setSfPresentTiming(TimePoint presentFenceTime, TimePoint presentEndTime) override;
void setHwcPresentDelayedTime(DisplayId displayId, TimePoint earliestFrameStartTime) override;
@@ -192,7 +194,7 @@
std::optional<TimePoint> hwcValidateStartTime;
std::optional<TimePoint> hwcValidateEndTime;
std::optional<TimePoint> hwcPresentDelayedTime;
- bool usedClientComposition = false;
+ bool requiresRenderEngine = false;
bool skippedValidate = false;
// Calculate high-level timing milestones from more granular display timing data
DisplayTimeline calculateDisplayTimeline(TimePoint fenceTime);
@@ -224,8 +226,8 @@
// Filter and sort the display ids by a given property
std::vector<DisplayId> getOrderedDisplayIds(
std::optional<TimePoint> DisplayTimingData::*sortBy);
- // Estimates a frame's total work duration including gpu time.
- std::optional<Duration> estimateWorkDuration();
+ // Estimates a frame's total work duration including gpu and gpu time.
+ std::optional<aidl::android::hardware::power::WorkDuration> estimateWorkDuration();
// There are two different targets and actual work durations we care about,
// this normalizes them together and takes the max of the two
Duration combineTimingEstimates(Duration totalDuration, Duration flingerDuration);
@@ -235,7 +237,6 @@
bool ensurePowerHintSessionRunning() REQUIRES(mHintSessionMutex);
std::unordered_map<DisplayId, DisplayTimingData> mDisplayTimingData;
-
// Current frame's delay
Duration mFrameDelayDuration{0ns};
// Last frame's post-composition duration
@@ -272,7 +273,6 @@
std::vector<aidl::android::hardware::power::WorkDuration> mHintSessionQueue;
// The latest values we have received for target and actual
Duration mTargetDuration = kDefaultTargetDuration;
- std::optional<Duration> mActualDuration;
// The list of thread ids, stored so we can restart the session from this class if needed
std::vector<int32_t> mHintSessionThreadIds;
Duration mLastTargetDurationSent = kDefaultTargetDuration;
diff --git a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp
index d9343c7..86ad86e 100644
--- a/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/PowerAdvisorTest.cpp
@@ -20,6 +20,8 @@
#include <DisplayHardware/PowerAdvisor.h>
#include <android_os.h>
#include <binder/Status.h>
+#include <com_android_graphics_surfaceflinger_flags.h>
+#include <common/FlagManager.h>
#include <common/test/FlagUtils.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -51,6 +53,20 @@
void setTimingTestingMode(bool testinMode);
void allowReportActualToAcquireMutex();
bool sessionExists();
+ int64_t toNanos(Duration d);
+
+ struct GpuTestConfig {
+ bool adpfGpuFlagOn;
+ Duration frame1GpuFenceDuration;
+ Duration frame2GpuFenceDuration;
+ Duration vsyncPeriod;
+ Duration presentDuration = 0ms;
+ Duration postCompDuration = 0ms;
+ bool frame1RequiresRenderEngine;
+ bool frame2RequiresRenderEngine;
+ };
+
+ WorkDuration testGpuScenario(GpuTestConfig& config);
protected:
TestableSurfaceFlinger mFlinger;
@@ -65,6 +81,10 @@
return mPowerAdvisor->mHintSession != nullptr;
}
+int64_t PowerAdvisorTest::toNanos(Duration d) {
+ return std::chrono::nanoseconds(d).count();
+}
+
void PowerAdvisorTest::SetUp() {
mPowerAdvisor = std::make_unique<impl::PowerAdvisor>(*mFlinger.flinger());
mPowerAdvisor->mPowerHal = std::make_unique<NiceMock<MockPowerHalController>>();
@@ -117,6 +137,71 @@
mPowerAdvisor->mDelayReportActualMutexAcquisitonPromise.set_value(true);
}
+WorkDuration PowerAdvisorTest::testGpuScenario(GpuTestConfig& config) {
+ SET_FLAG_FOR_TEST(com::android::graphics::surfaceflinger::flags::adpf_gpu_sf,
+ config.adpfGpuFlagOn);
+ mPowerAdvisor->onBootFinished();
+ startPowerHintSession();
+
+ std::vector<DisplayId> displayIds{PhysicalDisplayId::fromPort(42u), GpuVirtualDisplayId(0),
+ GpuVirtualDisplayId(1)};
+ mPowerAdvisor->setDisplays(displayIds);
+ auto display1 = displayIds[0];
+ // 60hz
+
+ TimePoint startTime = TimePoint::now();
+ // advisor only starts on frame 2 so do an initial frame
+ fakeBasicFrameTiming(startTime, config.vsyncPeriod);
+ setExpectedTiming(config.vsyncPeriod, startTime + config.vsyncPeriod);
+
+ // report GPU
+ mPowerAdvisor->setRequiresRenderEngine(display1, config.frame1RequiresRenderEngine);
+ if (config.adpfGpuFlagOn) {
+ mPowerAdvisor->setGpuStartTime(display1, startTime);
+ }
+ if (config.frame1GpuFenceDuration.count() == Fence::SIGNAL_TIME_PENDING) {
+ mPowerAdvisor->setGpuFenceTime(display1,
+ std::make_unique<FenceTime>(Fence::SIGNAL_TIME_PENDING));
+ } else {
+ TimePoint end = startTime + config.frame1GpuFenceDuration;
+ mPowerAdvisor->setGpuFenceTime(display1, std::make_unique<FenceTime>(end.ns()));
+ }
+
+ // increment the frame
+ std::this_thread::sleep_for(config.vsyncPeriod);
+ startTime = TimePoint::now();
+ fakeBasicFrameTiming(startTime, config.vsyncPeriod);
+ setExpectedTiming(config.vsyncPeriod, startTime + config.vsyncPeriod);
+
+ // report GPU
+ mPowerAdvisor->setRequiresRenderEngine(display1, config.frame2RequiresRenderEngine);
+ if (config.adpfGpuFlagOn) {
+ mPowerAdvisor->setGpuStartTime(display1, startTime);
+ }
+ if (config.frame2GpuFenceDuration.count() == Fence::SIGNAL_TIME_PENDING) {
+ mPowerAdvisor->setGpuFenceTime(display1,
+ std::make_unique<FenceTime>(Fence::SIGNAL_TIME_PENDING));
+ } else {
+ TimePoint end = startTime + config.frame2GpuFenceDuration;
+ mPowerAdvisor->setGpuFenceTime(display1, std::make_unique<FenceTime>(end.ns()));
+ }
+ mPowerAdvisor->setSfPresentTiming(startTime, startTime + config.presentDuration);
+ mPowerAdvisor->setCompositeEnd(startTime + config.presentDuration + config.postCompDuration);
+
+ // don't report timing for the HWC
+ mPowerAdvisor->setHwcValidateTiming(displayIds[0], startTime, startTime);
+ mPowerAdvisor->setHwcPresentTiming(displayIds[0], startTime, startTime);
+
+ std::vector<aidl::android::hardware::power::WorkDuration> durationReq;
+ EXPECT_CALL(*mMockPowerHintSession, reportActualWorkDuration(_))
+ .Times(1)
+ .WillOnce(DoAll(testing::SaveArg<0>(&durationReq),
+ testing::Return(testing::ByMove(HalResult<void>::ok()))));
+ mPowerAdvisor->reportActualWorkDuration();
+ EXPECT_EQ(durationReq.size(), 1u);
+ return durationReq[0];
+}
+
Duration PowerAdvisorTest::getFenceWaitDelayDuration(bool skipValidate) {
return (skipValidate ? PowerAdvisor::kFenceWaitStartDelaySkippedValidate
: PowerAdvisor::kFenceWaitStartDelayValidated);
@@ -390,5 +475,148 @@
mPowerAdvisor->startPowerHintSession({1, 2, 3});
}
+TEST_F(PowerAdvisorTest, setGpuFenceTime_cpuThenGpuFrames) {
+ GpuTestConfig config{
+ .adpfGpuFlagOn = false,
+ // faked buffer fence time for testing
+ .frame1GpuFenceDuration = 41ms,
+ .frame2GpuFenceDuration = 31ms,
+ .vsyncPeriod = 10ms,
+ .presentDuration = 2ms,
+ .postCompDuration = 8ms,
+ .frame1RequiresRenderEngine = false,
+ .frame2RequiresRenderEngine = true,
+ };
+ WorkDuration res = testGpuScenario(config);
+ EXPECT_EQ(res.gpuDurationNanos, 0L);
+ EXPECT_EQ(res.cpuDurationNanos, 0L);
+ EXPECT_GE(res.durationNanos, toNanos(30ms + getErrorMargin()));
+ EXPECT_LE(res.durationNanos, toNanos(31ms + getErrorMargin()));
+}
+
+TEST_F(PowerAdvisorTest, setGpuFenceTime_cpuThenGpuFrames_flagOn) {
+ GpuTestConfig config{
+ .adpfGpuFlagOn = true,
+ .frame1GpuFenceDuration = 40ms,
+ .frame2GpuFenceDuration = 30ms,
+ .vsyncPeriod = 10ms,
+ .presentDuration = 2ms,
+ .postCompDuration = 8ms,
+ .frame1RequiresRenderEngine = false,
+ .frame2RequiresRenderEngine = true,
+ };
+ WorkDuration res = testGpuScenario(config);
+ EXPECT_EQ(res.gpuDurationNanos, toNanos(30ms));
+ EXPECT_EQ(res.cpuDurationNanos, toNanos(10ms));
+ EXPECT_EQ(res.durationNanos, toNanos(30ms + getErrorMargin()));
+}
+
+TEST_F(PowerAdvisorTest, setGpuFenceTime_gpuThenCpuFrames) {
+ GpuTestConfig config{
+ .adpfGpuFlagOn = false,
+ // faked fence time for testing
+ .frame1GpuFenceDuration = 41ms,
+ .frame2GpuFenceDuration = 31ms,
+ .vsyncPeriod = 10ms,
+ .presentDuration = 2ms,
+ .postCompDuration = 8ms,
+ .frame1RequiresRenderEngine = true,
+ .frame2RequiresRenderEngine = false,
+ };
+ WorkDuration res = testGpuScenario(config);
+ EXPECT_EQ(res.gpuDurationNanos, 0L);
+ EXPECT_EQ(res.cpuDurationNanos, 0L);
+ EXPECT_EQ(res.durationNanos, toNanos(10ms + getErrorMargin()));
+}
+
+TEST_F(PowerAdvisorTest, setGpuFenceTime_gpuThenCpuFrames_flagOn) {
+ GpuTestConfig config{
+ .adpfGpuFlagOn = true,
+ .frame1GpuFenceDuration = 40ms,
+ .frame2GpuFenceDuration = 30ms,
+ .vsyncPeriod = 10ms,
+ .presentDuration = 2ms,
+ .postCompDuration = 8ms,
+ .frame1RequiresRenderEngine = true,
+ .frame2RequiresRenderEngine = false,
+ };
+ WorkDuration res = testGpuScenario(config);
+ EXPECT_EQ(res.gpuDurationNanos, 0L);
+ EXPECT_EQ(res.cpuDurationNanos, toNanos(10ms));
+ EXPECT_EQ(res.durationNanos, toNanos(10ms + getErrorMargin()));
+}
+
+TEST_F(PowerAdvisorTest, setGpuFenceTime_twoSignaledGpuFrames) {
+ GpuTestConfig config{
+ .adpfGpuFlagOn = false,
+ // added a margin as a workaround since we set GPU start time at the time of fence set
+ // call
+ .frame1GpuFenceDuration = 31ms,
+ .frame2GpuFenceDuration = 51ms,
+ .vsyncPeriod = 10ms,
+ .presentDuration = 2ms,
+ .postCompDuration = 8ms,
+ .frame1RequiresRenderEngine = true,
+ .frame2RequiresRenderEngine = true,
+ };
+ WorkDuration res = testGpuScenario(config);
+ EXPECT_EQ(res.gpuDurationNanos, 0L);
+ EXPECT_EQ(res.cpuDurationNanos, 0L);
+ EXPECT_GE(res.durationNanos, toNanos(50ms + getErrorMargin()));
+ EXPECT_LE(res.durationNanos, toNanos(51ms + getErrorMargin()));
+}
+
+TEST_F(PowerAdvisorTest, setGpuFenceTime_twoSignaledGpuFenceFrames_flagOn) {
+ GpuTestConfig config{
+ .adpfGpuFlagOn = true,
+ .frame1GpuFenceDuration = 30ms,
+ .frame2GpuFenceDuration = 50ms,
+ .vsyncPeriod = 10ms,
+ .presentDuration = 2ms,
+ .postCompDuration = 8ms,
+ .frame1RequiresRenderEngine = true,
+ .frame2RequiresRenderEngine = true,
+ };
+ WorkDuration res = testGpuScenario(config);
+ EXPECT_EQ(res.gpuDurationNanos, toNanos(50ms));
+ EXPECT_EQ(res.cpuDurationNanos, toNanos(10ms));
+ EXPECT_EQ(res.durationNanos, toNanos(50ms + getErrorMargin()));
+}
+
+TEST_F(PowerAdvisorTest, setGpuFenceTime_UnsingaledGpuFenceFrameUsingPreviousFrame) {
+ GpuTestConfig config{
+ .adpfGpuFlagOn = false,
+ .frame1GpuFenceDuration = 31ms,
+ .frame2GpuFenceDuration = Duration::fromNs(Fence::SIGNAL_TIME_PENDING),
+ .vsyncPeriod = 10ms,
+ .presentDuration = 2ms,
+ .postCompDuration = 8ms,
+ .frame1RequiresRenderEngine = true,
+ .frame2RequiresRenderEngine = true,
+ };
+ WorkDuration res = testGpuScenario(config);
+ EXPECT_EQ(res.gpuDurationNanos, 0L);
+ EXPECT_EQ(res.cpuDurationNanos, 0L);
+ EXPECT_GE(res.durationNanos, toNanos(30ms + getErrorMargin()));
+ EXPECT_LE(res.durationNanos, toNanos(31ms + getErrorMargin()));
+}
+
+TEST_F(PowerAdvisorTest, setGpuFenceTime_UnsingaledGpuFenceFrameUsingPreviousFrame_flagOn) {
+ GpuTestConfig config{
+ .adpfGpuFlagOn = true,
+ .frame1GpuFenceDuration = 30ms,
+ .frame2GpuFenceDuration = Duration::fromNs(Fence::SIGNAL_TIME_PENDING),
+ .vsyncPeriod = 10ms,
+ .presentDuration = 22ms,
+ .postCompDuration = 88ms,
+ .frame1RequiresRenderEngine = true,
+ .frame2RequiresRenderEngine = true,
+ };
+ WorkDuration res = testGpuScenario(config);
+ EXPECT_EQ(res.gpuDurationNanos, toNanos(30ms));
+ EXPECT_EQ(res.cpuDurationNanos, toNanos(110ms));
+ EXPECT_EQ(res.durationNanos, toNanos(110ms + getErrorMargin()));
+}
+
} // namespace
} // namespace android::Hwc2::impl
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
index 8e8eb1d..e8630ba 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockPowerAdvisor.h
@@ -40,6 +40,7 @@
MOCK_METHOD(void, reportActualWorkDuration, (), (override));
MOCK_METHOD(void, enablePowerHintSession, (bool enabled), (override));
MOCK_METHOD(bool, startPowerHintSession, (std::vector<int32_t> && threadIds), (override));
+ MOCK_METHOD(void, setGpuStartTime, (DisplayId displayId, TimePoint startTime), (override));
MOCK_METHOD(void, setGpuFenceTime,
(DisplayId displayId, std::unique_ptr<FenceTime>&& fenceTime), (override));
MOCK_METHOD(void, setHwcValidateTiming,
@@ -49,8 +50,8 @@
(DisplayId displayId, TimePoint presentStartTime, TimePoint presentEndTime),
(override));
MOCK_METHOD(void, setSkippedValidate, (DisplayId displayId, bool skipped), (override));
- MOCK_METHOD(void, setRequiresClientComposition,
- (DisplayId displayId, bool requiresClientComposition), (override));
+ MOCK_METHOD(void, setRequiresRenderEngine, (DisplayId displayId, bool requiresRenderEngine),
+ (override));
MOCK_METHOD(void, setExpectedPresentTime, (TimePoint expectedPresentTime), (override));
MOCK_METHOD(void, setSfPresentTiming, (TimePoint presentFenceTime, TimePoint presentEndTime),
(override));