SF multithreaded_present: clean up and add more tests
Add tests for CompositionEngine to verify that the displays which are
expected to offload HWC calls do so.
In CompositionEngine::present, improve the process for selecting which
displays to offload. In the old process, a virtual display without HAL
support could in theory return true for supportsOffloadPresent. Even
though it wasn't counted in the original number, it could then be told
to offload present, resulting in one of the intended displays not
offloading.
In the new process, store a list of eligible displays, so that only
eligible displays are told to offload. This also means that
supportsOffloadPresent is called at most once per frame.
Bug: 241285491
Bug: 259132483
Test: libcompositionengine_test
Change-Id: Ie2836e07e900c0269d60112ec0ebfa82ee4b82d7
diff --git a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
index 748d87b..7be5fe3 100644
--- a/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/CompositionEngine.cpp
@@ -90,29 +90,37 @@
}
namespace {
-int numDisplaysWithOffloadPresentSupport(const CompositionRefreshArgs& args) {
- if (!FlagManager::getInstance().multithreaded_present() || args.outputs.size() < 2) {
- return 0;
+void offloadOutputs(Outputs& outputs) {
+ if (!FlagManager::getInstance().multithreaded_present() || outputs.size() < 2) {
+ return;
}
- int numEligibleDisplays = 0;
- // Only run present in multiple threads if all HWC-enabled displays
- // being refreshed support it.
- if (!std::all_of(args.outputs.begin(), args.outputs.end(),
- [&numEligibleDisplays](const auto& output) {
- if (!ftl::Optional(output->getDisplayId())
- .and_then(HalDisplayId::tryCast)) {
- // Not HWC-enabled, so it is always
- // client-composited.
- return true;
- }
- const bool support = output->supportsOffloadPresent();
- numEligibleDisplays += static_cast<int>(support);
- return support;
- })) {
- return 0;
+ ui::PhysicalDisplayVector<compositionengine::Output*> outputsToOffload;
+ for (const auto& output : outputs) {
+ if (!ftl::Optional(output->getDisplayId()).and_then(HalDisplayId::tryCast)) {
+ // Not HWC-enabled, so it is always client-composited. No need to offload.
+ continue;
+ }
+
+ // Only run present in multiple threads if all HWC-enabled displays
+ // being refreshed support it.
+ if (!output->supportsOffloadPresent()) {
+ return;
+ }
+ outputsToOffload.push_back(output.get());
}
- return numEligibleDisplays;
+
+ if (outputsToOffload.size() < 2) {
+ return;
+ }
+
+ // Leave the last eligible display on the main thread, which will
+ // allow it to run concurrently without an extra thread hop.
+ outputsToOffload.pop_back();
+
+ for (compositionengine::Output* output : outputsToOffload) {
+ output->offloadPresentNextFrame();
+ }
}
} // namespace
@@ -136,20 +144,7 @@
// Offloading the HWC call for `present` allows us to simultaneously call it
// on multiple displays. This is desirable because these calls block and can
// be slow.
- if (const int numEligibleDisplays = numDisplaysWithOffloadPresentSupport(args);
- numEligibleDisplays > 1) {
- // Leave the last eligible display on the main thread, which will
- // allow it to run concurrently without an extra thread hop.
- int numToOffload = numEligibleDisplays - 1;
- for (auto& output : args.outputs) {
- if (output->supportsOffloadPresent()) {
- output->offloadPresentNextFrame();
- if (--numToOffload == 0) {
- break;
- }
- }
- }
- }
+ offloadOutputs(args.outputs);
ui::DisplayVector<ftl::Future<std::monostate>> presentFutures;
for (const auto& output : args.outputs) {