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

Commit 6312599b authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "SF: Isolate modesetting in DisplayModeController" into main

parents 262b467e 5c989f5c
Loading
Loading
Loading
Loading
+195 −4
Original line number Diff line number Diff line
@@ -20,30 +20,221 @@

#include "Display/DisplayModeController.h"
#include "Display/DisplaySnapshot.h"
#include "DisplayHardware/HWComposer.h"

#include <common/FlagManager.h>
#include <ftl/concat.h>
#include <ftl/expected.h>
#include <log/log.h>

namespace android::display {

template <size_t N>
inline std::string DisplayModeController::Display::concatId(const char (&str)[N]) const {
    return std::string(ftl::Concat(str, ' ', snapshot.get().displayId().value).str());
}

DisplayModeController::Display::Display(DisplaySnapshotRef snapshot,
                                        RefreshRateSelectorPtr selectorPtr)
      : snapshot(snapshot),
        selectorPtr(std::move(selectorPtr)),
        pendingModeFpsTrace(concatId("PendingModeFps")),
        activeModeFpsTrace(concatId("ActiveModeFps")),
        renderRateFpsTrace(concatId("RenderRateFps")),
        hasDesiredModeTrace(concatId("HasDesiredMode"), false) {}

void DisplayModeController::registerDisplay(PhysicalDisplayId displayId,
                                            DisplaySnapshotRef snapshotRef,
                                            RefreshRateSelectorPtr selectorPtr) {
    std::lock_guard lock(mDisplayLock);
    mDisplays.emplace_or_replace(displayId, std::make_unique<Display>(snapshotRef, selectorPtr));
}

void DisplayModeController::registerDisplay(DisplaySnapshotRef snapshotRef,
                                            DisplayModeId activeModeId,
                                            scheduler::RefreshRateSelector::Config config) {
    const auto& snapshot = snapshotRef.get();
    const auto displayId = snapshot.displayId();

    mDisplays.emplace_or_replace(displayId, snapshotRef, snapshot.displayModes(), activeModeId,
                                 config);
    std::lock_guard lock(mDisplayLock);
    mDisplays.emplace_or_replace(displayId,
                                 std::make_unique<Display>(snapshotRef, snapshot.displayModes(),
                                                           activeModeId, config));
}

void DisplayModeController::unregisterDisplay(PhysicalDisplayId displayId) {
    std::lock_guard lock(mDisplayLock);
    const bool ok = mDisplays.erase(displayId);
    ALOGE_IF(!ok, "%s: Unknown display %s", __func__, to_string(displayId).c_str());
}

auto DisplayModeController::selectorPtrFor(PhysicalDisplayId displayId) -> RefreshRateSelectorPtr {
auto DisplayModeController::selectorPtrFor(PhysicalDisplayId displayId) const
        -> RefreshRateSelectorPtr {
    std::lock_guard lock(mDisplayLock);
    return mDisplays.get(displayId)
            .transform([](const Display& display) { return display.selectorPtr; })
            .transform([](const DisplayPtr& displayPtr) { return displayPtr->selectorPtr; })
            .value_or(nullptr);
}

auto DisplayModeController::setDesiredMode(PhysicalDisplayId displayId,
                                           DisplayModeRequest&& desiredMode) -> DesiredModeAction {
    std::lock_guard lock(mDisplayLock);
    const auto& displayPtr =
            FTL_EXPECT(mDisplays.get(displayId).ok_or(DesiredModeAction::None)).get();

    {
        ATRACE_NAME(displayPtr->concatId(__func__).c_str());
        ALOGD("%s %s", displayPtr->concatId(__func__).c_str(), to_string(desiredMode).c_str());

        std::scoped_lock lock(displayPtr->desiredModeLock);

        if (auto& desiredModeOpt = displayPtr->desiredModeOpt) {
            // A mode transition was already scheduled, so just override the desired mode.
            const bool emitEvent = desiredModeOpt->emitEvent;
            const bool force = desiredModeOpt->force;
            desiredModeOpt = std::move(desiredMode);
            desiredModeOpt->emitEvent |= emitEvent;
            if (FlagManager::getInstance().connected_display()) {
                desiredModeOpt->force |= force;
            }
            return DesiredModeAction::None;
        }

        // If the desired mode is already active...
        const auto activeMode = displayPtr->selectorPtr->getActiveMode();
        if (const auto& desiredModePtr = desiredMode.mode.modePtr;
            !desiredMode.force && activeMode.modePtr->getId() == desiredModePtr->getId()) {
            if (activeMode == desiredMode.mode) {
                return DesiredModeAction::None;
            }

            // ...but the render rate changed:
            setActiveModeLocked(displayId, desiredModePtr->getId(), desiredModePtr->getVsyncRate(),
                                desiredMode.mode.fps);
            return DesiredModeAction::InitiateRenderRateSwitch;
        }

        // Restore peak render rate to schedule the next frame as soon as possible.
        setActiveModeLocked(displayId, activeMode.modePtr->getId(),
                            activeMode.modePtr->getVsyncRate(), activeMode.modePtr->getPeakFps());

        // Initiate a mode change.
        displayPtr->desiredModeOpt = std::move(desiredMode);
        displayPtr->hasDesiredModeTrace = true;
    }

    return DesiredModeAction::InitiateDisplayModeSwitch;
}

auto DisplayModeController::getDesiredMode(PhysicalDisplayId displayId) const
        -> DisplayModeRequestOpt {
    std::lock_guard lock(mDisplayLock);
    const auto& displayPtr =
            FTL_EXPECT(mDisplays.get(displayId).ok_or(DisplayModeRequestOpt())).get();

    {
        std::scoped_lock lock(displayPtr->desiredModeLock);
        return displayPtr->desiredModeOpt;
    }
}

auto DisplayModeController::getPendingMode(PhysicalDisplayId displayId) const
        -> DisplayModeRequestOpt {
    std::lock_guard lock(mDisplayLock);
    const auto& displayPtr =
            FTL_EXPECT(mDisplays.get(displayId).ok_or(DisplayModeRequestOpt())).get();

    {
        std::scoped_lock lock(displayPtr->desiredModeLock);
        return displayPtr->pendingModeOpt;
    }
}

bool DisplayModeController::isModeSetPending(PhysicalDisplayId displayId) const {
    std::lock_guard lock(mDisplayLock);
    const auto& displayPtr = FTL_EXPECT(mDisplays.get(displayId).ok_or(false)).get();

    {
        std::scoped_lock lock(displayPtr->desiredModeLock);
        return displayPtr->isModeSetPending;
    }
}

scheduler::FrameRateMode DisplayModeController::getActiveMode(PhysicalDisplayId displayId) const {
    return selectorPtrFor(displayId)->getActiveMode();
}

void DisplayModeController::clearDesiredMode(PhysicalDisplayId displayId) {
    std::lock_guard lock(mDisplayLock);
    const auto& displayPtr = FTL_TRY(mDisplays.get(displayId).ok_or(ftl::Unit())).get();

    {
        std::scoped_lock lock(displayPtr->desiredModeLock);
        displayPtr->desiredModeOpt.reset();
        displayPtr->hasDesiredModeTrace = false;
    }
}

bool DisplayModeController::initiateModeChange(PhysicalDisplayId displayId,
                                               DisplayModeRequest&& desiredMode,
                                               const hal::VsyncPeriodChangeConstraints& constraints,
                                               hal::VsyncPeriodChangeTimeline& outTimeline) {
    std::lock_guard lock(mDisplayLock);
    const auto& displayPtr = FTL_EXPECT(mDisplays.get(displayId).ok_or(false)).get();

    // TODO: b/255635711 - Flow the DisplayModeRequest through the desired/pending/active states.
    // For now, `desiredMode` and `desiredModeOpt` are one and the same, but the latter is not
    // cleared until the next `SF::initiateDisplayModeChanges`. However, the desired mode has been
    // consumed at this point, so clear the `force` flag to prevent an endless loop of
    // `initiateModeChange`.
    if (FlagManager::getInstance().connected_display()) {
        std::scoped_lock lock(displayPtr->desiredModeLock);
        if (displayPtr->desiredModeOpt) {
            displayPtr->desiredModeOpt->force = false;
        }
    }

    displayPtr->pendingModeOpt = std::move(desiredMode);
    displayPtr->isModeSetPending = true;

    const auto& mode = *displayPtr->pendingModeOpt->mode.modePtr;

    if (mComposerPtr->setActiveModeWithConstraints(displayId, mode.getHwcId(), constraints,
                                                   &outTimeline) != OK) {
        return false;
    }

    ATRACE_INT(displayPtr->pendingModeFpsTrace.c_str(), mode.getVsyncRate().getIntValue());
    return true;
}

void DisplayModeController::finalizeModeChange(PhysicalDisplayId displayId, DisplayModeId modeId,
                                               Fps vsyncRate, Fps renderFps) {
    std::lock_guard lock(mDisplayLock);
    setActiveModeLocked(displayId, modeId, vsyncRate, renderFps);

    const auto& displayPtr = FTL_TRY(mDisplays.get(displayId).ok_or(ftl::Unit())).get();
    displayPtr->isModeSetPending = false;
}

void DisplayModeController::setActiveMode(PhysicalDisplayId displayId, DisplayModeId modeId,
                                          Fps vsyncRate, Fps renderFps) {
    std::lock_guard lock(mDisplayLock);
    setActiveModeLocked(displayId, modeId, vsyncRate, renderFps);
}

void DisplayModeController::setActiveModeLocked(PhysicalDisplayId displayId, DisplayModeId modeId,
                                                Fps vsyncRate, Fps renderFps) {
    const auto& displayPtr = FTL_TRY(mDisplays.get(displayId).ok_or(ftl::Unit())).get();

    ATRACE_INT(displayPtr->activeModeFpsTrace.c_str(), vsyncRate.getIntValue());
    ATRACE_INT(displayPtr->renderRateFpsTrace.c_str(), renderFps.getIntValue());

    displayPtr->selectorPtr->setActiveMode(modeId, renderFps);

    if (mActiveModeListener) {
        mActiveModeListener(displayId, vsyncRate, renderFps);
    }
}

} // namespace android::display
+83 −16
Original line number Diff line number Diff line
@@ -17,16 +17,26 @@
#pragma once

#include <memory>
#include <mutex>
#include <string>
#include <utility>

#include <android-base/thread_annotations.h>
#include <ftl/function.h>
#include <ftl/optional.h>
#include <ui/DisplayId.h>
#include <ui/DisplayMap.h>

#include "Display/DisplayModeRequest.h"
#include "Display/DisplaySnapshotRef.h"
#include "DisplayHardware/DisplayMode.h"
#include "Scheduler/RefreshRateSelector.h"
#include "ThreadContext.h"
#include "TracedOrdinal.h"

namespace android {
class HWComposer;
} // namespace android

namespace android::display {

@@ -34,40 +44,97 @@ namespace android::display {
// certain heuristic signals.
class DisplayModeController {
public:
    // The referenced DisplaySnapshot must outlive the registration.
    void registerDisplay(DisplaySnapshotRef, DisplayModeId, scheduler::RefreshRateSelector::Config)
            REQUIRES(kMainThreadContext);
    void unregisterDisplay(PhysicalDisplayId) REQUIRES(kMainThreadContext);
    using ActiveModeListener = ftl::Function<void(PhysicalDisplayId, Fps vsyncRate, Fps renderFps)>;

    DisplayModeController() = default;

    // TODO(b/241285876): Remove once ownership is no longer shared with DisplayDevice.
    void setHwComposer(HWComposer* composerPtr) { mComposerPtr = composerPtr; }
    void setActiveModeListener(const ActiveModeListener& listener) {
        mActiveModeListener = listener;
    }

    // TODO: b/241285876 - Remove once ownership is no longer shared with DisplayDevice.
    using RefreshRateSelectorPtr = std::shared_ptr<scheduler::RefreshRateSelector>;

    // Used by tests to inject an existing RefreshRateSelector.
    // TODO: b/241285876 - Remove this.
    void registerDisplay(PhysicalDisplayId, DisplaySnapshotRef, RefreshRateSelectorPtr)
            EXCLUDES(mDisplayLock);

    // The referenced DisplaySnapshot must outlive the registration.
    void registerDisplay(DisplaySnapshotRef, DisplayModeId, scheduler::RefreshRateSelector::Config)
            REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock);
    void unregisterDisplay(PhysicalDisplayId) REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock);

