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

Commit d6a3f6e8 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "SurfaceFlinger: use setActiveConfigWithConstraints"

parents df13934f 3a77a7b6
Loading
Loading
Loading
Loading
+25 −4
Original line number Diff line number Diff line
@@ -247,8 +247,8 @@ nsecs_t HWComposer::getRefreshTimestamp(DisplayId displayId) const {
    // the refresh period and whatever closest timestamp we have.
    std::lock_guard lock(displayData.lastHwVsyncLock);
    nsecs_t now = systemTime(CLOCK_MONOTONIC);
    auto vsyncPeriod = getActiveConfig(displayId)->getVsyncPeriod();
    return now - ((now - displayData.lastHwVsync) % vsyncPeriod);
    auto vsyncPeriodNanos = getDisplayVsyncPeriod(displayId);
    return now - ((now - displayData.lastHwVsync) % vsyncPeriodNanos);
}

bool HWComposer::isConnected(DisplayId displayId) const {
@@ -291,6 +291,23 @@ std::shared_ptr<const HWC2::Display::Config> HWComposer::getActiveConfig(
    return config;
}

// Composer 2.4

bool HWComposer::isVsyncPeriodSwitchSupported(DisplayId displayId) const {
    return mDisplayData.at(displayId).hwcDisplay->isVsyncPeriodSwitchSupported();
}

nsecs_t HWComposer::getDisplayVsyncPeriod(DisplayId displayId) const {
    nsecs_t vsyncPeriodNanos;
    auto error = mDisplayData.at(displayId).hwcDisplay->getDisplayVsyncPeriod(&vsyncPeriodNanos);
    if (error != HWC2::Error::None) {
        LOG_DISPLAY_ERROR(displayId, "Failed to get Vsync Period");
        return 0;
    }

    return vsyncPeriodNanos;
}

int HWComposer::getActiveConfigIndex(DisplayId displayId) const {
    RETURN_IF_INVALID_DISPLAY(displayId, -1);

@@ -541,7 +558,9 @@ status_t HWComposer::setPowerMode(DisplayId displayId, int32_t intMode) {
    return NO_ERROR;
}

status_t HWComposer::setActiveConfig(DisplayId displayId, size_t configId) {
status_t HWComposer::setActiveConfigWithConstraints(
        DisplayId displayId, size_t configId, const HWC2::VsyncPeriodChangeConstraints& constraints,
        HWC2::VsyncPeriodChangeTimeline* outTimeline) {
    RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);

    auto& displayData = mDisplayData[displayId];
@@ -550,7 +569,9 @@ status_t HWComposer::setActiveConfig(DisplayId displayId, size_t configId) {
        return BAD_INDEX;
    }

    auto error = displayData.hwcDisplay->setActiveConfig(displayData.configMap[configId]);
    auto error =
            displayData.hwcDisplay->setActiveConfigWithConstraints(displayData.configMap[configId],
                                                                   constraints, outTimeline);
    RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
    return NO_ERROR;
}
+15 −6
Original line number Diff line number Diff line
@@ -102,9 +102,6 @@ public:
    // set power mode
    virtual status_t setPowerMode(DisplayId displayId, int mode) = 0;

    // set active config
    virtual status_t setActiveConfig(DisplayId displayId, size_t configId) = 0;

    // Sets a color transform to be applied to the result of composition
    virtual status_t setColorTransform(DisplayId displayId, const mat4& transform) = 0;

@@ -180,6 +177,14 @@ public:

    virtual bool isUsingVrComposer() const = 0;

    // Composer 2.4
    virtual bool isVsyncPeriodSwitchSupported(DisplayId displayId) const = 0;
    virtual nsecs_t getDisplayVsyncPeriod(DisplayId displayId) const = 0;
    virtual status_t setActiveConfigWithConstraints(
            DisplayId displayId, size_t configId,
            const HWC2::VsyncPeriodChangeConstraints& constraints,
            HWC2::VsyncPeriodChangeTimeline* outTimeline) = 0;

    // for debugging ----------------------------------------------------------
    virtual void dump(std::string& out) const = 0;

@@ -232,9 +237,6 @@ public:
    // set power mode
    status_t setPowerMode(DisplayId displayId, int mode) override;

    // set active config
    status_t setActiveConfig(DisplayId displayId, size_t configId) override;

    // Sets a color transform to be applied to the result of composition
    status_t setColorTransform(DisplayId displayId, const mat4& transform) override;

@@ -305,6 +307,13 @@ public:

    bool isUsingVrComposer() const override;

    // Composer 2.4
    bool isVsyncPeriodSwitchSupported(DisplayId displayId) const override;
    nsecs_t getDisplayVsyncPeriod(DisplayId displayId) const override;
    status_t setActiveConfigWithConstraints(DisplayId displayId, size_t configId,
                                            const HWC2::VsyncPeriodChangeConstraints& constraints,
                                            HWC2::VsyncPeriodChangeTimeline* outTimeline) override;

    // for debugging ----------------------------------------------------------
    void dump(std::string& out) const override;

+38 −13
Original line number Diff line number Diff line
@@ -59,11 +59,13 @@
namespace android {

Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function,
                     const scheduler::RefreshRateConfigs& refreshRateConfig)
                     const scheduler::RefreshRateConfigs& refreshRateConfig,
                     ISchedulerCallback& schedulerCallback)
      : mPrimaryDispSync(new impl::DispSync("SchedulerDispSync",
                                            sysprop::running_without_sync_framework(true))),
        mEventControlThread(new impl::EventControlThread(std::move(function))),
        mSupportKernelTimer(sysprop::support_kernel_idle_timer(false)),
        mSchedulerCallback(schedulerCallback),
        mRefreshRateConfigs(refreshRateConfig) {
    using namespace sysprop;

@@ -104,10 +106,12 @@ Scheduler::Scheduler(impl::EventControlThread::SetVSyncEnabledFunction function,

Scheduler::Scheduler(std::unique_ptr<DispSync> primaryDispSync,
                     std::unique_ptr<EventControlThread> eventControlThread,
                     const scheduler::RefreshRateConfigs& configs)
                     const scheduler::RefreshRateConfigs& configs,
                     ISchedulerCallback& schedulerCallback)
      : mPrimaryDispSync(std::move(primaryDispSync)),
        mEventControlThread(std::move(eventControlThread)),
        mSupportKernelTimer(false),
        mSchedulerCallback(schedulerCallback),
        mRefreshRateConfigs(configs) {}

Scheduler::~Scheduler() {
@@ -368,12 +372,7 @@ void Scheduler::chooseRefreshRateForContent() {
        mFeatures.configId = newConfigId;
    };
    auto newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
    changeRefreshRate(newRefreshRate, ConfigEvent::Changed);
}

void Scheduler::setSchedulerCallback(android::Scheduler::ISchedulerCallback* callback) {
    std::lock_guard<std::mutex> lock(mCallbackLock);
    mSchedulerCallback = callback;
    mSchedulerCallback.changeRefreshRate(newRefreshRate, ConfigEvent::Changed);
}

void Scheduler::resetIdleTimer() {
@@ -486,7 +485,7 @@ void Scheduler::handleTimerStateChanged(T* currentState, T newState, bool eventO
        }
    }
    const RefreshRate& newRefreshRate = mRefreshRateConfigs.getRefreshRateFromConfigId(newConfigId);
    changeRefreshRate(newRefreshRate, event);
    mSchedulerCallback.changeRefreshRate(newRefreshRate, event);
}

HwcConfigIndexType Scheduler::calculateRefreshRateType() {
@@ -526,10 +525,36 @@ std::optional<HwcConfigIndexType> Scheduler::getPreferredConfigId() {
    return mFeatures.configId;
}

void Scheduler::changeRefreshRate(const RefreshRate& refreshRate, ConfigEvent configEvent) {
    std::lock_guard<std::mutex> lock(mCallbackLock);
    if (mSchedulerCallback) {
        mSchedulerCallback->changeRefreshRate(refreshRate, configEvent);
void Scheduler::onNewVsyncPeriodChangeTimeline(const HWC2::VsyncPeriodChangeTimeline& timeline) {
    if (timeline.refreshRequired) {
        mSchedulerCallback.repaintEverythingForHWC();
    }

    std::lock_guard<std::mutex> lock(mVsyncTimelineLock);
    mLastVsyncPeriodChangeTimeline = std::make_optional(timeline);

    const auto maxAppliedTime = systemTime() + MAX_VSYNC_APPLIED_TIME.count();
    if (timeline.newVsyncAppliedTimeNanos > maxAppliedTime) {
        mLastVsyncPeriodChangeTimeline->newVsyncAppliedTimeNanos = maxAppliedTime;
    }
}

void Scheduler::onDisplayRefreshed(nsecs_t timestamp) {
    bool callRepaint = false;
    {
        std::lock_guard<std::mutex> lock(mVsyncTimelineLock);
        if (mLastVsyncPeriodChangeTimeline && mLastVsyncPeriodChangeTimeline->refreshRequired) {
            if (mLastVsyncPeriodChangeTimeline->refreshTimeNanos < timestamp) {
                mLastVsyncPeriodChangeTimeline->refreshRequired = false;
            } else {
                // We need to send another refresh as refreshTimeNanos is still in the future
                callRepaint = true;
            }
        }
    }

    if (callRepaint) {
        mSchedulerCallback.repaintEverythingForHWC();
    }
}

+22 −15
Original line number Diff line number Diff line
@@ -41,22 +41,24 @@ class FenceTime;
class InjectVSyncSource;
struct DisplayStateInfo;

class Scheduler {
public:
    using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate;
    using ConfigEvent = scheduler::RefreshRateConfigEvent;

class ISchedulerCallback {
public:
    virtual ~ISchedulerCallback() = default;
        virtual void changeRefreshRate(const RefreshRate&, ConfigEvent) = 0;
    virtual void changeRefreshRate(const scheduler::RefreshRateConfigs::RefreshRate&,
                                   scheduler::RefreshRateConfigEvent) = 0;
    virtual void repaintEverythingForHWC() = 0;
};

class Scheduler {
public:
    using RefreshRate = scheduler::RefreshRateConfigs::RefreshRate;
    using ConfigEvent = scheduler::RefreshRateConfigEvent;

    // Indicates whether to start the transaction early, or at vsync time.
    enum class TransactionStart { EARLY, NORMAL };

    Scheduler(impl::EventControlThread::SetVSyncEnabledFunction,
              const scheduler::RefreshRateConfigs&);
              const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback);

    virtual ~Scheduler();

@@ -114,9 +116,6 @@ public:
    // Detects content using layer history, and selects a matching refresh rate.
    void chooseRefreshRateForContent();

    // Called by Scheduler to control SurfaceFlinger operations.
    void setSchedulerCallback(ISchedulerCallback*);

    bool isIdleTimerEnabled() const { return mIdleTimer.has_value(); }
    void resetIdleTimer();

@@ -131,6 +130,12 @@ public:
    // Get the appropriate refresh for current conditions.
    std::optional<HwcConfigIndexType> getPreferredConfigId();

    // Notifies the scheduler about a refresh rate timeline change.
    void onNewVsyncPeriodChangeTimeline(const HWC2::VsyncPeriodChangeTimeline& timeline);

    // Notifies the scheduler when the display was refreshed
    void onDisplayRefreshed(nsecs_t timestamp);

private:
    friend class TestableScheduler;

@@ -142,7 +147,7 @@ private:

    // Used by tests to inject mocks.
    Scheduler(std::unique_ptr<DispSync>, std::unique_ptr<EventControlThread>,
              const scheduler::RefreshRateConfigs&);
              const scheduler::RefreshRateConfigs&, ISchedulerCallback& schedulerCallback);

    std::unique_ptr<VSyncSource> makePrimaryDispSyncSource(const char* name, nsecs_t phaseOffsetNs,
                                                           nsecs_t offsetThresholdForNextVsync);
@@ -165,8 +170,6 @@ private:
    void setVsyncPeriod(nsecs_t period);

    HwcConfigIndexType calculateRefreshRateType() REQUIRES(mFeatureStateLock);
    // Acquires a lock and calls the ChangeRefreshRateCallback with given parameters.
    void changeRefreshRate(const RefreshRate&, ConfigEvent);

    // Stores EventThread associated with a given VSyncSource, and an initial EventThreadConnection.
    struct Connection {
@@ -203,8 +206,7 @@ private:
    // Timer used to monitor display power mode.
    std::optional<scheduler::OneShotTimer> mDisplayPowerTimer;

    std::mutex mCallbackLock;
    ISchedulerCallback* mSchedulerCallback GUARDED_BY(mCallbackLock) = nullptr;
    ISchedulerCallback& mSchedulerCallback;

    // In order to make sure that the features don't override themselves, we need a state machine
    // to keep track which feature requested the config change.
@@ -223,6 +225,11 @@ private:
    } mFeatures GUARDED_BY(mFeatureStateLock);

    const scheduler::RefreshRateConfigs& mRefreshRateConfigs;

    std::mutex mVsyncTimelineLock;
    std::optional<HWC2::VsyncPeriodChangeTimeline> mLastVsyncPeriodChangeTimeline
            GUARDED_BY(mVsyncTimelineLock);
    static constexpr std::chrono::nanoseconds MAX_VSYNC_APPLIED_TIME = 200ms;
};

} // namespace android
+55 −13
Original line number Diff line number Diff line
@@ -1004,11 +1004,25 @@ bool SurfaceFlinger::performSetActiveConfig() {
    LOG_ALWAYS_FATAL_IF(!displayId);

    ATRACE_INT("ActiveConfigFPS_HWC", refreshRate.fps);
    getHwComposer().setActiveConfig(*displayId, mUpcomingActiveConfig.configId.value());

    // we need to submit an empty frame to HWC to start the process
    // TODO(b/142753666) use constrains
    HWC2::VsyncPeriodChangeConstraints constraints;
    constraints.desiredTimeNanos = systemTime();
    constraints.seamlessRequired = false;

    HWC2::VsyncPeriodChangeTimeline outTimeline;
    auto status =
            getHwComposer().setActiveConfigWithConstraints(*displayId,
                                                           mUpcomingActiveConfig.configId.value(),
                                                           constraints, &outTimeline);
    if (status != NO_ERROR) {
        LOG_ALWAYS_FATAL("setActiveConfigWithConstraints failed: %d", status);
        return false;
    }

    mScheduler->onNewVsyncPeriodChangeTimeline(outTimeline);
    // Scheduler will submit an empty frame to HWC if needed.
    mCheckPendingFence = true;
    mEventQueue->invalidate();
    return false;
}

@@ -1361,8 +1375,7 @@ nsecs_t SurfaceFlinger::getVsyncPeriod() const {
        return 0;
    }

    const auto config = getHwComposer().getActiveConfig(*displayId);
    return config ? config->getVsyncPeriod() : 0;
    return getHwComposer().getDisplayVsyncPeriod(*displayId);
}

void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
@@ -1448,9 +1461,13 @@ void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDis
}

