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

Commit 856c106c authored by Alec Mouri's avatar Alec Mouri Committed by Nathaniel Nifong
Browse files

Move reading sysprops out of the Flattener.

Flattener cannot read sysprops directly as otherwise FlattenerTest may
begin to use device-specific toggles in a test suite that is meant to be
device-agnostic

Bug: 196210513
Test: libcompositionengine_test
Change-Id: I65a4a18f7e609d4a0f70a4a49fae5cd1f85d12a2
(cherry picked from commit f0daebe2)
parent f99d336d
Loading
Loading
Loading
Loading
+50 −33
Original line number Diff line number Diff line
@@ -38,10 +38,14 @@ class Predictor;

class Flattener {
public:
    struct CachedSetRenderSchedulingTunables {
        // This default assumes that rendering a cached set takes about 3ms. That time is then cut
        // in half - the next frame using the cached set would have the same workload, meaning that
        // composition cost is the same. This is best illustrated with the following example:
    // Collection of tunables which are backed by sysprops
    struct Tunables {
        // Tunables that are specific to scheduling when a cached set should be rendered
        struct RenderScheduling {
            // This default assumes that rendering a cached set takes about 3ms. That time is then
            // cut in half - the next frame using the cached set would have the same workload,
            // meaning that composition cost is the same. This is best illustrated with the
            // following example:
            //
            // Suppose we're at a 120hz cadence so SurfaceFlinger is budgeted 8.3ms per-frame. If
            // renderCachedSets costs 3ms, then two consecutive frames have timings:
@@ -52,21 +56,38 @@ public:
            //
            // Now the second frame won't render a cached set afterwards, but the first frame didn't
            // really steal time from the second frame.
        static const constexpr std::chrono::nanoseconds kDefaultCachedSetRenderDuration = 1500us;
            static const constexpr std::chrono::nanoseconds kDefaultCachedSetRenderDuration =
                    1500us;

            static const constexpr size_t kDefaultMaxDeferRenderAttempts = 240;

        // Duration allocated for rendering a cached set. If we don't have enough time for rendering
        // a cached set, then rendering is deferred to another frame.
            // Duration allocated for rendering a cached set. If we don't have enough time for
            // rendering a cached set, then rendering is deferred to another frame.
            const std::chrono::nanoseconds cachedSetRenderDuration;
        // Maximum of times that we defer rendering a cached set. If we defer rendering a cached set
        // too many times, then render it anyways so that future frames would benefit from the
        // flattened cached set.
            // Maximum of times that we defer rendering a cached set. If we defer rendering a cached
            // set too many times, then render it anyways so that future frames would benefit from
            // the flattened cached set.
            const size_t maxDeferRenderAttempts;
        };
    Flattener(renderengine::RenderEngine& renderEngine, bool enableHolePunch = false,
              std::optional<CachedSetRenderSchedulingTunables> cachedSetRenderSchedulingTunables =
                      std::nullopt);

        static const constexpr std::chrono::milliseconds kDefaultActiveLayerTimeout = 150ms;

        static const constexpr bool kDefaultEnableHolePunch = true;

        // Threshold for determing whether a layer is active. A layer whose properties, including
        // the buffer, have not changed in at least this time is considered inactive and is
        // therefore a candidate for flattening.
        const std::chrono::milliseconds mActiveLayerTimeout;

        // Toggles for scheduling when it's safe to render a cached set.
        // See: RenderScheduling
        const std::optional<RenderScheduling> mRenderScheduling;

        // True if the hole punching feature should be enabled.
        const bool mEnableHolePunch;
    };

    Flattener(renderengine::RenderEngine& renderEngine, const Tunables& tunables);

