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

Commit c58708a6 authored by Shane's avatar Shane Committed by George Mount
Browse files

Reduce the votePreferredFrameRate calls

votePreferredFrameRate() is now called during
updateDisplayListIfDirty() so that it is only called
once for each View at most.

Fixes: 332622024
Fixes: 333193682
Test: atest ViewRootImplTest / ViewFrameRateTest / ViewTest
Change-Id: I32a97d55a03b15b4f899ff0ea52dd0b80766eed1
parent ecad616a
Loading
Loading
Loading
Loading
+31 −24
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import static android.view.flags.Flags.sensitiveContentAppProtection;
import static android.view.flags.Flags.toolkitFrameRateBySizeReadOnly;
import static android.view.flags.Flags.toolkitFrameRateDefaultNormalReadOnly;
import static android.view.flags.Flags.toolkitFrameRateSmallUsesPercentReadOnly;
import static android.view.flags.Flags.toolkitFrameRateVelocityMappingReadOnly;
import static android.view.flags.Flags.toolkitFrameRateViewEnablingReadOnly;
import static android.view.flags.Flags.toolkitMetricsForFrameRateDecision;
import static android.view.flags.Flags.toolkitSetFrameRateReadOnly;
@@ -2443,6 +2444,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
            toolkitFrameRateSmallUsesPercentReadOnly();
    private static final boolean sToolkitFrameRateViewEnablingReadOnlyFlagValue =
            toolkitFrameRateViewEnablingReadOnly();
    private static boolean sToolkitFrameRateVelocityMappingReadOnlyFlagValue =
            toolkitFrameRateVelocityMappingReadOnly();
    // Used to set frame rate compatibility.
    @Surface.FrameRateCompatibility int mFrameRateCompatibility =
@@ -5739,6 +5742,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     */
    private static final float FRAME_RATE_SIZE_PERCENTAGE_THRESHOLD = 0.07f;
    private static final float MAX_FRAME_RATE = 140;
    private static final int INFREQUENT_UPDATE_INTERVAL_MILLIS = 100;
    private static final int INFREQUENT_UPDATE_COUNTS = 2;
@@ -20824,12 +20829,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
            return;
        }
        // For VRR to vote the preferred frame rate
        if (sToolkitSetFrameRateReadOnlyFlagValue
                && sToolkitFrameRateViewEnablingReadOnlyFlagValue) {
            votePreferredFrameRate();
        }
        // Reset content capture caches
        mPrivateFlags4 &= ~PFLAG4_CONTENT_CAPTURE_IMPORTANCE_MASK;
        mContentCaptureSessionCached = false;
@@ -20932,11 +20931,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     */
    protected void damageInParent() {
        if (mParent != null && mAttachInfo != null) {
            // For VRR to vote the preferred frame rate
            if (sToolkitSetFrameRateReadOnlyFlagValue
                    && sToolkitFrameRateViewEnablingReadOnlyFlagValue) {
                votePreferredFrameRate();
            }
            mParent.onDescendantInvalidated(this, this);
        }
    }
@@ -23624,12 +23618,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
            return renderNode;
        }
        mPrivateFlags4 = (mPrivateFlags4 & ~PFLAG4_HAS_MOVED) | PFLAG4_HAS_DRAWN;
        // For VRR to vote the preferred frame rate
        if (sToolkitSetFrameRateReadOnlyFlagValue
                && sToolkitFrameRateViewEnablingReadOnlyFlagValue) {
            votePreferredFrameRate();
            updateInfrequentCount();
        }
        mPrivateFlags4 = (mPrivateFlags4 & ~PFLAG4_HAS_MOVED) | PFLAG4_HAS_DRAWN;
        if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0
                || !renderNode.hasDisplayList()
                || (mRecreateDisplayList)) {
@@ -23694,6 +23691,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
            mPrivateFlags |= PFLAG_DRAWN | PFLAG_DRAWING_CACHE_VALID;
            mPrivateFlags &= ~PFLAG_DIRTY_MASK;
        }
        mFrameContentVelocity = -1;
        return renderNode;
    }
