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

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

Merge "VRR: Change both frame rate and category" into main

parents faf1b4e6 6b3ff544
Loading
Loading
Loading
Loading
+47 −26
Original line number Diff line number Diff line
@@ -2428,6 +2428,26 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     */
    public static final int FRAME_RATE_CATEGORY_REASON_IDLE = 0x0700_0000;
    /**
     * This indicates that the frame rate category was chosen because it is currently boosting.
     * @hide
     */
    public static final int FRAME_RATE_CATEGORY_REASON_BOOST = 0x0800_0000;
    /**
     * This indicates that the frame rate category was chosen because it is currently having
     * touch boost.
     * @hide
     */
    public static final int FRAME_RATE_CATEGORY_REASON_TOUCH = 0x0900_0000;
    /**
     * This indicates that the frame rate category was chosen because it is currently having
     * touch boost.
     * @hide
     */
    public static final int FRAME_RATE_CATEGORY_REASON_CONFLICTED = 0x0A00_0000;
    private static final int FRAME_RATE_CATEGORY_REASON_MASK = 0xFFFF_0000;
    /**
@@ -5742,7 +5762,7 @@ 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;
    static final float MAX_FRAME_RATE = 140;
    private static final int INFREQUENT_UPDATE_INTERVAL_MILLIS = 100;
    private static final int INFREQUENT_UPDATE_COUNTS = 2;
@@ -33897,36 +33917,41 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        int height = mBottom - mTop;
        if (viewRootImpl != null && (width != 0 && height != 0)) {
            if (viewRootImpl.shouldCheckFrameRate(mPreferredFrameRate > 0f)) {
                float velocityFrameRate = 0f;
                if (mAttachInfo.mViewVelocityApi) {
                    float velocity = mFrameContentVelocity;
                int mask = PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN;
                float frameRate = 0;
                    if (velocity < 0f
                        && (mPrivateFlags4 & mask) == mask
                            && (mPrivateFlags4 & (PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN)) == (
                            PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN)
                            && 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;
                        // This current calculation is very simple. If something on the screen
                        // moved, then it votes for the highest velocity.
                        velocityFrameRate = MAX_FRAME_RATE;
                    } else if (velocity > 0f) {
                        velocityFrameRate = convertVelocityToFrameRate(velocity);
                    }
                if (velocity > 0f) {
                    if (sToolkitFrameRateVelocityMappingReadOnlyFlagValue) {
                        frameRate = convertVelocityToFrameRate(velocity);
                }
                    viewRootImpl.votePreferredFrameRate(frameRate, FRAME_RATE_COMPATIBILITY_GTE);
                    return;
                if (velocityFrameRate > 0f || mPreferredFrameRate > 0f) {
                    int compatibility = FRAME_RATE_COMPATIBILITY_GTE;
                    float frameRate = velocityFrameRate;
                    if (mPreferredFrameRate > velocityFrameRate) {
                        compatibility = FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
                        frameRate = mPreferredFrameRate;
                    }
                    viewRootImpl.votePreferredFrameRate(frameRate, compatibility);
                }
            }
            if (!willNotDraw() && isDirty()) {
            if (!willNotDraw() && isDirty() && viewRootImpl.shouldCheckFrameRateCategory()) {
                if (sToolkitMetricsForFrameRateDecisionFlagValue) {
                    float sizePercentage = width * height / mAttachInfo.mDisplayPixelCount;
                    viewRootImpl.recordViewPercentage(sizePercentage);
                }
                int frameRateCategory;
                int frameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE;
                if (Float.isNaN(mPreferredFrameRate)) {
                    frameRateCategory = calculateFrameRateCategory();
                } else if (mPreferredFrameRate < 0) {
@@ -33951,10 +33976,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                                    | FRAME_RATE_CATEGORY_REASON_INVALID;
                        }
                    }
                } else {
                    viewRootImpl.votePreferredFrameRate(mPreferredFrameRate,
                            mFrameRateCompatibility);
                    return;
                }
                int category = frameRateCategory & ~FRAME_RATE_CATEGORY_REASON_MASK;
+107 −93
Original line number Diff line number Diff line
@@ -35,14 +35,18 @@ import static android.view.Surface.FRAME_RATE_CATEGORY_NORMAL;
import static android.view.Surface.FRAME_RATE_CATEGORY_NO_PREFERENCE;
import static android.view.Surface.FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
import static android.view.Surface.FRAME_RATE_COMPATIBILITY_GTE;
import static android.view.View.FRAME_RATE_CATEGORY_REASON_BOOST;
import static android.view.View.FRAME_RATE_CATEGORY_REASON_CONFLICTED;
import static android.view.View.FRAME_RATE_CATEGORY_REASON_IDLE;
import static android.view.View.FRAME_RATE_CATEGORY_REASON_INTERMITTENT;
import static android.view.View.FRAME_RATE_CATEGORY_REASON_INVALID;
import static android.view.View.FRAME_RATE_CATEGORY_REASON_LARGE;
import static android.view.View.FRAME_RATE_CATEGORY_REASON_REQUESTED;
import static android.view.View.FRAME_RATE_CATEGORY_REASON_SMALL;
import static android.view.View.FRAME_RATE_CATEGORY_REASON_TOUCH;
import static android.view.View.FRAME_RATE_CATEGORY_REASON_UNKNOWN;
import static android.view.View.FRAME_RATE_CATEGORY_REASON_VELOCITY;
import static android.view.View.MAX_FRAME_RATE;
import static android.view.View.PFLAG_DRAW_ANIMATION;
import static android.view.View.SYSTEM_UI_FLAG_FULLSCREEN;
import static android.view.View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
@@ -4191,8 +4195,15 @@ public final class ViewRootImpl implements ViewParent,
        // For the variable refresh rate project.
        // We set the preferred frame rate and frame rate category at the end of performTraversals
        // when the values are applicable.
        setCategoryFromCategoryCounts();
        setPreferredFrameRate(mPreferredFrameRate);
        setPreferredFrameRateCategory(mPreferredFrameRateCategory);
        if (!mIsFrameRateConflicted) {
            mHandler.removeMessages(MSG_FRAME_RATE_SETTING);
            mHandler.sendEmptyMessageDelayed(MSG_FRAME_RATE_SETTING,
                    FRAME_RATE_SETTING_REEVALUATE_TIME);
        }
        checkIdleness();
        mFrameRateCategoryHighCount = mFrameRateCategoryHighCount > 0
                ? mFrameRateCategoryHighCount - 1 : mFrameRateCategoryHighCount;
        mFrameRateCategoryNormalCount = mFrameRateCategoryNormalCount > 0
@@ -4201,7 +4212,6 @@ public final class ViewRootImpl implements ViewParent,
                ? mFrameRateCategoryLowCount - 1 : mFrameRateCategoryLowCount;
        mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_DEFAULT;
        mPreferredFrameRate = -1;
        mFrameRateCompatibility = FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
        mIsFrameRateConflicted = false;
        mFrameRateCategoryChangeReason = FRAME_RATE_CATEGORY_REASON_UNKNOWN;
    }
@@ -6630,8 +6640,6 @@ public final class ViewRootImpl implements ViewParent,
                     */
                    mIsFrameRateBoosting = false;
                    mIsTouchBoosting = false;
                    setPreferredFrameRateCategory(Math.max(mPreferredFrameRateCategory,
                            mLastPreferredFrameRateCategory));
                    break;
                case MSG_CHECK_INVALIDATION_IDLE:
                    if (!mHasInvalidation && !mIsFrameRateBoosting && !mIsTouchBoosting) {
@@ -7677,7 +7685,6 @@ public final class ViewRootImpl implements ViewParent,
                    mWindowAttributes.type)) {
                // set the frame rate to the maximum value.
                mIsTouchBoosting = true;
                setPreferredFrameRateCategory(mPreferredFrameRateCategory);
            }
            /**
             * We want to lower the refresh rate when MotionEvent.ACTION_UP,
@@ -12469,59 +12476,50 @@ public final class ViewRootImpl implements ViewParent,
        EventLog.writeEvent(LOGTAG_VIEWROOT_DRAW_EVENT, mTag, msg);
    }
    /**
     * Sets the mPreferredFrameRateCategory from the high, high_hint, normal, and low counts.
     */
    private void setCategoryFromCategoryCounts() {
        if (mFrameRateCategoryHighCount > 0) {
            mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_HIGH;
        } else if (mFrameRateCategoryHighHintCount > 0) {
            mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_HIGH_HINT;
        } else if (mFrameRateCategoryNormalCount > 0) {
            mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NORMAL;
        } else if (mFrameRateCategoryLowCount > 0) {
            mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_LOW;
        }
    }
    private void setPreferredFrameRateCategory(int preferredFrameRateCategory) {
        if (!shouldSetFrameRateCategory()
                || (mFrameRateCompatibility == FRAME_RATE_COMPATIBILITY_GTE
                && mPreferredFrameRate > 0
                && sToolkitFrameRateVelocityMappingReadOnlyFlagValue)) {
        if (!shouldSetFrameRateCategory()) {
            return;
        }
        int categoryFromConflictedFrameRates = FRAME_RATE_CATEGORY_DEFAULT;
        if (mIsFrameRateConflicted) {
            categoryFromConflictedFrameRates = mPreferredFrameRate > 60
                    ? FRAME_RATE_CATEGORY_HIGH : FRAME_RATE_CATEGORY_NORMAL;
        }
        int frameRateCategory = mIsTouchBoosting
                ? FRAME_RATE_CATEGORY_HIGH_HINT
                : Math.max(preferredFrameRateCategory, categoryFromConflictedFrameRates);
        int frameRateCategory;
        int frameRateReason;
        String view;
        // FRAME_RATE_CATEGORY_HIGH has a higher precedence than FRAME_RATE_CATEGORY_HIGH_HINT
        // For now, FRAME_RATE_CATEGORY_HIGH_HINT is used for boosting with user interaction.
        // FRAME_RATE_CATEGORY_HIGH is for boosting without user interaction
        // (e.g., Window Initialization).
        if (mIsFrameRateBoosting || mInsetsAnimationRunning
                || (mFrameRateCompatibility == FRAME_RATE_COMPATIBILITY_GTE
                        && mPreferredFrameRate > 0)) {
        if (mIsFrameRateBoosting || mInsetsAnimationRunning) {
            frameRateCategory = FRAME_RATE_CATEGORY_HIGH;
            if (mFrameRateCompatibility == FRAME_RATE_COMPATIBILITY_GTE) {
                // We've received a velocity, so we'll let the velocity control the
                // frame rate unless we receive additional motion events.
                mIsTouchBoosting = false;
                mFrameRateCategoryChangeReason = FRAME_RATE_CATEGORY_REASON_VELOCITY;
                mFrameRateCategoryView = null;
            frameRateReason = FRAME_RATE_CATEGORY_REASON_BOOST;
            view = null;
        } else if (mIsTouchBoosting && preferredFrameRateCategory < FRAME_RATE_CATEGORY_HIGH_HINT) {
            frameRateCategory = FRAME_RATE_CATEGORY_HIGH_HINT;
            frameRateReason = FRAME_RATE_CATEGORY_REASON_TOUCH;
            view = null;
        } else {
                mFrameRateCategoryChangeReason = FRAME_RATE_CATEGORY_REASON_UNKNOWN;
            }
            frameRateCategory = preferredFrameRateCategory;
            frameRateReason = mFrameRateCategoryChangeReason;
            view = mFrameRateCategoryView;
        }
        try {
            if (frameRateCategory != FRAME_RATE_CATEGORY_DEFAULT
                    && mLastPreferredFrameRateCategory != frameRateCategory) {
                if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
                    String reason = reasonToString(mFrameRateCategoryChangeReason);
                    String sourceView = mFrameRateCategoryView == null ? "-"
                            : mFrameRateCategoryView;
                    if (preferredFrameRateCategory == FRAME_RATE_CATEGORY_HIGH_HINT) {
                        reason = "touch boost";
                        sourceView = "-";
                    } else if (categoryFromConflictedFrameRates == frameRateCategory
                            && frameRateCategory != preferredFrameRateCategory
                            && mIsFrameRateConflicted
                    ) {
                        reason = "conflict";
                        sourceView = "-";
                    }
                    String reason = reasonToString(frameRateReason);
                    String sourceView = view == null ? "-" : view;
                    String category = categoryToString(frameRateCategory);
                    Trace.traceBegin(
                            Trace.TRACE_TAG_VIEW, "ViewRootImpl#setFrameRateCategory "
@@ -12565,24 +12563,21 @@ public final class ViewRootImpl implements ViewParent,
            case FRAME_RATE_CATEGORY_REASON_VELOCITY -> str = "velocity";
            case FRAME_RATE_CATEGORY_REASON_IDLE -> str = "idle";
            case FRAME_RATE_CATEGORY_REASON_UNKNOWN -> str = "unknown";
            case FRAME_RATE_CATEGORY_REASON_BOOST -> str = "boost";
            case FRAME_RATE_CATEGORY_REASON_TOUCH -> str = "touch";
            case FRAME_RATE_CATEGORY_REASON_CONFLICTED -> str = "conflicted";
            default -> str = String.valueOf(reason);
        }
        return str;
    }
    private void setPreferredFrameRate(float preferredFrameRate) {
        if (!shouldSetFrameRate()) {
            return;
        }
        if (mFrameRateCompatibility == FRAME_RATE_COMPATIBILITY_GTE
                && preferredFrameRate > 0 && !sToolkitFrameRateVelocityMappingReadOnlyFlagValue) {
            mIsTouchBoosting = false;
        if (!shouldSetFrameRate() || preferredFrameRate < 0) {
            return;
        }
        try {
            if (mLastPreferredFrameRate != preferredFrameRate
                    && preferredFrameRate >= 0) {
            if (mLastPreferredFrameRate != preferredFrameRate) {
                if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
                    Trace.traceBegin(
                            Trace.TRACE_TAG_VIEW, "ViewRootImpl#setFrameRate "
@@ -12602,12 +12597,6 @@ public final class ViewRootImpl implements ViewParent,
        }
    }
    private void sendDelayedEmptyMessage(int message, int delayedTime) {
        mHandler.removeMessages(message);
        mHandler.sendEmptyMessageDelayed(message, delayedTime);
    }
    private boolean shouldSetFrameRateCategory() {
        // use toolkitSetFrameRate flag to gate the change
        return  mSurface.isValid() && shouldEnableDvrr();
@@ -12645,28 +12634,34 @@ public final class ViewRootImpl implements ViewParent,
            case FRAME_RATE_CATEGORY_HIGH ->
                    mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT;
        }
        int oldCategory = mPreferredFrameRateCategory;
        // For View that votes NO_PREFERENCE
        if (frameRateCategory > mPreferredFrameRateCategory) {
            mPreferredFrameRateCategory = frameRateCategory;
        if (mFrameRateCategoryHighCount > 0) {
            mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_HIGH;
        } else if (mFrameRateCategoryHighHintCount > 0) {
            mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_HIGH_HINT;
        } else if (mFrameRateCategoryNormalCount > 0) {
            mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_NORMAL;
        } else if (mFrameRateCategoryLowCount > 0) {
            mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_LOW;
            mFrameRateCategoryChangeReason = reason;
            mFrameRateCategoryView = view == null ? "-" : view.getClass().getSimpleName();
        }
        mHasInvalidation = true;
        checkIdleness();
        if (mPreferredFrameRateCategory != oldCategory
                && mPreferredFrameRateCategory == frameRateCategory
        ) {
            mFrameRateCategoryChangeReason = reason;
            mFrameRateCategoryView = view == null ? "null" : view.getClass().getSimpleName();
    }
    /**
     * Returns whether a View should vote for frame rate category. When the category is HIGH
     * already, there's no need to calculate the category on the View and vote.
     */
    public boolean shouldCheckFrameRateCategory() {
        return mPreferredFrameRateCategory < FRAME_RATE_CATEGORY_HIGH;
    }
    /**
     * Returns whether a View should vote for frame rate. When the maximum frame rate has already
     * been voted for, there's no point in calculating and voting for the frame rate. When
     * isDirect is false, then it will return false when the velocity-calculated frame rate
     * can be avoided.
     * @param isDirect true when the frame rate has been set directly on the View or false if
     *                 the calculation is based only on velocity.
     */
    public boolean shouldCheckFrameRate(boolean isDirect) {
        return mPreferredFrameRate < MAX_FRAME_RATE
                || (!isDirect && !sToolkitFrameRateVelocityMappingReadOnlyFlagValue
                && mPreferredFrameRateCategory < FRAME_RATE_CATEGORY_HIGH);
    }
    /**
@@ -12692,24 +12687,44 @@ public final class ViewRootImpl implements ViewParent,
        if (frameRate <= 0) {
            return;
        }
        if (frameRateCompatibility == FRAME_RATE_COMPATIBILITY_GTE) {
            mIsTouchBoosting = false;
            if (!sToolkitFrameRateVelocityMappingReadOnlyFlagValue) {
                mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_HIGH;
                mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT;
                mFrameRateCategoryChangeReason = FRAME_RATE_CATEGORY_REASON_VELOCITY;
                mFrameRateCategoryView = null;
                return;
            }
        }
        float nextFrameRate;
        int nextFrameRateCompatibility;
        if (frameRate > mPreferredFrameRate) {
            nextFrameRate = frameRate;
            nextFrameRateCompatibility = frameRateCompatibility;
        } else {
            nextFrameRate = mPreferredFrameRate;
            nextFrameRateCompatibility = mFrameRateCompatibility;
        }
        if (mPreferredFrameRate > 0 && mPreferredFrameRate % frameRate != 0
                && frameRate % mPreferredFrameRate != 0) {
            mIsFrameRateConflicted = true;
            mFrameRateCompatibility = FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
            if (nextFrameRate > 60 && mFrameRateCategoryHighCount != FRAME_RATE_CATEGORY_COUNT) {
                mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT;
                mFrameRateCategoryChangeReason = FRAME_RATE_CATEGORY_REASON_CONFLICTED;
                mFrameRateCategoryView = null;
            } else if (mFrameRateCategoryHighCount == 0 && mFrameRateCategoryHighHintCount == 0
                    && mFrameRateCategoryNormalCount < FRAME_RATE_CATEGORY_COUNT) {
                mFrameRateCategoryNormalCount = FRAME_RATE_CATEGORY_COUNT;
                mFrameRateCategoryChangeReason = FRAME_RATE_CATEGORY_REASON_CONFLICTED;
                mFrameRateCategoryView = null;
            }
        if (frameRate > mPreferredFrameRate) {
            mFrameRateCompatibility = frameRateCompatibility;
        }
        mPreferredFrameRate = Math.max(mPreferredFrameRate, frameRate);
        mPreferredFrameRate = nextFrameRate;
        mFrameRateCompatibility = nextFrameRateCompatibility;
        mHasInvalidation = true;
        if (!mIsFrameRateConflicted) {
            mHandler.removeMessages(MSG_FRAME_RATE_SETTING);
            mHandler.sendEmptyMessageDelayed(MSG_FRAME_RATE_SETTING,
                    FRAME_RATE_SETTING_REEVALUATE_TIME);
        }
        checkIdleness();
    }
    /**
@@ -12779,7 +12794,6 @@ public final class ViewRootImpl implements ViewParent,
    private void boostFrameRate(int boostTimeOut) {
        mIsFrameRateBoosting = true;
        setPreferredFrameRateCategory(mPreferredFrameRateCategory);
        mHandler.removeMessages(MSG_TOUCH_BOOST_TIMEOUT);
        mHandler.sendEmptyMessageDelayed(MSG_TOUCH_BOOST_TIMEOUT,
                boostTimeOut);
+23 −1
Original line number Diff line number Diff line
@@ -203,7 +203,9 @@ public class ViewFrameRateTest {
        mActivityRule.runOnUiThread(() -> {
            mMovingView.setFrameContentVelocity(1_000_000_000f);
            mMovingView.invalidate();
            runAfterDraw(() -> assertEquals(140f, mViewRoot.getLastPreferredFrameRate(), 0f));
            runAfterDraw(() -> {
                assertEquals(140f, mViewRoot.getLastPreferredFrameRate(), 0f);
            });
        });
        waitForAfterDraw();
    }
@@ -411,6 +413,26 @@ public class ViewFrameRateTest {
        waitForAfterDraw();
    }

    @Test
    @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,
            FLAG_TOOLKIT_FRAME_RATE_VIEW_ENABLING_READ_ONLY,
            FLAG_TOOLKIT_FRAME_RATE_VELOCITY_MAPPING_READ_ONLY
    })
    public void frameRateAndCategory() throws Throwable {
        waitForFrameRateCategoryToSettle();
        mActivityRule.runOnUiThread(() -> {
            mMovingView.setRequestedFrameRate(View.REQUESTED_FRAME_RATE_CATEGORY_LOW);
            mMovingView.setFrameContentVelocity(1f);
            mMovingView.invalidate();
            runAfterDraw(() -> {
                assertEquals(FRAME_RATE_CATEGORY_LOW,
                        mViewRoot.getLastPreferredFrameRateCategory());
                assertEquals(60f, mViewRoot.getLastPreferredFrameRate());
            });
        });
        waitForAfterDraw();
    }

    private void runAfterDraw(@NonNull Runnable runnable) {
        Handler handler = new Handler(Looper.getMainLooper());
        mAfterDrawLatch = new CountDownLatch(1);
+72 −61

File changed.

Preview size limit exceeded, changes collapsed.