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

Commit 3e263ad5 authored by Leon Scroggins's avatar Leon Scroggins Committed by Android (Google) Code Review
Browse files

Merge "Move HwVsyncState into VsyncSchedule"

parents 68063156 c275df4a
Loading
Loading
Loading
Loading
+35 −0
Original line number Diff line number Diff line
/*
 * Copyright 2023 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <vector>

#include "Display/DisplayModeRequest.h"

namespace android::scheduler {

struct ISchedulerCallback {
    virtual void setVsyncEnabled(bool) = 0;
    virtual void requestDisplayModes(std::vector<display::DisplayModeRequest>) = 0;
    virtual void kernelTimerChanged(bool expired) = 0;
    virtual void triggerOnFrameRateOverridesChanged() = 0;

protected:
    ~ISchedulerCallback() = default;
};

} // namespace android::scheduler
+13 −67
Original line number Diff line number Diff line
@@ -155,7 +155,7 @@ void Scheduler::onFrameSignal(ICompositor& compositor, VsyncId vsyncId,
}

void Scheduler::createVsyncSchedule(FeatureFlags features) {
    mVsyncSchedule.emplace(features);
    mVsyncSchedule = std::make_unique<VsyncSchedule>(features);
}

std::optional<Fps> Scheduler::getFrameRateOverride(uid_t uid) const {
@@ -394,38 +394,17 @@ void Scheduler::setVsyncConfig(const VsyncConfig& config, Period vsyncPeriod) {
}

void Scheduler::enableHardwareVsync() {
    std::lock_guard<std::mutex> lock(mHWVsyncLock);
    if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
        mVsyncSchedule->getTracker().resetModel();
        mSchedulerCallback.setVsyncEnabled(true);
        mPrimaryHWVsyncEnabled = true;
    }
    mVsyncSchedule->enableHardwareVsync(mSchedulerCallback);
}

void Scheduler::disableHardwareVsync(bool makeUnavailable) {
    std::lock_guard<std::mutex> lock(mHWVsyncLock);
    if (mPrimaryHWVsyncEnabled) {
        mSchedulerCallback.setVsyncEnabled(false);
        mPrimaryHWVsyncEnabled = false;
    }
    if (makeUnavailable) {
        mHWVsyncAvailable = false;
    }
void Scheduler::disableHardwareVsync(bool disallow) {
    mVsyncSchedule->disableHardwareVsync(mSchedulerCallback, disallow);
}

void Scheduler::resyncToHardwareVsync(bool makeAvailable, Fps refreshRate) {
    {
        std::lock_guard<std::mutex> lock(mHWVsyncLock);
        if (makeAvailable) {
            mHWVsyncAvailable = makeAvailable;
        } else if (!mHWVsyncAvailable) {
            // Hardware vsync is not currently available, so abort the resync
            // attempt for now
            return;
        }
void Scheduler::resyncToHardwareVsync(bool allowToEnable, Fps refreshRate) {
    if (mVsyncSchedule->isHardwareVsyncAllowed(allowToEnable) && refreshRate.isValid()) {
        mVsyncSchedule->startPeriodTransition(mSchedulerCallback, refreshRate.getPeriod());
    }

    setVsyncPeriod(refreshRate.getPeriodNsecs());
}

void Scheduler::setRenderRate(Fps renderFrameRate) {
@@ -458,37 +437,12 @@ void Scheduler::resync() {
    }
}

void Scheduler::setVsyncPeriod(nsecs_t period) {
    if (period <= 0) return;

    std::lock_guard<std::mutex> lock(mHWVsyncLock);
    mVsyncSchedule->getController().startPeriodTransition(period);

    if (!mPrimaryHWVsyncEnabled) {
        mVsyncSchedule->getTracker().resetModel();
        mSchedulerCallback.setVsyncEnabled(true);
        mPrimaryHWVsyncEnabled = true;
    }
}

void Scheduler::addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod,
                                bool* periodFlushed) {
    bool needsHwVsync = false;
    *periodFlushed = false;
    { // Scope for the lock
        std::lock_guard<std::mutex> lock(mHWVsyncLock);
        if (mPrimaryHWVsyncEnabled) {
            needsHwVsync =
                    mVsyncSchedule->getController().addHwVsyncTimestamp(timestamp, hwcVsyncPeriod,
                                                                        periodFlushed);
        }
    }

    if (needsHwVsync) {
        enableHardwareVsync();
    } else {
        disableHardwareVsync(false);
    }
bool Scheduler::addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriodIn) {
    const auto hwcVsyncPeriod = ftl::Optional(hwcVsyncPeriodIn).transform([](nsecs_t nanos) {
        return Period::fromNs(nanos);
    });
    return mVsyncSchedule->addResyncSample(mSchedulerCallback, TimePoint::fromNs(timestamp),
                                           hwcVsyncPeriod);
}

void Scheduler::addPresentFence(std::shared_ptr<FenceTime> fence) {
@@ -636,14 +590,6 @@ void Scheduler::dump(utils::Dumper& dumper) const {

    mFrameRateOverrideMappings.dump(dumper);
    dumper.eol();

    {
        utils::Dumper::Section section(dumper, "Hardware VSYNC"sv);

        std::lock_guard lock(mHWVsyncLock);
        dumper.dump("hwVsyncAvailable"sv, mHWVsyncAvailable);
        dumper.dump("hwVsyncEnabled"sv, mPrimaryHWVsyncEnabled);
    }
}

void Scheduler::dumpVsync(std::string& out) const {
+9 −23
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@
#include "Display/DisplayModeRequest.h"
#include "EventThread.h"
#include "FrameRateOverrideMappings.h"
#include "ISchedulerCallback.h"
#include "LayerHistory.h"
#include "MessageQueue.h"
#include "OneShotTimer.h"
@@ -92,16 +93,6 @@ namespace scheduler {

using GlobalSignals = RefreshRateSelector::GlobalSignals;

struct ISchedulerCallback {
    virtual void setVsyncEnabled(bool) = 0;
    virtual void requestDisplayModes(std::vector<display::DisplayModeRequest>) = 0;
    virtual void kernelTimerChanged(bool expired) = 0;
    virtual void triggerOnFrameRateOverridesChanged() = 0;

protected:
    ~ISchedulerCallback() = default;
};

class Scheduler : android::impl::MessageQueue {
    using Impl = android::impl::MessageQueue;

@@ -192,20 +183,20 @@ public:
    void setRenderRate(Fps);

    void enableHardwareVsync();
    void disableHardwareVsync(bool makeUnavailable);
    void disableHardwareVsync(bool disallow);

    // Resyncs the scheduler to hardware vsync.
    // If makeAvailable is true, then hardware vsync will be turned on.
    // If allowToEnable is true, then hardware vsync will be turned on.
    // Otherwise, if hardware vsync is not already enabled then this method will
    // no-op.
    void resyncToHardwareVsync(bool makeAvailable, Fps refreshRate);
    void resyncToHardwareVsync(bool allowToEnable, Fps refreshRate);
    void resync() EXCLUDES(mDisplayLock);
    void forceNextResync() { mLastResyncTime = 0; }

    // Passes a vsync sample to VsyncController. periodFlushed will be true if
    // VsyncController detected that the vsync period changed, and false otherwise.
    void addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod,
                         bool* periodFlushed);
    // Passes a vsync sample to VsyncController. Returns true if
    // VsyncController detected that the vsync period changed and false
    // otherwise.
    bool addResyncSample(nsecs_t timestamp, std::optional<nsecs_t> hwcVsyncPeriod);
    void addPresentFence(std::shared_ptr<FenceTime>);

    // Layers are registered on creation, and unregistered when the weak reference expires.
@@ -297,7 +288,6 @@ private:
    void touchTimerCallback(TimerState);
    void displayPowerTimerCallback(TimerState);

    void setVsyncPeriod(nsecs_t period);
    void setVsyncConfig(const VsyncConfig&, Period vsyncPeriod);

    // Chooses a leader among the registered displays, unless `leaderIdOpt` is specified. The new
@@ -362,14 +352,10 @@ private:
    ConnectionHandle mAppConnectionHandle;
    ConnectionHandle mSfConnectionHandle;

    mutable std::mutex mHWVsyncLock;
    bool mPrimaryHWVsyncEnabled GUARDED_BY(mHWVsyncLock) = false;
    bool mHWVsyncAvailable GUARDED_BY(mHWVsyncLock) = false;

    std::atomic<nsecs_t> mLastResyncTime = 0;

    const FeatureFlags mFeatures;
    std::optional<VsyncSchedule> mVsyncSchedule;
    std::unique_ptr<VsyncSchedule> mVsyncSchedule;

    // Shifts the VSYNC phase during certain transactions and refresh rate changes.
    const sp<VsyncModulator> mVsyncModulator;
+80 −6
Original line number Diff line number Diff line
@@ -16,11 +16,14 @@

#define ATRACE_TAG ATRACE_TAG_GRAPHICS

#include <ftl/fake_guard.h>
#include <scheduler/Fps.h>
#include <scheduler/Timer.h>

#include "VsyncSchedule.h"

#include "ISchedulerCallback.h"
#include "Utils/Dumper.h"
#include "VSyncDispatchTimerQueue.h"
#include "VSyncPredictor.h"
#include "VSyncReactor.h"
@@ -54,18 +57,16 @@ private:
VsyncSchedule::VsyncSchedule(FeatureFlags features)
      : mTracker(createTracker()),
        mDispatch(createDispatch(*mTracker)),
        mController(createController(*mTracker, features)) {
    if (features.test(Feature::kTracePredictedVsync)) {
        mTracer = std::make_unique<PredictedVsyncTracer>(*mDispatch);
    }
}
        mController(createController(*mTracker, features)),
        mTracer(features.test(Feature::kTracePredictedVsync)
                        ? std::make_unique<PredictedVsyncTracer>(*mDispatch)
                        : nullptr) {}

VsyncSchedule::VsyncSchedule(TrackerPtr tracker, DispatchPtr dispatch, ControllerPtr controller)
      : mTracker(std::move(tracker)),
        mDispatch(std::move(dispatch)),
        mController(std::move(controller)) {}

VsyncSchedule::VsyncSchedule(VsyncSchedule&&) = default;
VsyncSchedule::~VsyncSchedule() = default;

Period VsyncSchedule::period() const {
@@ -77,6 +78,16 @@ TimePoint VsyncSchedule::vsyncDeadlineAfter(TimePoint timePoint) const {
}

void VsyncSchedule::dump(std::string& out) const {
    utils::Dumper dumper(out);
    {
        std::lock_guard<std::mutex> lock(mHwVsyncLock);
        dumper.dump("hwVsyncState", ftl::enum_string(mHwVsyncState));

        ftl::FakeGuard guard(kMainThreadContext);
        dumper.dump("pendingHwVsyncState", ftl::enum_string(mPendingHwVsyncState));
        dumper.eol();
    }

    out.append("VsyncController:\n");
    mController->dump(out);

@@ -120,4 +131,67 @@ VsyncSchedule::ControllerPtr VsyncSchedule::createController(VsyncTracker& track
    return reactor;
}

void VsyncSchedule::startPeriodTransition(ISchedulerCallback& callback, Period period) {
    std::lock_guard<std::mutex> lock(mHwVsyncLock);
    mController->startPeriodTransition(period.ns());
    enableHardwareVsyncLocked(callback);
}

bool VsyncSchedule::addResyncSample(ISchedulerCallback& callback, TimePoint timestamp,
                                    ftl::Optional<Period> hwcVsyncPeriod) {
    bool needsHwVsync = false;
    bool periodFlushed = false;
    {
        std::lock_guard<std::mutex> lock(mHwVsyncLock);
        if (mHwVsyncState == HwVsyncState::Enabled) {
            needsHwVsync = mController->addHwVsyncTimestamp(timestamp.ns(),
                                                            hwcVsyncPeriod.transform(&Period::ns),
                                                            &periodFlushed);
        }
    }
    if (needsHwVsync) {
        enableHardwareVsync(callback);
    } else {
        disableHardwareVsync(callback, false /* disallow */);
    }
    return periodFlushed;
}