    void setDisplaySize(ui::Size size) {
        mDisplaySize = size;
@@ -177,8 +198,7 @@ private:
    void buildCachedSets(std::chrono::steady_clock::time_point now);

    renderengine::RenderEngine& mRenderEngine;
    const bool mEnableHolePunch;
    const std::optional<CachedSetRenderSchedulingTunables> mCachedSetRenderSchedulingTunables;
    const Tunables mTunables;

    TexturePool mTexturePool;

@@ -202,9 +222,6 @@ private:
    size_t mCachedSetCreationCount = 0;
    size_t mCachedSetCreationCost = 0;
    std::unordered_map<size_t, size_t> mInvalidatedCachedSetAges;
    std::chrono::nanoseconds mActiveLayerTimeout = kActiveLayerTimeout;

    static constexpr auto kActiveLayerTimeout = std::chrono::nanoseconds(150ms);
};

} // namespace compositionengine::impl::planner
+3 −0
Original line number Diff line number Diff line
@@ -39,6 +39,9 @@ namespace compositionengine::impl::planner {
// heuristically determining the composition strategy of the current layer stack,
// and flattens inactive layers into an override buffer so it can be used
// as a more efficient representation of parts of the layer stack.
// Implicitly, layer caching must also be enabled for the Planner to have any effect
// E.g., setprop debug.sf.enable_layer_caching 1, or
// adb shell service call SurfaceFlinger 1040 i32 1 [i64 <display ID>]
class Planner {
public:
    Planner(renderengine::RenderEngine& renderengine);
+9 −18
Original line number Diff line number Diff line
@@ -60,19 +60,8 @@ bool isSameStack(const std::vector<const LayerState*>& incomingLayers,

} // namespace

Flattener::Flattener(
        renderengine::RenderEngine& renderEngine, bool enableHolePunch,
        std::optional<CachedSetRenderSchedulingTunables> cachedSetRenderSchedulingTunables)
      : mRenderEngine(renderEngine),
        mEnableHolePunch(enableHolePunch),
        mCachedSetRenderSchedulingTunables(cachedSetRenderSchedulingTunables),
        mTexturePool(mRenderEngine) {
    const int timeoutInMs =
            base::GetIntProperty(std::string("debug.sf.layer_caching_active_layer_timeout_ms"), 0);
    if (timeoutInMs != 0) {
        mActiveLayerTimeout = std::chrono::milliseconds(timeoutInMs);
    }
}
Flattener::Flattener(renderengine::RenderEngine& renderEngine, const Tunables& tunables)
      : mRenderEngine(renderEngine), mTunables(tunables), mTexturePool(mRenderEngine) {}

NonBufferHash Flattener::flattenLayers(const std::vector<const LayerState*>& layers,
                                       NonBufferHash hash, time_point now) {
@@ -128,14 +117,14 @@ void Flattener::renderCachedSets(
    // If we have a render deadline, and the flattener is configured to skip rendering if we don't
    // have enough time, then we skip rendering the cached set if we think that we'll steal too much
    // time from the next frame.
    if (renderDeadline && mCachedSetRenderSchedulingTunables) {
    if (renderDeadline && mTunables.mRenderScheduling) {
        if (const auto estimatedRenderFinish =
                    now + mCachedSetRenderSchedulingTunables->cachedSetRenderDuration;
                    now + mTunables.mRenderScheduling->cachedSetRenderDuration;
            estimatedRenderFinish > *renderDeadline) {
            mNewCachedSet->incrementSkipCount();

            if (mNewCachedSet->getSkipCount() <=
                mCachedSetRenderSchedulingTunables->maxDeferRenderAttempts) {
                mTunables.mRenderScheduling->maxDeferRenderAttempts) {
                ATRACE_FORMAT("DeadlinePassed: exceeded deadline by: %d us",
                              std::chrono::duration_cast<std::chrono::microseconds>(
                                      estimatedRenderFinish - *renderDeadline)
@@ -420,8 +409,10 @@ std::vector<Flattener::Run> Flattener::findCandidateRuns(time_point now) const {
    bool runHasFirstLayer = false;

    for (auto currentSet = mLayers.cbegin(); currentSet != mLayers.cend(); ++currentSet) {
        const bool layerIsInactive = now - currentSet->getLastUpdate() > mActiveLayerTimeout;
        const bool layerIsInactive =
                now - currentSet->getLastUpdate() > mTunables.mActiveLayerTimeout;
        const bool layerHasBlur = currentSet->hasBlurBehind();

        if (layerIsInactive && (firstLayer || runHasFirstLayer || !layerHasBlur) &&
            !currentSet->hasUnsupportedDataspace()) {
            if (isPartOfRun) {
@@ -522,7 +513,7 @@ void Flattener::buildCachedSets(time_point now) {
        mNewCachedSet->addBackgroundBlurLayer(*bestRun->getBlurringLayer());
    }

    if (mEnableHolePunch && bestRun->getHolePunchCandidate() &&
    if (mTunables.mEnableHolePunch && bestRun->getHolePunchCandidate() &&
        bestRun->getHolePunchCandidate()->requiresHolePunch()) {
        // Add the pip layer to mNewCachedSet, but in a special way - it should
        // replace the buffer with a clear round rect.
+22 −12
Original line number Diff line number Diff line
@@ -32,36 +32,46 @@ namespace android::compositionengine::impl::planner {

namespace {

std::optional<Flattener::CachedSetRenderSchedulingTunables> buildFlattenerTuneables() {
std::optional<Flattener::Tunables::RenderScheduling> buildRenderSchedulingTunables() {
    if (!base::GetBoolProperty(std::string("debug.sf.enable_cached_set_render_scheduling"), true)) {
        return std::nullopt;
    }

    auto renderDuration = std::chrono::nanoseconds(
    const auto renderDuration = std::chrono::nanoseconds(
            base::GetUintProperty<uint64_t>(std::string("debug.sf.cached_set_render_duration_ns"),
                                            Flattener::CachedSetRenderSchedulingTunables::
                                            Flattener::Tunables::RenderScheduling::
                                                    kDefaultCachedSetRenderDuration.count()));

    auto maxDeferRenderAttempts = base::GetUintProperty<
    const auto maxDeferRenderAttempts = base::GetUintProperty<
            size_t>(std::string("debug.sf.cached_set_max_defer_render_attmpts"),
                    Flattener::CachedSetRenderSchedulingTunables::kDefaultMaxDeferRenderAttempts);
                    Flattener::Tunables::RenderScheduling::kDefaultMaxDeferRenderAttempts);

    return std::make_optional<Flattener::CachedSetRenderSchedulingTunables>(
            Flattener::CachedSetRenderSchedulingTunables{
    return std::make_optional<Flattener::Tunables::RenderScheduling>(
            Flattener::Tunables::RenderScheduling{
                    .cachedSetRenderDuration = renderDuration,
                    .maxDeferRenderAttempts = maxDeferRenderAttempts,
            });
}

Flattener::Tunables buildFlattenerTuneables() {
    const auto activeLayerTimeout = std::chrono::milliseconds(
            base::GetIntProperty<int32_t>(std::string(
                                                  "debug.sf.layer_caching_active_layer_timeout_ms"),
                                          Flattener::Tunables::kDefaultActiveLayerTimeout.count()));
    const auto enableHolePunch =
            base::GetBoolProperty(std::string("debug.sf.enable_hole_punch_pip"),
                                  Flattener::Tunables::kDefaultEnableHolePunch);
    return Flattener::Tunables{
            .mActiveLayerTimeout = activeLayerTimeout,
            .mRenderScheduling = buildRenderSchedulingTunables(),
            .mEnableHolePunch = enableHolePunch,
    };
}

} // namespace

Planner::Planner(renderengine::RenderEngine& renderEngine)
      // Implicitly, layer caching must also be enabled for the hole punch or
      // predictor to have any effect.
      // E.g., setprop debug.sf.enable_layer_caching 1, or
      // adb shell service call SurfaceFlinger 1040 i32 1 [i64 <display ID>]
      : mFlattener(renderEngine,
                   base::GetBoolProperty(std::string("debug.sf.enable_hole_punch_pip"), true),
                   buildFlattenerTuneables()) {
    mPredictorEnabled =
            base::GetBoolProperty(std::string("debug.sf.enable_planner_prediction"), false);
+15 −12
Original line number Diff line number Diff line
@@ -47,23 +47,24 @@ namespace {

class TestableFlattener : public Flattener {
public:
    TestableFlattener(renderengine::RenderEngine& renderEngine, bool enableHolePunch,
                      std::optional<Flattener::CachedSetRenderSchedulingTunables>
                              cachedSetRenderSchedulingTunables = std::nullopt)
          : Flattener(renderEngine, enableHolePunch, cachedSetRenderSchedulingTunables) {}
    TestableFlattener(renderengine::RenderEngine& renderEngine, const Tunables& tunables)
          : Flattener(renderEngine, tunables) {}
    const std::optional<CachedSet>& getNewCachedSetForTesting() const { return mNewCachedSet; }
};

class FlattenerTest : public testing::Test {
public:
    FlattenerTest() : FlattenerTest(std::nullopt) {}
    FlattenerTest()
          : FlattenerTest(Flattener::Tunables{
                    .mActiveLayerTimeout = 100ms,
                    .mRenderScheduling = std::nullopt,
                    .mEnableHolePunch = true,
            }) {}
    void SetUp() override;

protected:
    FlattenerTest(std::optional<Flattener::CachedSetRenderSchedulingTunables>
                          cachedSetRenderSchedulingTunables)
          : mFlattener(std::make_unique<TestableFlattener>(mRenderEngine, true,
                                                           cachedSetRenderSchedulingTunables)) {}
    FlattenerTest(const Flattener::Tunables& tunables)
          : mFlattener(std::make_unique<TestableFlattener>(mRenderEngine, tunables)) {}
    void initializeOverrideBuffer(const std::vector<const LayerState*>& layers);
    void initializeFlattener(const std::vector<const LayerState*>& layers);
    void expectAllLayersFlattened(const std::vector<const LayerState*>& layers);
@@ -899,11 +900,13 @@ class FlattenerRenderSchedulingTest : public FlattenerTest {
public:
    FlattenerRenderSchedulingTest()
          : FlattenerTest(
                    Flattener::CachedSetRenderSchedulingTunables{.cachedSetRenderDuration =
                    Flattener::Tunables{.mActiveLayerTimeout = 100ms,
                                        .mRenderScheduling = Flattener::Tunables::
                                                RenderScheduling{.cachedSetRenderDuration =
                                                                         kCachedSetRenderDuration,
                                                                 .maxDeferRenderAttempts =
                                                                         kMaxDeferRenderAttempts}) {
    }
                                                                         kMaxDeferRenderAttempts},
                                        .mEnableHolePunch = true}) {}
};

TEST_F(FlattenerRenderSchedulingTest, flattenLayers_renderCachedSets_defersUpToMaxAttempts) {