    // Returns `nullptr` if the display is no longer registered (or never was).
    RefreshRateSelectorPtr selectorPtrFor(PhysicalDisplayId) REQUIRES(kMainThreadContext);
    RefreshRateSelectorPtr selectorPtrFor(PhysicalDisplayId) const EXCLUDES(mDisplayLock);

    // Used by tests to inject an existing RefreshRateSelector.
    // TODO(b/241285876): Remove this.
    void registerDisplay(PhysicalDisplayId displayId, DisplaySnapshotRef snapshotRef,
                         RefreshRateSelectorPtr selectorPtr) {
        mDisplays.emplace_or_replace(displayId, snapshotRef, selectorPtr);
    }
    enum class DesiredModeAction { None, InitiateDisplayModeSwitch, InitiateRenderRateSwitch };

    DesiredModeAction setDesiredMode(PhysicalDisplayId, DisplayModeRequest&&)
            EXCLUDES(mDisplayLock);

    using DisplayModeRequestOpt = ftl::Optional<DisplayModeRequest>;

    DisplayModeRequestOpt getDesiredMode(PhysicalDisplayId) const EXCLUDES(mDisplayLock);
    void clearDesiredMode(PhysicalDisplayId) EXCLUDES(mDisplayLock);

    DisplayModeRequestOpt getPendingMode(PhysicalDisplayId) const REQUIRES(kMainThreadContext)
            EXCLUDES(mDisplayLock);
    bool isModeSetPending(PhysicalDisplayId) const REQUIRES(kMainThreadContext)
            EXCLUDES(mDisplayLock);

