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);