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

Commit 754c4cb0 authored by Ady Abraham's avatar Ady Abraham Committed by Android (Google) Code Review
Browse files

Merge "SF: remove wp<Layer> from LayerHistory" into sc-dev

parents b19cc001 bdda8f08
Loading
Loading
Loading
Loading
+3 −53
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@
#include "LayerVector.h"
#include "MonitoredProducer.h"
#include "RenderArea.h"
#include "Scheduler/LayerInfo.h"
#include "Scheduler/Seamlessness.h"
#include "SurfaceFlinger.h"
#include "SurfaceTracing.h"
@@ -141,59 +142,8 @@ public:
        float radius = 0.0f;
    };

    // FrameRateCompatibility specifies how we should interpret the frame rate associated with
    // the layer.
    enum class FrameRateCompatibility {
        Default, // Layer didn't specify any specific handling strategy

        Exact, // Layer needs the exact frame rate.

        ExactOrMultiple, // Layer needs the exact frame rate (or a multiple of it) to present the
                         // content properly. Any other value will result in a pull down.

        NoVote, // Layer doesn't have any requirements for the refresh rate and
                // should not be considered when the display refresh rate is determined.
    };

    // Encapsulates the frame rate and compatibility of the layer. This information will be used
    // when the display refresh rate is determined.
    struct FrameRate {
        using Seamlessness = scheduler::Seamlessness;

        Fps rate;
        FrameRateCompatibility type;
        Seamlessness seamlessness;

        FrameRate()
              : rate(0),
                type(FrameRateCompatibility::Default),
                seamlessness(Seamlessness::Default) {}
        FrameRate(Fps rate, FrameRateCompatibility type,
                  Seamlessness seamlessness = Seamlessness::OnlySeamless)
              : rate(rate), type(type), seamlessness(getSeamlessness(rate, seamlessness)) {}

        bool operator==(const FrameRate& other) const {
            return rate.equalsWithMargin(other.rate) && type == other.type &&
                    seamlessness == other.seamlessness;
        }

        bool operator!=(const FrameRate& other) const { return !(*this == other); }

        // Convert an ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value to a
        // Layer::FrameRateCompatibility. Logs fatal if the compatibility value is invalid.
        static FrameRateCompatibility convertCompatibility(int8_t compatibility);
        static scheduler::Seamlessness convertChangeFrameRateStrategy(int8_t strategy);

    private:
        static Seamlessness getSeamlessness(Fps rate, Seamlessness seamlessness) {
            if (!rate.isValid()) {
                // Refresh rate of 0 is a special value which should reset the vote to
                // its default value.
                return Seamlessness::Default;
            }
            return seamlessness;
        }
    };
    using FrameRate = scheduler::LayerInfo::FrameRate;
    using FrameRateCompatibility = scheduler::LayerInfo::FrameRateCompatibility;

    struct State {
        Geometry active_legacy;
+43 −40
Original line number Diff line number Diff line
@@ -39,13 +39,13 @@ namespace android::scheduler {

namespace {

bool isLayerActive(const Layer& layer, const LayerInfo& info, nsecs_t threshold) {
bool isLayerActive(const LayerInfo& info, nsecs_t threshold) {
    // Layers with an explicit vote are always kept active
    if (layer.getFrameRateForLayerTree().rate.isValid()) {
    if (info.getSetFrameRateVote().rate.isValid()) {
        return true;
    }

    return layer.isVisible() && info.getLastUpdatedTime() >= threshold;
    return info.isVisible() && info.getLastUpdatedTime() >= threshold;
}

bool traceEnabled() {
@@ -58,11 +58,7 @@ bool useFrameRatePriority() {
    return atoi(value);
}

void trace(const wp<Layer>& weak, const LayerInfo& info, LayerHistory::LayerVoteType type,
           int fps) {
    const auto layer = weak.promote();
    if (!layer) return;

void trace(const LayerInfo& info, LayerHistory::LayerVoteType type, int fps) {
    const auto traceType = [&](LayerHistory::LayerVoteType checkedType, int value) {
        ATRACE_INT(info.getTraceTag(checkedType), type == checkedType ? value : 0);
    };
@@ -75,7 +71,7 @@ void trace(const wp<Layer>& weak, const LayerInfo& info, LayerHistory::LayerVote
    traceType(LayerHistory::LayerVoteType::Min, 1);
    traceType(LayerHistory::LayerVoteType::Max, 1);

    ALOGD("%s: %s @ %d Hz", __FUNCTION__, layer->getName().c_str(), fps);
    ALOGD("%s: %s @ %d Hz", __FUNCTION__, info.getName().c_str(), fps);
}
} // namespace

@@ -88,11 +84,27 @@ LayerHistory::LayerHistory(const RefreshRateConfigs& refreshRateConfigs)
LayerHistory::~LayerHistory() = default;

void LayerHistory::registerLayer(Layer* layer, LayerVoteType type) {
    auto info = std::make_unique<LayerInfo>(layer->getName(), type);
    auto info = std::make_unique<LayerInfo>(layer->getName(), layer->getOwnerUid(), type);
    std::lock_guard lock(mLock);
    mLayerInfos.emplace_back(layer, std::move(info));
}

void LayerHistory::deregisterLayer(Layer* layer) {
    std::lock_guard lock(mLock);

    const auto it = std::find_if(mLayerInfos.begin(), mLayerInfos.end(),
                                 [layer](const auto& pair) { return pair.first == layer; });
    LOG_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer);

    const size_t i = static_cast<size_t>(it - mLayerInfos.begin());
    if (i < mActiveLayersEnd) {
        mActiveLayersEnd--;
    }
    const size_t last = mLayerInfos.size() - 1;
    std::swap(mLayerInfos[i], mLayerInfos[last]);
    mLayerInfos.erase(mLayerInfos.begin() + static_cast<long>(last));
}

void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now,
                          LayerUpdateType updateType) {
    std::lock_guard lock(mLock);
@@ -102,7 +114,15 @@ void LayerHistory::record(Layer* layer, nsecs_t presentTime, nsecs_t now,
    LOG_FATAL_IF(it == mLayerInfos.end(), "%s: unknown layer %p", __FUNCTION__, layer);

    const auto& info = it->second;
    info->setLastPresentTime(presentTime, now, updateType, mModeChangePending);
    const auto layerProps = LayerInfo::LayerProps{
            .visible = layer->isVisible(),
            .bounds = layer->getBounds(),
            .transform = layer->getTransform(),
            .setFrameRateVote = layer->getFrameRateForLayerTree(),
            .frameRateSelectionPriority = layer->getFrameRateSelectionPriority(),
    };

    info->setLastPresentTime(presentTime, now, updateType, mModeChangePending, layerProps);

    // Activate layer if inactive.
    if (const auto end = activeLayers().end(); it >= end) {
@@ -119,15 +139,10 @@ LayerHistory::Summary LayerHistory::summarize(nsecs_t now) {
    partitionLayers(now);

    for (const auto& [layer, info] : activeLayers()) {
        const auto strong = layer.promote();
        if (!strong) {
            continue;
        }

        const auto frameRateSelectionPriority = strong->getFrameRateSelectionPriority();
        const auto frameRateSelectionPriority = info->getFrameRateSelectionPriority();
        const auto layerFocused = Layer::isLayerFocusedBasedOnPriority(frameRateSelectionPriority);
        ALOGV("%s has priority: %d %s focused", strong->getName().c_str(),
              frameRateSelectionPriority, layerFocused ? "" : "not");
        ALOGV("%s has priority: %d %s focused", info->getName().c_str(), frameRateSelectionPriority,
              layerFocused ? "" : "not");

        const auto vote = info->getRefreshRateVote(now);
        // Skip NoVote layer as those don't have any requirements
@@ -136,18 +151,18 @@ LayerHistory::Summary LayerHistory::summarize(nsecs_t now) {
        }

        // Compute the layer's position on the screen
        const Rect bounds = Rect(strong->getBounds());
        const ui::Transform transform = strong->getTransform();
        const Rect bounds = Rect(info->getBounds());
        const ui::Transform transform = info->getTransform();
        constexpr bool roundOutwards = true;
        Rect transformed = transform.transform(bounds, roundOutwards);

        const float layerArea = transformed.getWidth() * transformed.getHeight();
        float weight = mDisplayArea ? layerArea / mDisplayArea : 0.0f;
        summary.push_back({strong->getName(), strong->getOwnerUid(), vote.type, vote.fps,
        summary.push_back({info->getName(), info->getOwnerUid(), vote.type, vote.fps,
                           vote.seamlessness, weight, layerFocused});

        if (CC_UNLIKELY(mTraceEnabled)) {
            trace(layer, *info, vote.type, vote.fps.getIntValue());
            trace(*info, vote.type, vote.fps.getIntValue());
        }
    }

@@ -160,11 +175,11 @@ void LayerHistory::partitionLayers(nsecs_t now) {
    // Collect expired and inactive layers after active layers.
    size_t i = 0;
    while (i < mActiveLayersEnd) {
        auto& [weak, info] = mLayerInfos[i];
        if (const auto layer = weak.promote(); layer && isLayerActive(*layer, *info, threshold)) {
        auto& [layerUnsafe, info] = mLayerInfos[i];
        if (isLayerActive(*info, threshold)) {
            i++;
            // Set layer vote if set
            const auto frameRate = layer->getFrameRateForLayerTree();
            const auto frameRate = info->getSetFrameRateVote();
            const auto voteType = [&]() {
                switch (frameRate.type) {
                    case Layer::FrameRateCompatibility::Default:
@@ -179,7 +194,7 @@ void LayerHistory::partitionLayers(nsecs_t now) {
            }();

            if (frameRate.rate.isValid() || voteType == LayerVoteType::NoVote) {
                const auto type = layer->isVisible() ? voteType : LayerVoteType::NoVote;
                const auto type = info->isVisible() ? voteType : LayerVoteType::NoVote;
                info->setLayerVote({type, frameRate.rate, frameRate.seamlessness});
            } else {
                info->resetLayerVote();
@@ -188,24 +203,12 @@ void LayerHistory::partitionLayers(nsecs_t now) {
        }

        if (CC_UNLIKELY(mTraceEnabled)) {
            trace(weak, *info, LayerHistory::LayerVoteType::NoVote, 0);
            trace(*info, LayerHistory::LayerVoteType::NoVote, 0);
        }

        info->onLayerInactive(now);
        std::swap(mLayerInfos[i], mLayerInfos[--mActiveLayersEnd]);
    }

    // Collect expired layers after inactive layers.
    size_t end = mLayerInfos.size();
    while (i < end) {
        if (mLayerInfos[i].first.promote()) {
            i++;
        } else {
            std::swap(mLayerInfos[i], mLayerInfos[--end]);
        }
    }

    mLayerInfos.erase(mLayerInfos.begin() + static_cast<long>(end), mLayerInfos.end());
}

void LayerHistory::clear() {
+3 −1
Original line number Diff line number Diff line
@@ -70,13 +70,15 @@ public:
    Summary summarize(nsecs_t now);

    void clear();

    void deregisterLayer(Layer*);
    std::string dump() const;

private:
    friend LayerHistoryTest;
    friend TestableScheduler;

    using LayerPair = std::pair<wp<Layer>, std::unique_ptr<LayerInfo>>;
    using LayerPair = std::pair<Layer*, std::unique_ptr<LayerInfo>>;
    using LayerInfos = std::vector<LayerPair>;

    struct ActiveLayers {
+5 −2
Original line number Diff line number Diff line
@@ -37,17 +37,20 @@ namespace android::scheduler {
const RefreshRateConfigs* LayerInfo::sRefreshRateConfigs = nullptr;
bool LayerInfo::sTraceEnabled = false;

LayerInfo::LayerInfo(const std::string& name, LayerHistory::LayerVoteType defaultVote)
LayerInfo::LayerInfo(const std::string& name, uid_t ownerUid,
                     LayerHistory::LayerVoteType defaultVote)
      : mName(name),
        mOwnerUid(ownerUid),
        mDefaultVote(defaultVote),
        mLayerVote({defaultVote, Fps(0.0f)}),
        mRefreshRateHistory(name) {}

void LayerInfo::setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, LayerUpdateType updateType,
                                   bool pendingModeChange) {
                                   bool pendingModeChange, LayerProps props) {
    lastPresentTime = std::max(lastPresentTime, static_cast<nsecs_t>(0));

    mLastUpdatedTime = std::max(lastPresentTime, now);
    mLayerProps = props;
    switch (updateType) {
        case LayerUpdateType::AnimationTX:
            mLastAnimationTime = std::max(lastPresentTime, now);
+80 −2
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#pragma once

#include <ui/Transform.h>
#include <utils/Timers.h>

#include <chrono>
@@ -65,22 +66,84 @@ public:
        Seamlessness seamlessness = Seamlessness::Default;
    };

    // FrameRateCompatibility specifies how we should interpret the frame rate associated with
    // the layer.
    enum class FrameRateCompatibility {
        Default, // Layer didn't specify any specific handling strategy

        Exact, // Layer needs the exact frame rate.

        ExactOrMultiple, // Layer needs the exact frame rate (or a multiple of it) to present the
                         // content properly. Any other value will result in a pull down.

        NoVote, // Layer doesn't have any requirements for the refresh rate and
                // should not be considered when the display refresh rate is determined.
    };

    // Encapsulates the frame rate and compatibility of the layer. This information will be used
    // when the display refresh rate is determined.
    struct FrameRate {
        using Seamlessness = scheduler::Seamlessness;

        Fps rate;
        FrameRateCompatibility type;
        Seamlessness seamlessness;

        FrameRate()
              : rate(0),
                type(FrameRateCompatibility::Default),
                seamlessness(Seamlessness::Default) {}
        FrameRate(Fps rate, FrameRateCompatibility type,
                  Seamlessness seamlessness = Seamlessness::OnlySeamless)
              : rate(rate), type(type), seamlessness(getSeamlessness(rate, seamlessness)) {}

        bool operator==(const FrameRate& other) const {
            return rate.equalsWithMargin(other.rate) && type == other.type &&
                    seamlessness == other.seamlessness;
        }

        bool operator!=(const FrameRate& other) const { return !(*this == other); }

        // Convert an ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value to a
        // Layer::FrameRateCompatibility. Logs fatal if the compatibility value is invalid.
        static FrameRateCompatibility convertCompatibility(int8_t compatibility);
        static scheduler::Seamlessness convertChangeFrameRateStrategy(int8_t strategy);

    private:
        static Seamlessness getSeamlessness(Fps rate, Seamlessness seamlessness) {
            if (!rate.isValid()) {
                // Refresh rate of 0 is a special value which should reset the vote to
                // its default value.
                return Seamlessness::Default;
            }
            return seamlessness;
        }
    };

    static void setTraceEnabled(bool enabled) { sTraceEnabled = enabled; }

    static void setRefreshRateConfigs(const RefreshRateConfigs& refreshRateConfigs) {
        sRefreshRateConfigs = &refreshRateConfigs;
    }

    LayerInfo(const std::string& name, LayerHistory::LayerVoteType defaultVote);
    LayerInfo(const std::string& name, uid_t ownerUid, LayerHistory::LayerVoteType defaultVote);

    LayerInfo(const LayerInfo&) = delete;
    LayerInfo& operator=(const LayerInfo&) = delete;

    struct LayerProps {
        bool visible = false;
        FloatRect bounds;
        ui::Transform transform;
        FrameRate setFrameRateVote;
        int32_t frameRateSelectionPriority = -1;
    };

    // Records the last requested present time. It also stores information about when
    // the layer was last updated. If the present time is farther in the future than the
    // updated time, the updated time is the present time.
    void setLastPresentTime(nsecs_t lastPresentTime, nsecs_t now, LayerUpdateType updateType,
                            bool pendingModeChange);
                            bool pendingModeChange, LayerProps props);

    // Sets an explicit layer vote. This usually comes directly from the application via
    // ANativeWindow_setFrameRate API
@@ -94,12 +157,24 @@ public:
    // Resets the layer vote to its default.
    void resetLayerVote() { mLayerVote = {mDefaultVote, Fps(0.0f), Seamlessness::Default}; }

    std::string getName() const { return mName; }

    uid_t getOwnerUid() const { return mOwnerUid; }

    LayerVote getRefreshRateVote(nsecs_t now);

    // Return the last updated time. If the present time is farther in the future than the
    // updated time, the updated time is the present time.
    nsecs_t getLastUpdatedTime() const { return mLastUpdatedTime; }

    FrameRate getSetFrameRateVote() const { return mLayerProps.setFrameRateVote; }
    bool isVisible() const { return mLayerProps.visible; }
    int32_t getFrameRateSelectionPriority() const { return mLayerProps.frameRateSelectionPriority; }

    FloatRect getBounds() const { return mLayerProps.bounds; }

    ui::Transform getTransform() const { return mLayerProps.transform; }

    // Returns a C string for tracing a vote
    const char* getTraceTag(LayerHistory::LayerVoteType type) const;

@@ -193,6 +268,7 @@ private:
    bool isFrameTimeValid(const FrameTimeData&) const;

    const std::string mName;
    const uid_t mOwnerUid;

    // Used for sanitizing the heuristic data. If two frames are less than
    // this period apart from each other they'll be considered as duplicates.
@@ -217,6 +293,8 @@ private:
    static constexpr size_t HISTORY_SIZE = RefreshRateHistory::HISTORY_SIZE;
    static constexpr std::chrono::nanoseconds HISTORY_DURATION = 1s;

    LayerProps mLayerProps;

    RefreshRateHistory mRefreshRateHistory;

    mutable std::unordered_map<LayerHistory::LayerVoteType, std::string> mTraceTags;
Loading