Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 370b8b52 authored by Leon Scroggins III's avatar Leon Scroggins III
Browse files

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
parent 0bd0d4c6
Loading
Loading
Loading
Loading
+5 −7
Original line number Diff line number Diff line
@@ -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 @@ struct CompositionRefreshArgs {
    // 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;
+33 −3
Original line number Diff line number Diff line
@@ -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 @@ void Output::prepare(const compositionengine::CompositionRefreshArgs& refreshArg

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 @@ void Output::writeCompositionState(const compositionengine::CompositionRefreshAr
        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;

+10 −2
Original line number Diff line number Diff line
@@ -190,7 +190,6 @@ void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId,
    const FrameTargeter::BeginFrameArgs beginFrameArgs =
            {.frameBeginTime = SchedulerClock::now(),
             .vsyncId = vsyncId,
             // TODO(b/255601557): Calculate per display.
             .expectedVsyncTime = expectedVsyncTime,
             .sfWorkDuration = mVsyncModulator->getVsyncConfig().sfWorkDuration,
             .hwcMinWorkDuration = mVsyncConfiguration->getCurrentConfigs().hwcMinWorkDuration};
@@ -202,11 +201,20 @@ void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId,
        FrameTargets targets;
        targets.try_emplace(pacesetterPtr->displayId, &pacesetterPtr->targeterPtr->target());

        // TODO (b/256196556): Followers should use the next VSYNC after the frontrunner, not the
        // pacesetter.
        // Update expectedVsyncTime, which may have been adjusted by beginFrame.
        expectedVsyncTime = pacesetterPtr->targeterPtr->target().expectedPresentTime();

        for (const auto& [id, display] : mDisplays) {
            if (id == pacesetterPtr->displayId) continue;

            auto followerBeginFrameArgs = beginFrameArgs;
            followerBeginFrameArgs.expectedVsyncTime =
                    display.schedulePtr->vsyncDeadlineAfter(expectedVsyncTime);

            FrameTargeter& targeter = *display.targeterPtr;
            targeter.beginFrame(beginFrameArgs, *display.schedulePtr);
            targeter.beginFrame(followerBeginFrameArgs, *display.schedulePtr);
            targets.try_emplace(id, &targeter.target());
        }

+2 −3
Original line number Diff line number Diff line
@@ -2681,6 +2681,8 @@ CompositeResultsPerDisplay SurfaceFlinger::composite(
        if (const auto display = getCompositionDisplayLocked(id)) {
            refreshArgs.outputs.push_back(display);
        }

        refreshArgs.frameTargets.try_emplace(id, &targeter->target());
    }

    std::vector<DisplayId> displayIds;
@@ -2753,9 +2755,6 @@ CompositeResultsPerDisplay SurfaceFlinger::composite(
    // TODO(b/255601557) Update frameInterval per display
    refreshArgs.frameInterval = mScheduler->getNextFrameInterval(pacesetterId, expectedPresentTime);
    refreshArgs.scheduledFrameTime = mScheduler->getScheduledFrameTime();
    refreshArgs.expectedPresentTime = expectedPresentTime.ns();
    // TODO(b/255601557): Calculate and pass per-display values for each FrameTarget.
    refreshArgs.earliestPresentTime = pacesetterTarget.earliestPresentTime();
    refreshArgs.hasTrustedPresentationListener = mNumTrustedPresentationListeners > 0;
    {
        auto& notifyExpectedPresentData = mNotifyExpectedPresentMap[pacesetterId];