void VsyncSchedule::enableHardwareVsync(ISchedulerCallback& callback) {
    std::lock_guard<std::mutex> lock(mHwVsyncLock);
    enableHardwareVsyncLocked(callback);
}

void VsyncSchedule::enableHardwareVsyncLocked(ISchedulerCallback& callback) {
    if (mHwVsyncState == HwVsyncState::Disabled) {
        getTracker().resetModel();
        callback.setVsyncEnabled(true);
        mHwVsyncState = HwVsyncState::Enabled;
    }
}

void VsyncSchedule::disableHardwareVsync(ISchedulerCallback& callback, bool disallow) {
    std::lock_guard<std::mutex> lock(mHwVsyncLock);
    if (mHwVsyncState == HwVsyncState::Enabled) {
        callback.setVsyncEnabled(false);
    }
    mHwVsyncState = disallow ? HwVsyncState::Disallowed : HwVsyncState::Disabled;
}

bool VsyncSchedule::isHardwareVsyncAllowed(bool makeAllowed) {
    std::lock_guard<std::mutex> lock(mHwVsyncLock);
    if (makeAllowed && mHwVsyncState == HwVsyncState::Disallowed) {
        mHwVsyncState = HwVsyncState::Disabled;
    }
    return mHwVsyncState != HwVsyncState::Disallowed;
}

