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

Commit 88217126 authored by Dominik Laskowski's avatar Dominik Laskowski Committed by Android (Google) Code Review
Browse files

Merge "Reland^2 "SF: Set an initial mode [...] for external displays"" into main

parents bb52df82 88096877
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -27,6 +27,9 @@ struct DisplayModeRequest {

    // Whether to emit DisplayEventReceiver::DISPLAY_EVENT_MODE_CHANGE.
    bool emitEvent = false;

    // Whether to force the request to be applied, even if the mode is unchanged.
    bool force = false;
};

inline bool operator==(const DisplayModeRequest& lhs, const DisplayModeRequest& rhs) {
+21 −4
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@

#define ATRACE_TAG ATRACE_TAG_GRAPHICS

#include <common/FlagManager.h>
#include <compositionengine/CompositionEngine.h>
#include <compositionengine/Display.h>
#include <compositionengine/DisplayColorProfile.h>
@@ -214,6 +215,17 @@ void DisplayDevice::setActiveMode(DisplayModeId modeId, Fps vsyncRate, Fps rende
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;

@@ -517,8 +529,7 @@ void DisplayDevice::animateOverlay() {
    }
}

auto DisplayDevice::setDesiredMode(display::DisplayModeRequest&& desiredMode, bool force)
        -> DesiredModeAction {
auto DisplayDevice::setDesiredMode(display::DisplayModeRequest&& desiredMode) -> DesiredModeAction {
    ATRACE_CALL();

    const auto& desiredModePtr = desiredMode.mode.modePtr;
@@ -526,20 +537,26 @@ auto DisplayDevice::setDesiredMode(display::DisplayModeRequest&& desiredMode, bo
    LOG_ALWAYS_FATAL_IF(getPhysicalId() != desiredModePtr->getPhysicalDisplayId(),
                        "DisplayId mismatch");

    ALOGV("%s(%s)", __func__, to_string(*desiredModePtr).c_str());
    // TODO (b/318533819): Stringize DisplayModeRequest.
    ALOGD("%s(%s, force=%s)", __func__, to_string(*desiredModePtr).c_str(),
          desiredMode.force ? "true" : "false");

    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 (!force && activeMode.modePtr->getId() == desiredModePtr->getId()) {
    if (!desiredMode.force && activeMode.modePtr->getId() == desiredModePtr->getId()) {
        if (activeMode == desiredMode.mode) {
            return DesiredModeAction::None;
        }
+1 −2
Original line number Diff line number Diff line
@@ -189,8 +189,7 @@ public:

    enum class DesiredModeAction { None, InitiateDisplayModeSwitch, InitiateRenderRateSwitch };

    DesiredModeAction setDesiredMode(display::DisplayModeRequest&&, bool force = false)
            EXCLUDES(mDesiredModeLock);
    DesiredModeAction setDesiredMode(display::DisplayModeRequest&&) EXCLUDES(mDesiredModeLock);

    using DisplayModeRequestOpt = ftl::Optional<display::DisplayModeRequest>;

+14 −1
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include "HWC2.h"

#include <android/configuration.h>
#include <common/FlagManager.h>
#include <ui/Fence.h>
#include <ui/FloatRect.h>
#include <ui/GraphicBuffer.h>
@@ -416,7 +417,19 @@ Error Display::setActiveConfigWithConstraints(hal::HWConfigId configId,
                                              VsyncPeriodChangeTimeline* outTimeline) {
    ALOGV("[%" PRIu64 "] setActiveConfigWithConstraints", mId);

    if (isVsyncPeriodSwitchSupported()) {
    // FIXME (b/319505580): At least the first config set on an external display must be
    // `setActiveConfig`, so skip over the block that calls `setActiveConfigWithConstraints`
    // for simplicity.
    ui::DisplayConnectionType type = ui::DisplayConnectionType::Internal;
    const bool connected_display = FlagManager::getInstance().connected_display();
    if (connected_display) {
        // Do not bail out on error, since the underlying API may return UNSUPPORTED on older HWCs.
        // TODO: b/323905961 - Remove this AIDL call.
        getConnectionType(&type);
    }

    if (isVsyncPeriodSwitchSupported() &&
        (!connected_display || type != ui::DisplayConnectionType::External)) {
        Hwc2::IComposerClient::VsyncPeriodChangeConstraints hwc2Constraints;
        hwc2Constraints.desiredTimeNanos = constraints.desiredTimeNanos;
        hwc2Constraints.seamlessRequired = constraints.seamlessRequired;
+110 −8
Original line number Diff line number Diff line
@@ -1230,8 +1230,10 @@ status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>& displayToken,
    return NO_ERROR;
}

void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& request, bool force) {
    const auto displayId = request.mode.modePtr->getPhysicalDisplayId();
void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& desiredMode) {
    const auto mode = desiredMode.mode;
    const auto displayId = mode.modePtr->getPhysicalDisplayId();

    ATRACE_NAME(ftl::Concat(__func__, ' ', displayId.value).c_str());

    const auto display = getDisplayDeviceLocked(displayId);
@@ -1240,10 +1242,9 @@ void SurfaceFlinger::setDesiredMode(display::DisplayModeRequest&& request, bool
        return;
    }

    const auto mode = request.mode;
    const bool emitEvent = request.emitEvent;
    const bool emitEvent = desiredMode.emitEvent;

    switch (display->setDesiredMode(std::move(request), force)) {
    switch (display->setDesiredMode(std::move(desiredMode))) {
        case DisplayDevice::DesiredModeAction::InitiateDisplayModeSwitch:
            // DisplayDevice::setDesiredMode updated the render rate, so inform Scheduler.
            mScheduler->setRenderRate(displayId,
@@ -1429,7 +1430,8 @@ void SurfaceFlinger::initiateDisplayModeChanges() {
              to_string(displayModePtrOpt->get()->getVsyncRate()).c_str(),
              to_string(display->getId()).c_str());

        if (display->getActiveMode() == desiredModeOpt->mode) {
        if ((!FlagManager::getInstance().connected_display() || !desiredModeOpt->force) &&
            display->getActiveMode() == desiredModeOpt->mode) {
            applyActiveMode(display);
            continue;
        }
@@ -3284,13 +3286,88 @@ std::pair<DisplayModes, DisplayModePtr> SurfaceFlinger::loadDisplayModes(
    std::vector<HWComposer::HWCDisplayMode> hwcModes;
    std::optional<hal::HWConfigId> activeModeHwcIdOpt;

    const bool isExternalDisplay = FlagManager::getInstance().connected_display() &&
            getHwComposer().getDisplayConnectionType(displayId) ==
                    ui::DisplayConnectionType::External;

    int attempt = 0;
    constexpr int kMaxAttempts = 3;
    do {
        hwcModes = getHwComposer().getModes(displayId,
                                            scheduler::RefreshRateSelector::kMinSupportedFrameRate
                                                    .getPeriodNsecs());
        activeModeHwcIdOpt = getHwComposer().getActiveMode(displayId).value_opt();
        const auto activeModeHwcIdExp = getHwComposer().getActiveMode(displayId);
        activeModeHwcIdOpt = activeModeHwcIdExp.value_opt();

        if (isExternalDisplay &&
            activeModeHwcIdExp.has_error([](status_t error) { return error == NO_INIT; })) {
            constexpr nsecs_t k59HzVsyncPeriod = 16949153;
            constexpr nsecs_t k60HzVsyncPeriod = 16666667;

            // DM sets the initial mode for an external display to 1080p@60, but
            // this comes after SF creates its own state (including the
            // DisplayDevice). For now, pick the same mode in order to avoid
            // inconsistent state and unnecessary mode switching.
            // TODO (b/318534874): Let DM decide the initial mode.
            //
            // Try to find 1920x1080 @ 60 Hz
            if (const auto iter = std::find_if(hwcModes.begin(), hwcModes.end(),
                                               [](const auto& mode) {
                                                   return mode.width == 1920 &&
                                                           mode.height == 1080 &&
                                                           mode.vsyncPeriod == k60HzVsyncPeriod;
                                               });
                iter != hwcModes.end()) {
                activeModeHwcIdOpt = iter->hwcId;
                break;
            }

            // Try to find 1920x1080 @ 59-60 Hz
            if (const auto iter = std::find_if(hwcModes.begin(), hwcModes.end(),
                                               [](const auto& mode) {
                                                   return mode.width == 1920 &&
                                                           mode.height == 1080 &&
                                                           mode.vsyncPeriod >= k60HzVsyncPeriod &&
                                                           mode.vsyncPeriod <= k59HzVsyncPeriod;
                                               });
                iter != hwcModes.end()) {
                activeModeHwcIdOpt = iter->hwcId;
                break;
            }

            // The display does not support 1080p@60, and this is the last attempt to pick a display
            // mode. Prefer 60 Hz if available, with the closest resolution to 1080p.
            if (attempt + 1 == kMaxAttempts) {
                std::vector<HWComposer::HWCDisplayMode> hwcModeOpts;

                for (const auto& mode : hwcModes) {
                    if (mode.width <= 1920 && mode.height <= 1080 &&
                        mode.vsyncPeriod >= k60HzVsyncPeriod &&
                        mode.vsyncPeriod <= k59HzVsyncPeriod) {
                        hwcModeOpts.push_back(mode);
                    }
                }

                if (const auto iter = std::max_element(hwcModeOpts.begin(), hwcModeOpts.end(),
                                                       [](const auto& a, const auto& b) {
                                                           const auto aSize = a.width * a.height;
                                                           const auto bSize = b.width * b.height;
                                                           if (aSize < bSize)
                                                               return true;
                                                           else if (aSize == bSize)
                                                               return a.vsyncPeriod > b.vsyncPeriod;
                                                           else
                                                               return false;
                                                       });
                    iter != hwcModeOpts.end()) {
                    activeModeHwcIdOpt = iter->hwcId;
                    break;
                }

                // hwcModeOpts was empty, use hwcModes[0] as the last resort
                activeModeHwcIdOpt = hwcModes[0].hwcId;
            }
        }

        const auto isActiveMode = [activeModeHwcIdOpt](const HWComposer::HWCDisplayMode& mode) {
            return mode.hwcId == activeModeHwcIdOpt;
@@ -3351,6 +3428,10 @@ std::pair<DisplayModes, DisplayModePtr> SurfaceFlinger::loadDisplayModes(
                return pair.second->getHwcId() == activeModeHwcIdOpt;
            })->second;

    if (isExternalDisplay) {
        ALOGI("External display %s initial mode: {%s}", to_string(displayId).c_str(),
              to_string(*activeMode).c_str());
    }
    return {modes, activeMode};
}

@@ -3659,6 +3740,27 @@ void SurfaceFlinger::processDisplayAdded(const wp<IBinder>& displayToken,
    }

    mDisplays.try_emplace(displayToken, std::move(display));

    // For an external display, loadDisplayModes already attempted to select the same mode
    // as DM, but SF still needs to be updated to match.
    // TODO (b/318534874): Let DM decide the initial mode.
    if (const auto& physical = state.physical;
        mScheduler && physical && FlagManager::getInstance().connected_display()) {
        const bool isInternalDisplay = mPhysicalDisplays.get(physical->id)
                                               .transform(&PhysicalDisplay::isInternal)
                                               .value_or(false);

        if (!isInternalDisplay) {
            auto activeModePtr = physical->activeMode;
            const auto fps = activeModePtr->getPeakFps();

            setDesiredMode(
                    {.mode = scheduler::FrameRateMode{fps,
                                                      ftl::as_non_null(std::move(activeModePtr))},
                     .emitEvent = false,
                     .force = true});
        }
    }
}

void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) {
@@ -8383,7 +8485,7 @@ status_t SurfaceFlinger::applyRefreshRateSelectorPolicy(
        return INVALID_OPERATION;
    }

    setDesiredMode({std::move(preferredMode), .emitEvent = true}, force);
    setDesiredMode({std::move(preferredMode), .emitEvent = true, .force = force});

    // Update the frameRateOverride list as the display render rate might have changed
    if (mScheduler->updateFrameRateOverrides(scheduler::GlobalSignals{}, preferredFps)) {
Loading