void SurfaceFlinger::onVsyncPeriodTimingChangedReceived(
        int32_t /*sequenceId*/, hwc2_display_t /*display*/,
        const hwc_vsync_period_change_timeline_t& /*updatedTimeline*/) {
    // TODO(b/142753004): use timeline when changing refresh rate
        int32_t sequenceId, hwc2_display_t /*display*/,
        const hwc_vsync_period_change_timeline_t& updatedTimeline) {
    Mutex::Autolock lock(mStateLock);
    if (sequenceId != getBE().mComposerSequenceId) {
        return;
    }
    mScheduler->onNewVsyncPeriodChangeTimeline(updatedTimeline);
}

void SurfaceFlinger::onRefreshReceived(int sequenceId, hwc2_display_t /*hwcDisplayId*/) {
@@ -1761,11 +1778,17 @@ void SurfaceFlinger::handleMessageRefresh() {

    mGeometryInvalid = false;

    // Store the present time just before calling to the composition engine so we could notify
    // the scheduler.
    const auto presentTime = systemTime();

    mCompositionEngine->present(refreshArgs);
    mTimeStats->recordFrameDuration(mFrameStartTime, systemTime());
    // Reset the frame start time now that we've recorded this frame.
    mFrameStartTime = 0;

    mScheduler->onDisplayRefreshed(presentTime);

    postFrame();
    postComposition();

@@ -2551,7 +2574,7 @@ void SurfaceFlinger::initScheduler(DisplayId primaryDisplayId) {
    // start the EventThread
    mScheduler =
            getFactory().createScheduler([this](bool enabled) { setPrimaryVsyncEnabled(enabled); },
                                         *mRefreshRateConfigs);
                                         *mRefreshRateConfigs, *this);
    mAppConnectionHandle =
            mScheduler->createConnection("app", mPhaseOffsets->getCurrentAppOffset(),
                                         mPhaseOffsets->getOffsetThresholdForNextVsync(),
@@ -2570,8 +2593,6 @@ void SurfaceFlinger::initScheduler(DisplayId primaryDisplayId) {
    mRegionSamplingThread =
            new RegionSamplingThread(*this, *mScheduler,
                                     RegionSamplingThread::EnvironmentTimingTunables());

    mScheduler->setSchedulerCallback(this);
}

void SurfaceFlinger::commitTransaction()
@@ -4316,8 +4337,8 @@ void SurfaceFlinger::dumpAllLocked(const DumpArgs& args, std::string& result) co
                      "  refresh-rate              : %f fps\n"
                      "  x-dpi                     : %f\n"
                      "  y-dpi                     : %f\n",
                      1e9 / activeConfig->getVsyncPeriod(), activeConfig->getDpiX(),
                      activeConfig->getDpiY());
                      1e9 / getHwComposer().getDisplayVsyncPeriod(*displayId),
                      activeConfig->getDpiX(), activeConfig->getDpiY());
    }

    StringAppendF(&result, "  transaction time: %f us\n", inTransactionDuration / 1000.0);