void VsyncSchedule::setPendingHardwareVsyncState(bool enabled) {
    mPendingHwVsyncState = enabled ? HwVsyncState::Enabled : HwVsyncState::Disabled;
}

bool VsyncSchedule::getPendingHardwareVsyncState() const {
    return mPendingHwVsyncState == HwVsyncState::Enabled;
}

} // namespace android::scheduler
+61 −6
Original line number Diff line number Diff line
@@ -19,6 +19,9 @@
#include <memory>
#include <string>

#include <ThreadContext.h>
#include <ftl/enum.h>
#include <ftl/optional.h>
#include <scheduler/Features.h>
#include <scheduler/Time.h>

@@ -32,6 +35,8 @@ class SchedulerFuzzer;

namespace android::scheduler {

struct ISchedulerCallback;

// TODO(b/185535769): Rename classes, and remove aliases.
class VSyncDispatch;
class VSyncTracker;
@@ -44,12 +49,24 @@ using VsyncTracker = VSyncTracker;
class VsyncSchedule {
public:
    explicit VsyncSchedule(FeatureFlags);
    VsyncSchedule(VsyncSchedule&&);
    ~VsyncSchedule();

    Period period() const;
    TimePoint vsyncDeadlineAfter(TimePoint) const;

    // Inform the schedule that the period is changing and the schedule needs to recalibrate
    // itself. The schedule will end the period transition internally. This will
    // enable hardware VSYNCs in order to calibrate.
    //
    // \param [in] period   The period that the system is changing into.
    void startPeriodTransition(ISchedulerCallback&, Period period);