    scheduler::FrameRateMode getActiveMode(PhysicalDisplayId) const EXCLUDES(mDisplayLock);

    bool initiateModeChange(PhysicalDisplayId, DisplayModeRequest&&,
                            const hal::VsyncPeriodChangeConstraints&,
                            hal::VsyncPeriodChangeTimeline& outTimeline)
            REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock);

    void finalizeModeChange(PhysicalDisplayId, DisplayModeId, Fps vsyncRate, Fps renderFps)
            REQUIRES(kMainThreadContext) EXCLUDES(mDisplayLock);

    void setActiveMode(PhysicalDisplayId, DisplayModeId, Fps vsyncRate, Fps renderFps)
            EXCLUDES(mDisplayLock);

private:
    struct Display {
        Display(DisplaySnapshotRef snapshot, RefreshRateSelectorPtr selectorPtr)
              : snapshot(snapshot), selectorPtr(std::move(selectorPtr)) {}
        template <size_t N>
        std::string concatId(const char (&)[N]) const;

        Display(DisplaySnapshotRef, RefreshRateSelectorPtr);
        Display(DisplaySnapshotRef snapshot, DisplayModes modes, DisplayModeId activeModeId,
                scheduler::RefreshRateSelector::Config config)
              : Display(snapshot,
                        std::make_shared<scheduler::RefreshRateSelector>(std::move(modes),
                                                                         activeModeId, config)) {}