@@ -5438,6 +5459,27 @@ void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& disp
void SurfaceFlinger::setAllowedDisplayConfigsInternal(const sp<DisplayDevice>& display,
                                                      const std::vector<int32_t>& allowedConfigs) {
    if (!display->isPrimary()) {
        // TODO(b/144711714): For non-primary displays we should be able to set an active config
        // as well. For now, just call directly to setActiveConfigWithConstraints but ideally
        // it should go thru setDesiredActiveConfig, similar to primary display.
        ALOGV("setAllowedDisplayConfigsInternal for non-primary display");
        const auto displayId = display->getId();
        LOG_ALWAYS_FATAL_IF(!displayId);

        HWC2::VsyncPeriodChangeConstraints constraints;
        constraints.desiredTimeNanos = systemTime();
        constraints.seamlessRequired = false;

        HWC2::VsyncPeriodChangeTimeline timeline = {0, 0, 0};
        getHwComposer().setActiveConfigWithConstraints(*displayId, allowedConfigs[0], constraints,
                                                       &timeline);
        if (timeline.refreshRequired) {
            repaintEverythingForHWC();
        }

        auto configId = HwcConfigIndexType(allowedConfigs[0]);
        display->setActiveConfig(configId);
        mScheduler->onConfigChanged(mAppConnectionHandle, display->getId()->value, configId);
        return;
    }

Loading