@@ -24792,8 +24791,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        final int privateFlags = mPrivateFlags;
        mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
        mFrameContentVelocity = -1;
        /*
         * Draw traversal performs several drawing steps which must be executed
         * in the appropriate order:
@@ -33888,32 +33885,42 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        return mLastFrameRateCategory;
    }
    private void votePreferredFrameRate() {
    /**
     * Used to vote the preferred frame rate and frame rate category to ViewRootImpl
     *
     * @hide
     */
    protected void votePreferredFrameRate() {
        // use toolkitSetFrameRate flag to gate the change
        ViewRootImpl viewRootImpl = getViewRootImpl();
        int width = mRight - mLeft;
        int height = mBottom - mTop;
        float alpha = mTransformationInfo != null ? mTransformationInfo.mAlpha : 1;
        int visibility = mViewFlags & VISIBILITY_MASK;
        if (viewRootImpl != null && (width != 0 && height != 0)
                && alpha != 0 && visibility == View.VISIBLE
        ) {
        if (viewRootImpl != null && (width != 0 && height != 0)) {
            if (mAttachInfo.mViewVelocityApi) {
                float velocity = mFrameContentVelocity;
                int mask = PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN;
                if (velocity < 0f && (mPrivateFlags4 & mask) == mask) {
                float frameRate = 0;
                if (velocity < 0f
                        && (mPrivateFlags4 & mask) == mask
                        && mParent instanceof View
                        && ((View) mParent).mFrameContentVelocity <= 0
                ) {
                    // This current calculation is very simple. If something on the screen moved,
                    // then it votes for the highest velocity. If it doesn't move, then return 0.
                    velocity = Float.POSITIVE_INFINITY;
                    frameRate = MAX_FRAME_RATE;
                }
                if (velocity > 0f) {
                    float frameRate = convertVelocityToFrameRate(velocity);
                    if (sToolkitFrameRateVelocityMappingReadOnlyFlagValue) {
                        frameRate = convertVelocityToFrameRate(velocity);
                    }
                    viewRootImpl.votePreferredFrameRate(frameRate, FRAME_RATE_COMPATIBILITY_GTE);
                    return;
                }
            }
            if (!willNotDraw()) {
            if (!willNotDraw() && isDirty()) {
                if (sToolkitMetricsForFrameRateDecisionFlagValue) {
                    float sizePercentage = width * height / mAttachInfo.mDisplayPixelCount;
                    viewRootImpl.recordViewPercentage(sizePercentage);
@@ -33962,7 +33969,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        float density = mAttachInfo.mDensity;
        float velocityDps = velocityPps / density;
        // Choose a frame rate in increments of 10fps
        return Math.min(140f, 60f + (10f * (float) Math.floor(velocityDps / 300f)));
        return Math.min(MAX_FRAME_RATE, 60f + (10f * (float) Math.floor(velocityDps / 300f)));
    }
    /**
+2 −0
Original line number Diff line number Diff line
@@ -4227,6 +4227,7 @@ public final class ViewRootImpl implements ViewParent,
                ? mFrameRateCategoryLowCount - 1 : mFrameRateCategoryLowCount;
        mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE;
        mPreferredFrameRate = -1;
        mFrameRateCompatibility = FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
        mIsFrameRateConflicted = false;
    }
@@ -12496,6 +12497,7 @@ public final class ViewRootImpl implements ViewParent,
    private void setPreferredFrameRateCategory(int preferredFrameRateCategory) {
        if (!shouldSetFrameRateCategory()
                || (mFrameRateCompatibility == FRAME_RATE_COMPATIBILITY_GTE
                && mPreferredFrameRate > 0
                && sToolkitFrameRateVelocityMappingReadOnlyFlagValue)) {
            return;
        }
+116 −32
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ package android.view;
import static android.view.Surface.FRAME_RATE_CATEGORY_HIGH;
import static android.view.Surface.FRAME_RATE_CATEGORY_LOW;
import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL;
import static android.view.Surface.FRAME_RATE_COMPATIBILITY_GTE;
import static android.view.flags.Flags.FLAG_TOOLKIT_FRAME_RATE_VELOCITY_MAPPING_READ_ONLY;
import static android.view.flags.Flags.FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY;
import static android.view.flags.Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY;
@@ -27,18 +26,23 @@ import static android.view.flags.Flags.FLAG_VIEW_VELOCITY_API;
import static android.view.flags.Flags.toolkitFrameRateBySizeReadOnly;
import static android.view.flags.Flags.toolkitFrameRateDefaultNormalReadOnly;
import static android.view.flags.Flags.toolkitFrameRateSmallUsesPercentReadOnly;
import static android.view.flags.Flags.toolkitFrameRateVelocityMappingReadOnly;

import static junit.framework.Assert.assertEquals;

import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import android.annotation.NonNull;
import android.app.Activity;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.util.DisplayMetrics;
import android.widget.FrameLayout;

import androidx.test.annotation.UiThreadTest;
import androidx.test.filters.SmallTest;
@@ -69,6 +73,8 @@ public class ViewFrameRateTest {
    private Activity mActivity;
    private View mMovingView;
    private ViewRootImpl mViewRoot;
    private CountDownLatch mAfterDrawLatch;
    private Throwable mAfterDrawThrowable;

    @Before
    public void setUp() throws Throwable {
@@ -82,23 +88,34 @@ public class ViewFrameRateTest {
            parent = parent.getParent();
        }
        mViewRoot = (ViewRootImpl) parent;
        mAfterDrawThrowable = null;
    }

    @UiThreadTest
    @Test
    @RequiresFlagsEnabled({FLAG_VIEW_VELOCITY_API,
            FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
    public void frameRateChangesWhenContentMoves() {
    public void frameRateChangesWhenContentMoves() throws Throwable {
        waitForFrameRateCategoryToSettle();
        mActivityRule.runOnUiThread(() -> {
            mMovingView.offsetLeftAndRight(100);
        float frameRate = mViewRoot.getPreferredFrameRate();
            runAfterDraw(() -> {
                if (toolkitFrameRateVelocityMappingReadOnly()) {
                    float frameRate = mViewRoot.getLastPreferredFrameRate();
                    assertTrue(frameRate > 0);
                } else {
                    assertEquals(FRAME_RATE_CATEGORY_HIGH,
                            mViewRoot.getLastPreferredFrameRateCategory());
                }
            });
        });
        waitForAfterDraw();
    }

    @UiThreadTest
    @Test
    @RequiresFlagsEnabled(FLAG_VIEW_VELOCITY_API)
    public void firstFrameNoMovement() {
        assertEquals(0f, mViewRoot.getPreferredFrameRate(), 0f);
        assertEquals(0f, mViewRoot.getLastPreferredFrameRate(), 0f);
    }

    @Test
@@ -141,9 +158,34 @@ public class ViewFrameRateTest {
        mActivityRule.runOnUiThread(() -> {
            mMovingView.setFrameContentVelocity(1f);
            mMovingView.invalidate();
            assertEquals(60f, mViewRoot.getPreferredFrameRate(), 0f);
            assertEquals(FRAME_RATE_COMPATIBILITY_GTE, mViewRoot.getFrameRateCompatibility());
            runAfterDraw(() -> assertEquals(60f, mViewRoot.getLastPreferredFrameRate(), 0f));
        });
        waitForAfterDraw();
    }

    @Test
    @RequiresFlagsEnabled({FLAG_VIEW_VELOCITY_API,
            FLAG_TOOLKIT_FRAME_RATE_VELOCITY_MAPPING_READ_ONLY,
            FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY})
    public void velocityWithChildMovement() throws Throwable {
        FrameLayout frameLayout = new FrameLayout(mActivity);
        mActivityRule.runOnUiThread(() -> {
            ViewGroup.LayoutParams fullSize = new ViewGroup.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT);
            mActivity.setContentView(frameLayout, fullSize);
            if (mMovingView.getParent() instanceof ViewGroup) {
                ((ViewGroup) mMovingView.getParent()).removeView(mMovingView);
            }
            frameLayout.addView(mMovingView, fullSize);
        });
        waitForFrameRateCategoryToSettle();
        mActivityRule.runOnUiThread(() -> {
            frameLayout.setFrameContentVelocity(1f);
            mMovingView.offsetTopAndBottom(100);
            runAfterDraw(() -> assertEquals(60f, mViewRoot.getLastPreferredFrameRate(), 0f));
        });
        waitForAfterDraw();
    }

    @Test
@@ -161,23 +203,9 @@ public class ViewFrameRateTest {
        mActivityRule.runOnUiThread(() -> {
            mMovingView.setFrameContentVelocity(1_000_000_000f);
            mMovingView.invalidate();
            assertEquals(140f, mViewRoot.getPreferredFrameRate(), 0f);
            assertEquals(FRAME_RATE_COMPATIBILITY_GTE, mViewRoot.getFrameRateCompatibility());
        });
    }

    private void waitForFrameRateCategoryToSettle() throws Throwable {
        for (int i = 0; i < 5; i++) {
            final CountDownLatch drawLatch = new CountDownLatch(1);

            // Now that it is small, any invalidation should have a normal category
            mActivityRule.runOnUiThread(() -> {
                mMovingView.invalidate();
                mMovingView.getViewTreeObserver().addOnDrawListener(drawLatch::countDown);
            runAfterDraw(() -> assertEquals(140f, mViewRoot.getLastPreferredFrameRate(), 0f));
        });

            assertTrue(drawLatch.await(1, TimeUnit.SECONDS));
        }
        waitForAfterDraw();
    }

    @Test
@@ -211,8 +239,10 @@ public class ViewFrameRateTest {
            mMovingView.invalidate();
            int expected = toolkitFrameRateBySizeReadOnly()
                    ? FRAME_RATE_CATEGORY_LOW : FRAME_RATE_CATEGORY_NORMAL;
            assertEquals(expected, mViewRoot.getPreferredFrameRateCategory());
            runAfterDraw(
                    () -> assertEquals(expected, mViewRoot.getLastPreferredFrameRateCategory()));
        });
        waitForAfterDraw();
    }

    @Test
@@ -245,8 +275,10 @@ public class ViewFrameRateTest {
            mMovingView.invalidate();
            int expected = toolkitFrameRateBySizeReadOnly()
                    ? FRAME_RATE_CATEGORY_LOW : FRAME_RATE_CATEGORY_NORMAL;
            assertEquals(expected, mViewRoot.getPreferredFrameRateCategory());
            runAfterDraw(
                    () -> assertEquals(expected, mViewRoot.getLastPreferredFrameRateCategory()));
        });
        waitForAfterDraw();
    }

    @Test
@@ -279,8 +311,10 @@ public class ViewFrameRateTest {
            mMovingView.invalidate();
            int expected = toolkitFrameRateBySizeReadOnly()
                    ? FRAME_RATE_CATEGORY_LOW : FRAME_RATE_CATEGORY_NORMAL;
            assertEquals(expected, mViewRoot.getPreferredFrameRateCategory());
            runAfterDraw(
                    () -> assertEquals(expected, mViewRoot.getLastPreferredFrameRateCategory()));
        });
        waitForAfterDraw();
    }

    @Test
@@ -313,8 +347,10 @@ public class ViewFrameRateTest {
            mMovingView.invalidate();
            int expected = toolkitFrameRateDefaultNormalReadOnly()
                    ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH;
            assertEquals(expected, mViewRoot.getPreferredFrameRateCategory());
            runAfterDraw(
                    () -> assertEquals(expected, mViewRoot.getLastPreferredFrameRateCategory()));
        });
        waitForAfterDraw();
    }

    @Test
@@ -347,8 +383,10 @@ public class ViewFrameRateTest {
            mMovingView.invalidate();
            int expected = toolkitFrameRateDefaultNormalReadOnly()
                    ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH;
            assertEquals(expected, mViewRoot.getPreferredFrameRateCategory());
            runAfterDraw(
                    () -> assertEquals(expected, mViewRoot.getLastPreferredFrameRateCategory()));
        });
        waitForAfterDraw();
    }

    @Test
@@ -367,8 +405,54 @@ public class ViewFrameRateTest {
            mMovingView.invalidate();
            int expected = toolkitFrameRateDefaultNormalReadOnly()
                    ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH;
            assertEquals(expected,
                    mViewRoot.getPreferredFrameRateCategory());
            runAfterDraw(() -> assertEquals(expected,
                    mViewRoot.getLastPreferredFrameRateCategory()));
        });
        waitForAfterDraw();
    }

    private void runAfterDraw(@NonNull Runnable runnable) {
        Handler handler = new Handler(Looper.getMainLooper());
        mAfterDrawLatch = new CountDownLatch(1);
        ViewTreeObserver.OnDrawListener listener = new ViewTreeObserver.OnDrawListener() {
            @Override
            public void onDraw() {
                handler.postAtFrontOfQueue(() -> {
                    mMovingView.getViewTreeObserver().removeOnDrawListener(this);
                    try {
                        runnable.run();
                    } catch (Throwable t) {
                        mAfterDrawThrowable = t;
                    }
                    mAfterDrawLatch.countDown();
                });
            }
        };
        mMovingView.getViewTreeObserver().addOnDrawListener(listener);
    }

    private void waitForAfterDraw() throws Throwable {
        assertTrue(mAfterDrawLatch.await(1, TimeUnit.SECONDS));
        if (mAfterDrawThrowable != null) {
            throw mAfterDrawThrowable;
        }
    }

    private void waitForFrameRateCategoryToSettle() throws Throwable {
        for (int i = 0; i < 5 || mViewRoot.getIsFrameRateBoosting(); i++) {
            final CountDownLatch drawLatch = new CountDownLatch(1);

            // Now that it is small, any invalidation should have a normal category
            ViewTreeObserver.OnDrawListener listener = drawLatch::countDown;

            mActivityRule.runOnUiThread(() -> {
                mMovingView.invalidate();
                mMovingView.getViewTreeObserver().addOnDrawListener(listener);
            });

            assertTrue(drawLatch.await(1, TimeUnit.SECONDS));
            mActivityRule.runOnUiThread(
                    () -> mMovingView.getViewTreeObserver().removeOnDrawListener(listener));
        }
    }
}
+336 −189

File changed.

Preview size limit exceeded, changes collapsed.