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

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

Merge changes Ie15c0abb,I14390a3d

* changes:
  SF: Adding sysprop flag for video detection
  SF: Updating video detection logic. This is V0.
parents a80d2c0d e5a06e09
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -393,9 +393,8 @@ void BufferQueueLayer::onFrameAvailable(const BufferItem& item) {
    // Add this buffer from our internal queue tracker
    { // Autolock scope
        if (mFlinger->mUseSmart90ForVideo) {
            // Report the requested present time to the Scheduler, if the feature is turned on.
            mFlinger->mScheduler->addFramePresentTimeForLayer(item.mTimestamp,
                                                              item.mIsAutoTimestamp, mName.c_str());
            // Report mApi ID for each layer.
            mFlinger->mScheduler->addNativeWindowApi(item.mApi);
        }

        Mutex::Autolock lock(mQueueItemLock);
+70 −104
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
#include <configstore/Utils.h>
#include <cutils/properties.h>
#include <system/window.h>
#include <ui/DisplayStatInfo.h>
#include <utils/Timers.h>
#include <utils/Trace.h>
@@ -296,21 +297,29 @@ void Scheduler::dumpPrimaryDispSync(std::string& result) const {
    mPrimaryDispSync->dump(result);
}

void Scheduler::addFramePresentTimeForLayer(const nsecs_t framePresentTime, bool isAutoTimestamp,
                                            const std::string layerName) {
    // This is V1 logic. It calculates the average FPS based on the timestamp frequency
    // regardless of which layer the timestamp came from.
    // For now, the averages and FPS are recorded in the systrace.
    determineTimestampAverage(isAutoTimestamp, framePresentTime);
void Scheduler::addNativeWindowApi(int apiId) {
    std::lock_guard<std::mutex> lock(mWindowApiHistoryLock);
    mWindowApiHistory[mApiHistoryCounter] = apiId;
    mApiHistoryCounter++;
    mApiHistoryCounter = mApiHistoryCounter % scheduler::ARRAY_SIZE;
}

    // This is V2 logic. It calculates the average and median timestamp difference based on the
    // individual layer history. The results are recorded in the systrace.
    determineLayerTimestampStats(layerName, framePresentTime);
void Scheduler::updateFpsBasedOnNativeWindowApi() {
    int mode;
    {
        std::lock_guard<std::mutex> lock(mWindowApiHistoryLock);
        mode = scheduler::calculate_mode(mWindowApiHistory);
    }
    ATRACE_INT("NativeWindowApiMode", mode);

void Scheduler::incrementFrameCounter() {
    std::lock_guard<std::mutex> lock(mLayerHistoryLock);
    mLayerHistory.incrementCounter();
    if (mode == NATIVE_WINDOW_API_MEDIA) {
        // TODO(b/127365162): These callback names are not accurate anymore. Update.
        mediaChangeRefreshRate(MediaFeatureState::MEDIA_PLAYING);
        ATRACE_INT("DetectedVideo", 1);
    } else {
        mediaChangeRefreshRate(MediaFeatureState::MEDIA_OFF);
        ATRACE_INT("DetectedVideo", 0);
    }
}

void Scheduler::setChangeRefreshRateCallback(
@@ -328,85 +337,6 @@ void Scheduler::updateFrameSkipping(const int64_t skipCount) {
    }
}

void Scheduler::determineLayerTimestampStats(const std::string layerName,
                                             const nsecs_t framePresentTime) {
    std::vector<int64_t> differencesMs;
    std::string differencesText = "";
    {
        std::lock_guard<std::mutex> lock(mLayerHistoryLock);
        mLayerHistory.insert(layerName, framePresentTime);

        // Traverse through the layer history, and determine the differences in present times.
        nsecs_t newestPresentTime = framePresentTime;
        for (int i = 1; i < mLayerHistory.getSize(); i++) {
            std::unordered_map<std::string, nsecs_t> layers = mLayerHistory.get(i);
            for (auto layer : layers) {
                if (layer.first != layerName) {
                    continue;
                }
                int64_t differenceMs = (newestPresentTime - layer.second) / 1000000;
                // Dismiss noise.
                if (differenceMs > 10 && differenceMs < 60) {
                    differencesMs.push_back(differenceMs);
                }
                IF_ALOGV() { differencesText += (std::to_string(differenceMs) + " "); }
                newestPresentTime = layer.second;
            }
        }
    }
    ALOGV("Layer %s timestamp intervals: %s", layerName.c_str(), differencesText.c_str());

    if (!differencesMs.empty()) {
        // Mean/Average is a good indicator for when 24fps videos are playing, because the frames
        // come in 33, and 49 ms intervals with occasional 41ms.
        const int64_t meanMs = scheduler::calculate_mean(differencesMs);
        const auto tagMean = "TimestampMean_" + layerName;
        ATRACE_INT(tagMean.c_str(), meanMs);

        // Mode and median are good indicators for 30 and 60 fps videos, because the majority of
        // frames come in 16, or 33 ms intervals.
        const auto tagMedian = "TimestampMedian_" + layerName;
        ATRACE_INT(tagMedian.c_str(), scheduler::calculate_median(&differencesMs));

        const auto tagMode = "TimestampMode_" + layerName;
        ATRACE_INT(tagMode.c_str(), scheduler::calculate_mode(differencesMs));
    }
}

void Scheduler::determineTimestampAverage(bool isAutoTimestamp, const nsecs_t framePresentTime) {
    ATRACE_INT("AutoTimestamp", isAutoTimestamp);

    // Video does not have timestamp automatically set, so we discard timestamps that are
    // coming in from other sources for now.
    if (isAutoTimestamp) {
        return;
    }
    int64_t differenceMs = (framePresentTime - mPreviousFrameTimestamp) / 1000000;
    mPreviousFrameTimestamp = framePresentTime;

    if (differenceMs < 10 || differenceMs > 100) {
        // Dismiss noise.
        return;
    }
    ATRACE_INT("TimestampDiff", differenceMs);

    mTimeDifferences[mCounter % scheduler::ARRAY_SIZE] = differenceMs;
    mCounter++;
    int64_t mean = scheduler::calculate_mean(mTimeDifferences);
    ATRACE_INT("AutoTimestampMean", mean);

    // TODO(b/113612090): This are current numbers from trial and error while running videos
    // from YouTube at 24, 30, and 60 fps.
    if (mean > 14 && mean < 18) {
        ATRACE_INT("MediaFPS", 60);
    } else if (mean > 31 && mean < 34) {
        ATRACE_INT("MediaFPS", 30);
        return;
    } else if (mean > 39 && mean < 42) {
        ATRACE_INT("MediaFPS", 24);
    }
}

void Scheduler::resetIdleTimer() {
    if (mIdleTimer) {
        mIdleTimer->reset();
@@ -414,22 +344,16 @@ void Scheduler::resetIdleTimer() {
}

void Scheduler::resetTimerCallback() {
    std::lock_guard<std::mutex> lock(mCallbackLock);
    if (mChangeRefreshRateCallback) {
    // We do not notify the applications about config changes when idle timer is reset.
        mChangeRefreshRateCallback(RefreshRateType::PERFORMANCE, ConfigEvent::None);
    timerChangeRefreshRate(IdleTimerState::RESET);
    ATRACE_INT("ExpiredIdleTimer", 0);
}
}

void Scheduler::expiredTimerCallback() {
    std::lock_guard<std::mutex> lock(mCallbackLock);
    if (mChangeRefreshRateCallback) {
    // We do not notify the applications about config changes when idle timer expires.
        mChangeRefreshRateCallback(RefreshRateType::DEFAULT, ConfigEvent::None);
    timerChangeRefreshRate(IdleTimerState::EXPIRED);
    ATRACE_INT("ExpiredIdleTimer", 1);
}
}

std::string Scheduler::doDump() {
    std::ostringstream stream;
@@ -437,4 +361,46 @@ std::string Scheduler::doDump() {
    return stream.str();
}

void Scheduler::mediaChangeRefreshRate(MediaFeatureState mediaFeatureState) {
    // Default playback for media is DEFAULT when media is on.
    RefreshRateType refreshRateType = RefreshRateType::DEFAULT;
    ConfigEvent configEvent = ConfigEvent::None;

    {
        std::lock_guard<std::mutex> lock(mFeatureStateLock);
        mCurrentMediaFeatureState = mediaFeatureState;
        // Only switch to PERFORMANCE if idle timer was reset, when turning
        // media off. If the timer is IDLE, stay at DEFAULT.
        if (mediaFeatureState == MediaFeatureState::MEDIA_OFF &&
            mCurrentIdleTimerState == IdleTimerState::RESET) {
            refreshRateType = RefreshRateType::PERFORMANCE;
        }
    }
    changeRefreshRate(refreshRateType, configEvent);
}

void Scheduler::timerChangeRefreshRate(IdleTimerState idleTimerState) {
    RefreshRateType refreshRateType = RefreshRateType::DEFAULT;
    ConfigEvent configEvent = ConfigEvent::None;

    {
        std::lock_guard<std::mutex> lock(mFeatureStateLock);
        mCurrentIdleTimerState = idleTimerState;
        // Only switch to PERFOMANCE if the idle timer was reset, and media is
        // not playing. Otherwise, stay at DEFAULT.
        if (idleTimerState == IdleTimerState::RESET &&
            mCurrentMediaFeatureState == MediaFeatureState::MEDIA_OFF) {
            refreshRateType = RefreshRateType::PERFORMANCE;
        }
    }
    changeRefreshRate(refreshRateType, configEvent);
}

void Scheduler::changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent) {
    std::lock_guard<std::mutex> lock(mCallbackLock);
    if (mChangeRefreshRateCallback) {
        mChangeRefreshRateCallback(refreshRateType, configEvent);
    }
}

} // namespace android
+30 −15
Original line number Diff line number Diff line
@@ -141,11 +141,11 @@ public:
    void addPresentFence(const std::shared_ptr<FenceTime>& fenceTime);
    void setIgnorePresentFences(bool ignore);
    nsecs_t expectedPresentTime();
    // Adds the present time for given layer to the history of present times.
    void addFramePresentTimeForLayer(const nsecs_t framePresentTime, bool isAutoTimestamp,
                                     const std::string layerName);
    // Increments counter in the layer history to indicate that SF has started a new frame.
    void incrementFrameCounter();
    // apiId indicates the API (NATIVE_WINDOW_API_xxx) that queues the buffer.
    // TODO(b/123956502): Remove this call with V1 go/content-fps-detection-in-scheduler.
    void addNativeWindowApi(int apiId);
    // Updates FPS based on the most occured request for Native Window API.
    void updateFpsBasedOnNativeWindowApi();
    // Callback that gets invoked when Scheduler wants to change the refresh rate.
    void setChangeRefreshRateCallback(const ChangeRefreshRateCallback& changeRefreshRateCallback);

@@ -165,17 +165,16 @@ protected:
private:
    friend class TestableScheduler;

    // 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.
    enum class MediaFeatureState { MEDIA_PLAYING, MEDIA_OFF };
    enum class IdleTimerState { EXPIRED, RESET };

    // Creates a connection on the given EventThread and forwards the given callbacks.
    sp<EventThreadConnection> createConnectionInternal(EventThread*, ResyncCallback&&);

    nsecs_t calculateAverage() const;
    void updateFrameSkipping(const int64_t skipCount);
    // Collects the statistical mean (average) and median between timestamp
    // intervals for each frame for each layer.
    void determineLayerTimestampStats(const std::string layerName, const nsecs_t framePresentTime);
    // Collects the average difference between timestamps for each frame regardless
    // of which layer the timestamp came from.
    void determineTimestampAverage(bool isAutoTimestamp, const nsecs_t framePresentTime);
    // Function that resets the idle timer.
    void resetIdleTimer();
    // Function that is called when the timer resets.
@@ -184,6 +183,12 @@ private:
    void expiredTimerCallback();
    // Sets vsync period.
    void setVsyncPeriod(const nsecs_t period);
    // Media feature's function to change the refresh rate.
    void mediaChangeRefreshRate(MediaFeatureState mediaFeatureState);
    // Idle timer feature's function to change the refresh rate.
    void timerChangeRefreshRate(IdleTimerState idleTimerState);
    // Acquires a lock and calls the ChangeRefreshRateCallback() with given parameters.
    void changeRefreshRate(RefreshRateType refreshRateType, ConfigEvent configEvent);

    // If fences from sync Framework are supported.
    const bool mHasSyncFramework;
@@ -217,10 +222,13 @@ private:
    std::array<int64_t, scheduler::ARRAY_SIZE> mTimeDifferences{};
    size_t mCounter = 0;

    // DetermineLayerTimestampStats is called from BufferQueueLayer::onFrameAvailable which
    // can run on any thread, and cause failure.
    std::mutex mLayerHistoryLock;
    LayerHistory mLayerHistory GUARDED_BY(mLayerHistoryLock);
    // The following few fields follow native window api bits that come with buffers. If there are
    // more buffers with NATIVE_WINDOW_API_MEDIA we render at 60Hz, otherwise we render at 90Hz.
    // There is not dependency on timestamp for V0.
    // TODO(b/123956502): Remove this when more robust logic for content fps detection is developed.
    std::mutex mWindowApiHistoryLock;
    std::array<int, scheduler::ARRAY_SIZE> mWindowApiHistory GUARDED_BY(mWindowApiHistoryLock);
    int64_t mApiHistoryCounter = 0;

    // Timer that records time between requests for next vsync. If the time is higher than a given
    // interval, a callback is fired. Set this variable to >0 to use this feature.
@@ -229,6 +237,13 @@ private:

    std::mutex mCallbackLock;
    ChangeRefreshRateCallback mChangeRefreshRateCallback GUARDED_BY(mCallbackLock);

    // 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.
    std::mutex mFeatureStateLock;
    MediaFeatureState mCurrentMediaFeatureState GUARDED_BY(mFeatureStateLock) =
            MediaFeatureState::MEDIA_OFF;
    IdleTimerState mCurrentIdleTimerState GUARDED_BY(mFeatureStateLock) = IdleTimerState::RESET;
};

} // namespace android
+0 −18
Original line number Diff line number Diff line
@@ -34,23 +34,5 @@ int64_t calculate_median(std::vector<int64_t>* v) {
    return v->at(n);
}

int64_t calculate_mode(const std::vector<int64_t>& v) {
    if (v.empty()) {
        return 0;
    }

    // Create a map with all the counts for the indivicual values in the vector.
    std::unordered_map<int64_t, int64_t> counts;
    for (int64_t value : v) {
        counts[value]++;
    }

    // Sort the map, and return the number with the highest count. If two numbers have
    // the same count, first one is returned.
    using ValueType = const decltype(counts)::value_type&;
    const auto compareCounts = [](ValueType l, ValueType r) { return l.second <= r.second; };
    return std::max_element(counts.begin(), counts.end(), compareCounts)->first;
}

} // namespace scheduler
} // namespace android
+19 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include <cinttypes>
#include <numeric>
#include <unordered_map>
#include <vector>

namespace android {
@@ -45,7 +46,24 @@ auto calculate_mean(const T& v) {
int64_t calculate_median(std::vector<int64_t>* v);

// Calculates the statistical mode in the vector. Return 0 if the vector is empty.
int64_t calculate_mode(const std::vector<int64_t>& v);
template <typename T>
auto calculate_mode(const T& v) {
    if (v.empty()) {
        return 0;
    }

    // Create a map with all the counts for the indivicual values in the vector.
    std::unordered_map<int64_t, int> counts;
    for (int64_t value : v) {
        counts[value]++;
    }

    // Sort the map, and return the number with the highest count. If two numbers have
    // the same count, first one is returned.
    using ValueType = const decltype(counts)::value_type&;
    const auto compareCounts = [](ValueType l, ValueType r) { return l.second <= r.second; };
    return static_cast<int>(std::max_element(counts.begin(), counts.end(), compareCounts)->first);
}

} // namespace scheduler
} // namespace android
 No newline at end of file
Loading