SF: Update present timing per display
Calculate presentation timing info (i.e. expected- and earliest-
PresentTime) separately for each display, since they are generally not
in sync. This allows SF to present each display at the proper time,
using tools that are already in use for the pacesetter display.
CompositionRefreshArgs:
- Replace earliest- and expected- PresentTime with a map of
FrameTargets which hold the times.
Output:
- Retrieve appropriate times from the relevant FrameTarget.
- Note: Since HAL virtual displays do not have a FrameTarget, they now
are provided with the default expected (0) and earliest (nullopt)
-PresentTimes. This is fine, since these times are irrelevant for
a virtual display. Previously, they simply used the pacesetter's
times.
- Trace the expected present time.
Scheduler:
- Compute the expectedPresentTime aka expectedVsyncTime for follower
displays via the next VSYNC after the pacesetter's
expectedPresentTime. TODO (b/256196556): The "followers" should
follow the frontrunner, not the pacesetter.
SurfaceFlinger:
- Populate CompositionRefreshArgs' map of FrameTargets.
For now, continue using the same scheduledFrameTime for all follower
displays. This is only used as a deadline for determining whether to
render a CachedSet. Adjusting it per follower would make us more likely
to render more CachedSets per frame, and we need a more holistic
approach for caching anyway.
Bug: 255601557
Bug: 256196556
Bug: 259132483
Test: perfetto traces
Change-Id: I2c27dc709afd1f33bddbf9c2ca1cd61dd335f66c
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 09c7c99..1c2f6cb 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -28,8 +28,11 @@
#include <compositionengine/impl/OutputLayer.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
#include <compositionengine/impl/planner/Planner.h>
+#include <ftl/algorithm.h>
#include <ftl/future.h>
#include <gui/TraceUtils.h>
+#include <scheduler/FrameTargeter.h>
+#include <scheduler/Time.h>
#include <optional>
#include <thread>
@@ -429,7 +432,28 @@
ftl::Future<std::monostate> Output::present(
const compositionengine::CompositionRefreshArgs& refreshArgs) {
- ATRACE_FORMAT("%s for %s", __func__, mNamePlusId.c_str());
+ const auto stringifyExpectedPresentTime = [this, &refreshArgs]() -> std::string {
+ return ftl::Optional(getDisplayId())
+ .and_then(PhysicalDisplayId::tryCast)
+ .and_then([&refreshArgs](PhysicalDisplayId id) {
+ return refreshArgs.frameTargets.get(id);
+ })
+ .transform([](const auto& frameTargetPtr) {
+ return frameTargetPtr.get()->expectedPresentTime();
+ })
+ .transform([](TimePoint expectedPresentTime) {
+ return base::StringPrintf(" vsyncIn %.2fms",
+ ticks<std::milli, float>(expectedPresentTime -
+ TimePoint::now()));
+ })
+ .or_else([] {
+ // There is no vsync for this output.
+ return std::make_optional(std::string());
+ })
+ .value();
+ };
+ ATRACE_FORMAT("%s for %s%s", __func__, mNamePlusId.c_str(),
+ stringifyExpectedPresentTime().c_str());
ALOGV(__FUNCTION__);
updateColorProfile(refreshArgs);
@@ -853,8 +877,14 @@
return;
}
- editState().earliestPresentTime = refreshArgs.earliestPresentTime;
- editState().expectedPresentTime = refreshArgs.expectedPresentTime;
+ if (auto frameTargetPtrOpt = ftl::Optional(getDisplayId())
+ .and_then(PhysicalDisplayId::tryCast)
+ .and_then([&refreshArgs](PhysicalDisplayId id) {
+ return refreshArgs.frameTargets.get(id);
+ })) {
+ editState().earliestPresentTime = frameTargetPtrOpt->get()->earliestPresentTime();
+ editState().expectedPresentTime = frameTargetPtrOpt->get()->expectedPresentTime().ns();
+ }
editState().frameInterval = refreshArgs.frameInterval;
editState().powerCallback = refreshArgs.powerCallback;