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

Commit c384c3ec authored by George Mount's avatar George Mount Committed by Android (Google) Code Review
Browse files

Merge "Move intermittent calculation to ViewRootImpl from View" into main

parents 1c3e90e2 9adead25
Loading
Loading
Loading
Loading
+23 −1
Original line number Diff line number Diff line
@@ -202,6 +202,14 @@ public class TextureView extends View {
    // Set by native code, do not write!
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
    private long mNativeWindow;
    // Used for VRR detecting "normal" frame rate rather than "high". This is the previous
    // interval for drawing. This can be removed when NORMAL is the default rate for Views.
    // (b/329156944)
    private long mMinusTwoFrameIntervalMillis = 0;
    // Used for VRR detecting "normal" frame rate rather than "high". This is the last
    // frame time for drawing. This can be removed when NORMAL is the default rate for Views.
    // (b/329156944)
    private long mLastFrameTimeMillis = 0;

    /**
     * Creates a new TextureView.
@@ -890,12 +898,26 @@ public class TextureView extends View {
     */
    @Override
    protected int calculateFrameRateCategory() {
        if (mMinusTwoFrameIntervalMillis > 15 && mMinusOneFrameIntervalMillis > 15) {
        long now = getDrawingTime();
        // This isn't necessary when the default frame rate is NORMAL (b/329156944)
        if (mMinusTwoFrameIntervalMillis > 15 && (now - mLastFrameTimeMillis) > 15) {
            return FRAME_RATE_CATEGORY_NORMAL;
        }
        return super.calculateFrameRateCategory();
    }

    /**
     * @hide
     */
    @Override
    protected void votePreferredFrameRate() {
        super.votePreferredFrameRate();
        // This isn't necessary when the default frame rate is NORMAL (b/329156944)
        long now = getDrawingTime();
        mMinusTwoFrameIntervalMillis = now - mLastFrameTimeMillis;
        mLastFrameTimeMillis = now;
    }

    @UnsupportedAppUsage
    private final SurfaceTexture.OnFrameAvailableListener mUpdateListener =
            surfaceTexture -> {
+95 −115
Original line number Diff line number Diff line
@@ -1133,7 +1133,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    private static final int FOCUSABLE_MASK = 0x00000011;
    /**
     * This view will adjust its padding to fit sytem windows (e.g. status bar)
     * This view will adjust its padding to fit system windows (e.g. status bar)
     */
    private static final int FITS_SYSTEM_WINDOWS = 0x00000002;
@@ -5764,23 +5764,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    static final float MAX_FRAME_RATE = 140;
    private static final int INFREQUENT_UPDATE_INTERVAL_MILLIS = 100;
    private static final int INFREQUENT_UPDATE_COUNTS = 2;
    // The preferred frame rate of the view that is mainly used for
    // touch boosting, view velocity handling, and TextureView.
    private float mPreferredFrameRate = REQUESTED_FRAME_RATE_CATEGORY_DEFAULT;
    private int mInfrequentUpdateCount = 0;
    private long mLastUpdateTimeMillis = 0;
    /**
     * @hide
     */
    protected int mMinusOneFrameIntervalMillis = 0;
    /**
     * @hide
     */
    protected int mMinusTwoFrameIntervalMillis = 0;
    private int mLastFrameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE;
    @FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
@@ -23651,7 +23638,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        if (sToolkitSetFrameRateReadOnlyFlagValue
                && sToolkitFrameRateViewEnablingReadOnlyFlagValue) {
            votePreferredFrameRate();
            updateInfrequentCount();
        }
        mPrivateFlags4 = (mPrivateFlags4 & ~PFLAG4_HAS_MOVED) | PFLAG4_HAS_DRAWN;
@@ -33903,15 +33889,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     * @hide
     */
    protected int calculateFrameRateCategory() {
        if (mMinusTwoFrameIntervalMillis + mMinusOneFrameIntervalMillis
                < INFREQUENT_UPDATE_INTERVAL_MILLIS) {
            return mSizeBasedFrameRateCategoryAndReason;
        }
        if (mInfrequentUpdateCount == INFREQUENT_UPDATE_COUNTS) {
            return FRAME_RATE_CATEGORY_NORMAL | FRAME_RATE_CATEGORY_REASON_INTERMITTENT;
        int category;
        switch (getViewRootImpl().intermittentUpdateState()) {
            case ViewRootImpl.INTERMITTENT_STATE_INTERMITTENT ->
                    category = FRAME_RATE_CATEGORY_NORMAL | FRAME_RATE_CATEGORY_REASON_INTERMITTENT;
            case ViewRootImpl.INTERMITTENT_STATE_NOT_INTERMITTENT ->
                    category = mSizeBasedFrameRateCategoryAndReason;
            default -> category = mLastFrameRateCategory;
        }
        return mLastFrameRateCategory;
        return category;
    }
    /**
@@ -33922,15 +33908,35 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
    protected void votePreferredFrameRate() {
        // use toolkitSetFrameRate flag to gate the change
        ViewRootImpl viewRootImpl = getViewRootImpl();
        int width = mRight - mLeft;
        int height = mBottom - mTop;
        if (viewRootImpl != null && (width != 0 && height != 0)) {
            if (viewRootImpl.shouldCheckFrameRate(mPreferredFrameRate > 0f)) {
        if (viewRootImpl == null) {
            return; // can't vote if not connected
        }
        float velocity = mFrameContentVelocity;
        float frameRate = mPreferredFrameRate;
        ViewParent parent = mParent;
        if (velocity <= 0 && Float.isNaN(frameRate)) {
            // The most common case is when nothing is set, so this special case is called
            // often.
            if (mAttachInfo.mViewVelocityApi
                    && (mPrivateFlags4 & (PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN)) == (
                    PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN)
                    && viewRootImpl.shouldCheckFrameRate(false)
                    && parent instanceof View
                    && ((View) parent).mFrameContentVelocity <= 0) {
                viewRootImpl.votePreferredFrameRate(MAX_FRAME_RATE, FRAME_RATE_COMPATIBILITY_GTE);
            }
            if (!willNotDraw() && viewRootImpl.shouldCheckFrameRateCategory()) {
                int frameRateCategory = calculateFrameRateCategory();
                int category = frameRateCategory & ~FRAME_RATE_CATEGORY_REASON_MASK;
                int reason = frameRateCategory & FRAME_RATE_CATEGORY_REASON_MASK;
                viewRootImpl.votePreferredFrameRateCategory(category, reason, this);
                mLastFrameRateCategory = frameRateCategory;
            }
            return;
        }
        if (viewRootImpl.shouldCheckFrameRate(frameRate > 0f)) {
            float velocityFrameRate = 0f;
            if (mAttachInfo.mViewVelocityApi) {
                    float velocity = mFrameContentVelocity;
                if (velocity < 0f
                        && (mPrivateFlags4 & (PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN)) == (
                        PFLAG4_HAS_MOVED | PFLAG4_HAS_DRAWN)
@@ -33944,27 +33950,31 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
                    velocityFrameRate = convertVelocityToFrameRate(velocity);
                }
            }
                if (velocityFrameRate > 0f || mPreferredFrameRate > 0f) {
                    int compatibility = FRAME_RATE_COMPATIBILITY_GTE;
                    float frameRate = velocityFrameRate;
                    if (mPreferredFrameRate > velocityFrameRate) {
            if (velocityFrameRate > 0f || frameRate > 0f) {
                int compatibility;
                if (frameRate >= velocityFrameRate) {
                    compatibility = FRAME_RATE_COMPATIBILITY_FIXED_SOURCE;
                        frameRate = mPreferredFrameRate;
                } else {
                    compatibility = FRAME_RATE_COMPATIBILITY_GTE;
                    frameRate = velocityFrameRate;
                }
                viewRootImpl.votePreferredFrameRate(frameRate, compatibility);
            }
        }
            if (!willNotDraw() && isDirty() && viewRootImpl.shouldCheckFrameRateCategory()) {
        if (!willNotDraw() && viewRootImpl.shouldCheckFrameRateCategory()) {
            if (sToolkitMetricsForFrameRateDecisionFlagValue) {
                int width = mRight - mLeft;
                int height = mBottom - mTop;
                float sizePercentage = width * height / mAttachInfo.mDisplayPixelCount;
                viewRootImpl.recordViewPercentage(sizePercentage);
            }
            int frameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE;
                if (Float.isNaN(mPreferredFrameRate)) {
            if (Float.isNaN(frameRate)) {
                frameRateCategory = calculateFrameRateCategory();
                } else if (mPreferredFrameRate < 0) {
                    switch ((int) mPreferredFrameRate) {
            } else if (frameRate < 0) {
                switch ((int) frameRate) {
                    case (int) REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE ->
                            frameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE
                                    | FRAME_RATE_CATEGORY_REASON_REQUESTED;
@@ -33993,7 +34003,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
            mLastFrameRateCategory = frameRateCategory;
        }
    }
    }
    private float convertVelocityToFrameRate(float velocityPps) {
        float density = mAttachInfo.mDensity;
@@ -34074,33 +34083,4 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
        }
        return 0;
    }
    /**
     * This function is mainly used for migrating infrequent layer logic
     * from SurfaceFlinger to Toolkit.
     * The infrequent layer logic includes:
     * - NORMAL for infrequent update: FT2-FT1 > 100 && FT3-FT2 > 100.
     * - HIGH/NORMAL based on size for frequent update: (FT3-FT2) + (FT2 - FT1) < 100.
     * - otherwise, use the previous category value.
     */
    private void updateInfrequentCount() {
        if (!willNotDraw()) {
            long currentTimeMillis = getDrawingTime();
            int timeIntervalMillis =
                    (int) Math.min(Integer.MAX_VALUE, currentTimeMillis - mLastUpdateTimeMillis);
            mMinusTwoFrameIntervalMillis = mMinusOneFrameIntervalMillis;
            mMinusOneFrameIntervalMillis = timeIntervalMillis;
            mLastUpdateTimeMillis = currentTimeMillis;
            if (mMinusTwoFrameIntervalMillis >= 30 && timeIntervalMillis < 2) {
                return;
            }
            if (timeIntervalMillis >= INFREQUENT_UPDATE_INTERVAL_MILLIS) {
                mInfrequentUpdateCount = mInfrequentUpdateCount == INFREQUENT_UPDATE_COUNTS
                        ? mInfrequentUpdateCount : mInfrequentUpdateCount + 1;
            } else {
                mInfrequentUpdateCount = 0;
            }
        }
    }
}
+110 −29
Original line number Diff line number Diff line
@@ -392,6 +392,26 @@ public final class ViewRootImpl implements ViewParent,
    private static final int UNSET_SYNC_ID = -1;
    private static final int INFREQUENT_UPDATE_INTERVAL_MILLIS = 100;
    private static final int INFREQUENT_UPDATE_COUNTS = 2;
    /**
     * The {@link #intermittentUpdateState()} value when the ViewRootImpl isn't intermittent.
     */
    public static final int INTERMITTENT_STATE_NOT_INTERMITTENT = 1;
    /**
     * The {@link #intermittentUpdateState()} value when the ViewRootImpl is transitioning either
     * to or from intermittent to not intermittent. This indicates that the frame rate shouldn't
     * change.
     */
    public static final int INTERMITTENT_STATE_IN_TRANSITION = -1;
    /**
     * The {@link #intermittentUpdateState()} value when the ViewRootImpl is intermittent.
     */
    public static final int INTERMITTENT_STATE_INTERMITTENT = 0;
    /**
     * Minimum time to wait before reporting changes to keep clear areas.
     */
@@ -623,6 +643,15 @@ public final class ViewRootImpl implements ViewParent,
    // Is the stylus pointer icon enabled
    private final boolean mIsStylusPointerIconEnabled;
    // VRR check for number of infrequent updates
    private int mInfrequentUpdateCount = 0;
    // VRR time of last update
    private long mLastUpdateTimeMillis = 0;
    // VRR interval since the previous
    private int mMinusOneFrameIntervalMillis = 0;
    // VRR interval between the previous and the frame before
    private int mMinusTwoFrameIntervalMillis = 0;
    /**
     * Update the Choreographer's FrameInfo object with the timing information for the current
     * ViewRootImpl instance. Erase the data in the current ViewFrameInfo to prepare for the next
@@ -1068,6 +1097,7 @@ public final class ViewRootImpl implements ViewParent,
    // Used to check if there is a message in the message queue
    // for idleness handling.
    private boolean mHasIdledMessage = false;
    private boolean mDrawnThisFrame = false;
    // Used to check if there is a conflict between different frame rate voting.
    // Take 24 and 30 as an example, 24 is not a divisor of 30.
    // We consider there is a conflict.
@@ -4220,6 +4250,9 @@ 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.
        if (mDrawnThisFrame) {
            mDrawnThisFrame = false;
            updateInfrequentCount();
            setCategoryFromCategoryCounts();
            setPreferredFrameRate(mPreferredFrameRate);
            setPreferredFrameRateCategory(mPreferredFrameRateCategory);
@@ -4240,6 +4273,7 @@ public final class ViewRootImpl implements ViewParent,
            mIsFrameRateConflicted = false;
            mFrameRateCategoryChangeReason = FRAME_RATE_CATEGORY_REASON_UNKNOWN;
        }
    }
    private void createSyncIfNeeded() {
        // WMS requested sync already started or there's nothing needing to sync
@@ -12516,6 +12550,15 @@ public final class ViewRootImpl implements ViewParent,
     * Sets the mPreferredFrameRateCategory from the high, high_hint, normal, and low counts.
     */
    private void setCategoryFromCategoryCounts() {
        switch (mPreferredFrameRateCategory) {
            case FRAME_RATE_CATEGORY_LOW -> mFrameRateCategoryLowCount = FRAME_RATE_CATEGORY_COUNT;
            case FRAME_RATE_CATEGORY_NORMAL ->
                    mFrameRateCategoryNormalCount = FRAME_RATE_CATEGORY_COUNT;
            case FRAME_RATE_CATEGORY_HIGH_HINT ->
                    mFrameRateCategoryHighHintCount = FRAME_RATE_CATEGORY_COUNT;
            case FRAME_RATE_CATEGORY_HIGH ->
                    mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT;
        }
        if (mFrameRateCategoryHighCount > 0) {
            mPreferredFrameRateCategory = FRAME_RATE_CATEGORY_HIGH;
        } else if (mFrameRateCategoryHighHintCount > 0) {
@@ -12661,21 +12704,31 @@ public final class ViewRootImpl implements ViewParent,
     */
    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
    public void votePreferredFrameRateCategory(int frameRateCategory, int reason, View view) {
        switch (frameRateCategory) {
            case FRAME_RATE_CATEGORY_LOW -> mFrameRateCategoryLowCount = FRAME_RATE_CATEGORY_COUNT;
            case FRAME_RATE_CATEGORY_NORMAL ->
                    mFrameRateCategoryNormalCount = FRAME_RATE_CATEGORY_COUNT;
            case FRAME_RATE_CATEGORY_HIGH_HINT ->
                    mFrameRateCategoryHighHintCount = FRAME_RATE_CATEGORY_COUNT;
            case FRAME_RATE_CATEGORY_HIGH ->
                    mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT;
        }
        if (frameRateCategory > mPreferredFrameRateCategory) {
            mPreferredFrameRateCategory = frameRateCategory;
            mFrameRateCategoryChangeReason = reason;
            mFrameRateCategoryView = view == null ? "-" : view.getClass().getSimpleName();
//            mFrameRateCategoryView = view == null ? "-" : view.getClass().getSimpleName();
        }
        mHasInvalidation = true;
        mDrawnThisFrame = true;
    }
    /**
     * Returns {@link #INTERMITTENT_STATE_INTERMITTENT} when the ViewRootImpl has only been
     * updated intermittently, {@link #INTERMITTENT_STATE_NOT_INTERMITTENT} when it is
     * not updated intermittently, and {@link #INTERMITTENT_STATE_IN_TRANSITION} when it
     * is transitioning between {@link #INTERMITTENT_STATE_NOT_INTERMITTENT} and
     * {@link #INTERMITTENT_STATE_INTERMITTENT}.
     */
    int intermittentUpdateState() {
        if (mMinusOneFrameIntervalMillis + mMinusTwoFrameIntervalMillis
                < INFREQUENT_UPDATE_INTERVAL_MILLIS) {
            return INTERMITTENT_STATE_NOT_INTERMITTENT;
        }
        if (mInfrequentUpdateCount == INFREQUENT_UPDATE_COUNTS) {
            return INTERMITTENT_STATE_INTERMITTENT;
        }
        return INTERMITTENT_STATE_IN_TRANSITION;
    }
    /**
@@ -12730,6 +12783,8 @@ public final class ViewRootImpl implements ViewParent,
                mFrameRateCategoryHighCount = FRAME_RATE_CATEGORY_COUNT;
                mFrameRateCategoryChangeReason = FRAME_RATE_CATEGORY_REASON_VELOCITY;
                mFrameRateCategoryView = null;
                mHasInvalidation = true;
                mDrawnThisFrame = true;
                return;
            }
        }
@@ -12761,6 +12816,7 @@ public final class ViewRootImpl implements ViewParent,
        mPreferredFrameRate = nextFrameRate;
        mFrameRateCompatibility = nextFrameRateCompatibility;
        mHasInvalidation = true;
        mDrawnThisFrame = true;
    }
    /**
@@ -12894,4 +12950,29 @@ public final class ViewRootImpl implements ViewParent,
        mHandler.removeMessages(MSG_CHECK_INVALIDATION_IDLE);
        mHandler.removeMessages(MSG_FRAME_RATE_SETTING);
    }
    /**
     * This function is mainly used for migrating infrequent layer logic
     * from SurfaceFlinger to Toolkit.
     * The infrequent layer logic includes:
     * - NORMAL for infrequent update: FT2-FT1 > 100 && FT3-FT2 > 100.
     * - HIGH/NORMAL based on size for frequent update: (FT3-FT2) + (FT2 - FT1) < 100.
     * - otherwise, use the previous category value.
     */
    private void updateInfrequentCount() {
        long currentTimeMillis = mAttachInfo.mDrawingTime;
        int timeIntervalMillis =
                (int) Math.min(Integer.MAX_VALUE, currentTimeMillis - mLastUpdateTimeMillis);
        mMinusTwoFrameIntervalMillis = mMinusOneFrameIntervalMillis;
        mMinusOneFrameIntervalMillis = timeIntervalMillis;
        mLastUpdateTimeMillis = currentTimeMillis;
        if (timeIntervalMillis >= INFREQUENT_UPDATE_INTERVAL_MILLIS) {
            int infrequentUpdateCount = mInfrequentUpdateCount;
            mInfrequentUpdateCount = infrequentUpdateCount == INFREQUENT_UPDATE_COUNTS
                    ? infrequentUpdateCount : infrequentUpdateCount + 1;
        } else {
            mInfrequentUpdateCount = 0;
        }
    }
}