SF: Predict HWC composition strategy
Asynchronously run ValidateDisplay to determine client composition
strategy. If we can predict that the composition strategy will not
change from frame to frame (for example by looking at whether
the geometry of the layers is changing), the hwc call is run
asynchronously with the gpu composition. If the result of the call is
incorrectly predicted, the gpu composition is rerun.
ValidateDisplay can take multiple milliseconds to complete and by
making it non-blocking in cases where we can predict the strategy
chosen by the hardware, we can jump start the client composition
and shave valuable milliseconds from the frame time.
This feature is disabled by default.
Test: perfetto traces
Bug: 220031739
Change-Id: Ia5f04f447455bba0bbebbe7642d8ade8313f381a
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 54daf38..84c22cf 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -207,16 +207,8 @@
setReleasedLayers(std::move(releasedLayers));
}
-void Display::chooseCompositionStrategy() {
- ATRACE_CALL();
- ALOGV(__FUNCTION__);
-
- if (mIsDisconnected) {
- return;
- }
-
- // Default to the base settings -- client composition only.
- Output::chooseCompositionStrategy();
+void Display::beginFrame() {
+ Output::beginFrame();
// If we don't have a HWC display, then we are done.
const auto halDisplayId = HalDisplayId::tryCast(mId);
@@ -224,8 +216,6 @@
return;
}
- // Get any composition changes requested by the HWC device, and apply them.
- std::optional<android::HWComposer::DeviceRequestedChanges> changes;
auto& hwc = getCompositionEngine().getHwComposer();
if (const auto physicalDisplayId = PhysicalDisplayId::tryCast(*halDisplayId);
physicalDisplayId && getState().displayBrightness) {
@@ -237,17 +227,43 @@
ALOGE_IF(result != NO_ERROR, "setDisplayBrightness failed for %s: %d, (%s)",
getName().c_str(), result, strerror(-result));
}
+ // Clear out the display brightness now that it's been communicated to composer.
+ editState().displayBrightness.reset();
+}
+bool Display::chooseCompositionStrategy(
+ std::optional<android::HWComposer::DeviceRequestedChanges>* outChanges) {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ if (mIsDisconnected) {
+ return false;
+ }
+
+ // If we don't have a HWC display, then we are done.
+ const auto halDisplayId = HalDisplayId::tryCast(mId);
+ if (!halDisplayId) {
+ return false;
+ }
+
+ // Get any composition changes requested by the HWC device, and apply them.
+ std::optional<android::HWComposer::DeviceRequestedChanges> changes;
+ auto& hwc = getCompositionEngine().getHwComposer();
if (status_t result =
hwc.getDeviceCompositionChanges(*halDisplayId, anyLayersRequireClientComposition(),
getState().earliestPresentTime,
getState().previousPresentFence,
- getState().expectedPresentTime, &changes);
+ getState().expectedPresentTime, outChanges);
result != NO_ERROR) {
ALOGE("chooseCompositionStrategy failed for %s: %d (%s)", getName().c_str(), result,
strerror(-result));
- return;
+ return false;
}
+
+ return true;
+}
+
+void Display::applyCompositionStrategy(const std::optional<DeviceRequestedChanges>& changes) {
if (changes) {
applyChangedTypesToLayers(changes->changedTypes);
applyDisplayRequests(changes->displayRequests);
@@ -259,8 +275,6 @@
auto& state = editState();
state.usesClientComposition = anyLayersRequireClientComposition();
state.usesDeviceComposition = !allLayersRequireClientComposition();
- // Clear out the display brightness now that it's been communicated to composer.
- state.displayBrightness.reset();
}
bool Display::getSkipColorTransform() const {
@@ -273,12 +287,6 @@
return hwc.hasCapability(Capability::SKIP_CLIENT_COLOR_TRANSFORM);
}
-bool Display::anyLayersRequireClientComposition() const {
- const auto layers = getOutputLayersOrderedByZ();
- return std::any_of(layers.begin(), layers.end(),
- [](const auto& layer) { return layer->requiresClientComposition(); });
-}
-
bool Display::allLayersRequireClientComposition() const {
const auto layers = getOutputLayersOrderedByZ();
return std::all_of(layers.begin(), layers.end(),
@@ -379,7 +387,8 @@
}
}
-void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs) {
+void Display::finishFrame(const compositionengine::CompositionRefreshArgs& refreshArgs,
+ GpuCompositionResult&& result) {
// We only need to actually compose the display if:
// 1) It is being handled by hardware composer, which may need this to
// keep its virtual display state machine in sync, or
@@ -389,7 +398,7 @@
return;
}
- impl::Output::finishFrame(refreshArgs);
+ impl::Output::finishFrame(refreshArgs, std::move(result));
}
} // namespace android::compositionengine::impl