        const DisplaySnapshotRef snapshot;
        const RefreshRateSelectorPtr selectorPtr;

        const std::string pendingModeFpsTrace;
        const std::string activeModeFpsTrace;
        const std::string renderRateFpsTrace;

        std::mutex desiredModeLock;
        DisplayModeRequestOpt desiredModeOpt GUARDED_BY(desiredModeLock);
        TracedOrdinal<bool> hasDesiredModeTrace GUARDED_BY(desiredModeLock);

        DisplayModeRequestOpt pendingModeOpt GUARDED_BY(kMainThreadContext);
        bool isModeSetPending GUARDED_BY(kMainThreadContext) = false;
    };

    ui::PhysicalDisplayMap<PhysicalDisplayId, Display> mDisplays;
    using DisplayPtr = std::unique_ptr<Display>;

    void setActiveModeLocked(PhysicalDisplayId, DisplayModeId, Fps vsyncRate, Fps renderFps)
            REQUIRES(mDisplayLock);

    // Set once when initializing the DisplayModeController, which the HWComposer must outlive.
    HWComposer* mComposerPtr = nullptr;

    ActiveModeListener mActiveModeListener;

    mutable std::mutex mDisplayLock;
    ui::PhysicalDisplayMap<PhysicalDisplayId, DisplayPtr> mDisplays GUARDED_BY(mDisplayLock);
};

} // namespace android::display
+6 −102
Original line number Diff line number Diff line
@@ -24,7 +24,6 @@