    // Pass a VSYNC sample to VsyncController. Return true if
    // VsyncController detected that the VSYNC period changed. Enable or disable
    // hardware VSYNCs depending on whether more samples are needed.
    bool addResyncSample(ISchedulerCallback&, TimePoint timestamp,
                         ftl::Optional<Period> hwcVsyncPeriod);

    // TODO(b/185535769): Hide behind API.
    const VsyncTracker& getTracker() const { return *mTracker; }
    VsyncTracker& getTracker() { return *mTracker; }
@@ -60,6 +77,22 @@ public:

    void dump(std::string&) const;

    // Turn on hardware VSYNCs, unless mHwVsyncState is Disallowed, in which
    // case this call is ignored.
    void enableHardwareVsync(ISchedulerCallback&) EXCLUDES(mHwVsyncLock);

    // Disable hardware VSYNCs. If `disallow` is true, future calls to
    // enableHardwareVsync are ineffective until allowHardwareVsync is called.
    void disableHardwareVsync(ISchedulerCallback&, bool disallow) EXCLUDES(mHwVsyncLock);

    // If true, enableHardwareVsync can enable hardware VSYNC (if not already
    // enabled). If false, enableHardwareVsync does nothing.
    bool isHardwareVsyncAllowed(bool makeAllowed) EXCLUDES(mHwVsyncLock);

    void setPendingHardwareVsyncState(bool enabled) REQUIRES(kMainThreadContext);

    bool getPendingHardwareVsyncState() const REQUIRES(kMainThreadContext);

private:
    friend class TestableScheduler;
    friend class android::EventThreadTest;
@@ -76,14 +109,36 @@ private:
    static DispatchPtr createDispatch(VsyncTracker&);
    static ControllerPtr createController(VsyncTracker&, FeatureFlags);

    void enableHardwareVsyncLocked(ISchedulerCallback&) REQUIRES(mHwVsyncLock);

    mutable std::mutex mHwVsyncLock;
    enum class HwVsyncState {
        // Hardware VSYNCs are currently enabled.
        Enabled,

        // Hardware VSYNCs are currently disabled. They can be enabled by a call
        // to `enableHardwareVsync`.
        Disabled,

        // Hardware VSYNCs are not currently allowed (e.g. because the display
        // is off).
        Disallowed,

        ftl_last = Disallowed,
    };
    HwVsyncState mHwVsyncState GUARDED_BY(mHwVsyncLock) = HwVsyncState::Disallowed;

    // Pending state, in case an attempt is made to set the state while the
    // device is off.
    HwVsyncState mPendingHwVsyncState GUARDED_BY(kMainThreadContext) = HwVsyncState::Disabled;

    class PredictedVsyncTracer;
    using TracerPtr = std::unique_ptr<PredictedVsyncTracer>;

    // Effectively const except in move constructor.
    TrackerPtr mTracker;
    DispatchPtr mDispatch;
    ControllerPtr mController;
    TracerPtr mTracer;
    const TrackerPtr mTracker;
    const DispatchPtr mDispatch;
    const ControllerPtr mController;
    const TracerPtr mTracer;
};

} // namespace android::scheduler
Loading