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/include/compositionengine/CompositionRefreshArgs.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
index 1a235e9..18a96f4 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/CompositionRefreshArgs.h
@@ -24,6 +24,7 @@
#include <compositionengine/LayerFE.h>
#include <compositionengine/OutputColorSetting.h>
#include <math/mat4.h>
+#include <scheduler/interface/ICompositor.h>
#include <ui/FenceTime.h>
#include <ui/Transform.h>
@@ -89,17 +90,14 @@
// If set, causes the dirty regions to flash with the delay
std::optional<std::chrono::microseconds> devOptFlashDirtyRegionsDelay;
- // Optional.
- // The earliest time to send the present command to the HAL.
- std::optional<std::chrono::steady_clock::time_point> earliestPresentTime;
-
- // The expected time for the next present
- nsecs_t expectedPresentTime{0};
+ scheduler::FrameTargets frameTargets;
// The frameInterval for the next present
- Fps frameInterval{};
+ // TODO (b/315371484): Calculate per display and store on `FrameTarget`.
+ Fps frameInterval;
// If set, a frame has been scheduled for that time.
+ // TODO (b/255601557): Calculate per display.
std::optional<std::chrono::steady_clock::time_point> scheduledFrameTime;
std::vector<BorderRenderInfo> borderInfoList;
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;