#define ATRACE_TAG ATRACE_TAG_GRAPHICS

#include <common/FlagManager.h>
#include <compositionengine/CompositionEngine.h>
#include <compositionengine/Display.h>
#include <compositionengine/DisplayColorProfile.h>
@@ -36,6 +35,7 @@
#include <compositionengine/RenderSurfaceCreationArgs.h>
#include <compositionengine/impl/OutputCompositionState.h>
#include <configstore/Utils.h>
#include <ftl/concat.h>
#include <log/log.h>
#include <system/window.h>

@@ -64,15 +64,11 @@ DisplayDevice::DisplayDevice(DisplayDeviceCreationArgs& args)
        mDisplayToken(args.displayToken),
        mSequenceId(args.sequenceId),
        mCompositionDisplay{args.compositionDisplay},
        mPendingModeFpsTrace(concatId("PendingModeFps")),
        mActiveModeFpsTrace(concatId("ActiveModeFps")),
        mRenderRateFpsTrace(concatId("RenderRateFps")),
        mPhysicalOrientation(args.physicalOrientation),
        mPowerMode(ftl::Concat("PowerMode ", getId().value).c_str(), args.initialPowerMode),
        mIsPrimary(args.isPrimary),
        mRequestedRefreshRate(args.requestedRefreshRate),
        mRefreshRateSelector(std::move(args.refreshRateSelector)),
        mHasDesiredModeTrace(concatId("HasDesiredMode"), false) {
        mRefreshRateSelector(std::move(args.refreshRateSelector)) {
    mCompositionDisplay->editState().isSecure = args.isSecure;
    mCompositionDisplay->editState().isProtected = args.isProtected;
    mCompositionDisplay->createRenderSurface(
@@ -204,47 +200,6 @@ bool DisplayDevice::isPoweredOn() const {
    return mPowerMode != hal::PowerMode::OFF;
}

void DisplayDevice::setActiveMode(DisplayModeId modeId, Fps vsyncRate, Fps renderFps) {
    ATRACE_INT(mActiveModeFpsTrace.c_str(), vsyncRate.getIntValue());
    ATRACE_INT(mRenderRateFpsTrace.c_str(), renderFps.getIntValue());

    mRefreshRateSelector->setActiveMode(modeId, renderFps);
    updateRefreshRateOverlayRate(vsyncRate, renderFps);
}

bool DisplayDevice::initiateModeChange(display::DisplayModeRequest&& desiredMode,
                                       const hal::VsyncPeriodChangeConstraints& constraints,
                                       hal::VsyncPeriodChangeTimeline& outTimeline) {
    // TODO(b/255635711): Flow the DisplayModeRequest through the desired/pending/active states. For
    // now, `desiredMode` and `mDesiredModeOpt` are one and the same, but the latter is not cleared
    // until the next `SF::initiateDisplayModeChanges`. However, the desired mode has been consumed
    // at this point, so clear the `force` flag to prevent an endless loop of `initiateModeChange`.
    if (FlagManager::getInstance().connected_display()) {
        std::scoped_lock lock(mDesiredModeLock);
        if (mDesiredModeOpt) {
            mDesiredModeOpt->force = false;
        }
    }

    mPendingModeOpt = std::move(desiredMode);
    mIsModeSetPending = true;

    const auto& mode = *mPendingModeOpt->mode.modePtr;

    if (mHwComposer.setActiveModeWithConstraints(getPhysicalId(), mode.getHwcId(), constraints,
                                                 &outTimeline) != OK) {
        return false;
    }

    ATRACE_INT(mPendingModeFpsTrace.c_str(), mode.getVsyncRate().getIntValue());
    return true;
}

void DisplayDevice::finalizeModeChange(DisplayModeId modeId, Fps vsyncRate, Fps renderFps) {
    setActiveMode(modeId, vsyncRate, renderFps);
    mIsModeSetPending = false;
}

nsecs_t DisplayDevice::getVsyncPeriodFromHWC() const {
    const auto physicalId = getPhysicalId();
    if (!mHwComposer.isConnected(physicalId)) {
@@ -450,8 +405,9 @@ void DisplayDevice::updateHdrSdrRatioOverlayRatio(float currentHdrSdrRatio) {
    }
}

void DisplayDevice::enableRefreshRateOverlay(bool enable, bool setByHwc, bool showSpinner,
                                             bool showRenderRate, bool showInMiddle) {
void DisplayDevice::enableRefreshRateOverlay(bool enable, bool setByHwc, Fps refreshRate,
                                             Fps renderFps, bool showSpinner, bool showRenderRate,
                                             bool showInMiddle) {
    if (!enable) {
        mRefreshRateOverlay.reset();
        return;
@@ -479,8 +435,7 @@ void DisplayDevice::enableRefreshRateOverlay(bool enable, bool setByHwc, bool sh
    if (mRefreshRateOverlay) {
        mRefreshRateOverlay->setLayerStack(getLayerStack());
        mRefreshRateOverlay->setViewport(getSize());
        updateRefreshRateOverlayRate(getActiveMode().modePtr->getVsyncRate(), getActiveMode().fps,
                                     setByHwc);
        updateRefreshRateOverlayRate(refreshRate, renderFps, setByHwc);
    }
}

@@ -531,57 +486,6 @@ void DisplayDevice::animateOverlay() {
    }
}

auto DisplayDevice::setDesiredMode(display::DisplayModeRequest&& desiredMode) -> DesiredModeAction {
    ATRACE_NAME(concatId(__func__).c_str());
    ALOGD("%s %s", concatId(__func__).c_str(), to_string(desiredMode).c_str());

    std::scoped_lock lock(mDesiredModeLock);
    if (mDesiredModeOpt) {
        // A mode transition was already scheduled, so just override the desired mode.
        const bool emitEvent = mDesiredModeOpt->emitEvent;
        const bool force = mDesiredModeOpt->force;
        mDesiredModeOpt = std::move(desiredMode);
        mDesiredModeOpt->emitEvent |= emitEvent;
        if (FlagManager::getInstance().connected_display()) {
            mDesiredModeOpt->force |= force;
        }
        return DesiredModeAction::None;
    }

    // If the desired mode is already active...
    const auto activeMode = refreshRateSelector().getActiveMode();
    if (const auto& desiredModePtr = desiredMode.mode.modePtr;
        !desiredMode.force && activeMode.modePtr->getId() == desiredModePtr->getId()) {
        if (activeMode == desiredMode.mode) {
            return DesiredModeAction::None;
        }

        // ...but the render rate changed:
        setActiveMode(desiredModePtr->getId(), desiredModePtr->getVsyncRate(),
                      desiredMode.mode.fps);
        return DesiredModeAction::InitiateRenderRateSwitch;
    }

    setActiveMode(activeMode.modePtr->getId(), activeMode.modePtr->getVsyncRate(),
                  activeMode.modePtr->getPeakFps());

    // Initiate a mode change.
    mDesiredModeOpt = std::move(desiredMode);
    mHasDesiredModeTrace = true;
    return DesiredModeAction::InitiateDisplayModeSwitch;
}

auto DisplayDevice::getDesiredMode() const -> DisplayModeRequestOpt {
    std::scoped_lock lock(mDesiredModeLock);
    return mDesiredModeOpt;
}

void DisplayDevice::clearDesiredMode() {
    std::scoped_lock lock(mDesiredModeLock);
    mDesiredModeOpt.reset();
    mHasDesiredModeTrace = false;
}

void DisplayDevice::adjustRefreshRate(Fps pacesetterDisplayRefreshRate) {
    using fps_approx_ops::operator<=;
    if (mRequestedRefreshRate <= 0_Hz) {
+5 −53

File changed.

Preview size limit exceeded, changes collapsed.

+109 −89

File changed.

Preview size limit exceeded, changes collapsed.

Loading