Merge "Improve performance of VRR" into main
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index c66abe8..5466bf5 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -889,11 +889,11 @@
* @hide
*/
@Override
- protected int calculateFrameRateCategory(int width, int height) {
+ protected int calculateFrameRateCategory() {
if (mMinusTwoFrameIntervalMillis > 15 && mMinusOneFrameIntervalMillis > 15) {
return FRAME_RATE_CATEGORY_NORMAL;
}
- return super.calculateFrameRateCategory(width, height);
+ return super.calculateFrameRateCategory();
}
@UnsupportedAppUsage
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 736e815..b6df1bb 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5695,17 +5695,10 @@
private ViewTranslationResponse mViewTranslationResponse;
/**
- * Threshold size for something to be considered a small area update (in DP).
- * This is the dimension for both width and height.
+ * The multiplier for mAttachInfo.mSmallSizePixels to consider a View to be small
+ * if both dimensions are smaller than this.
*/
- private static final float FRAME_RATE_SMALL_SIZE_THRESHOLD = 40f;
-
- /**
- * Threshold size for something to be considered a small area update (in DP) if
- * it is narrow. This is for either width OR height. For example, a narrow progress
- * bar could be considered a small area.
- */
- private static final float FRAME_RATE_NARROW_THRESHOLD = 10f;
+ private static final int FRAME_RATE_SQUARE_SMALL_SIZE_MULTIPLIER = 4;
private static final long INFREQUENT_UPDATE_INTERVAL_MILLIS = 100;
private static final int INFREQUENT_UPDATE_COUNTS = 2;
@@ -5740,6 +5733,8 @@
@FlaggedApi(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
public static final float REQUESTED_FRAME_RATE_CATEGORY_HIGH = -4;
+ private int mSizeBasedFrameRateCategoryAndReason;
+
/**
* Simple constructor to use when creating a view from code.
*
@@ -23561,6 +23556,9 @@
return renderNode;
}
+ mLastFrameX = mLeft + mRenderNode.getTranslationX();
+ mLastFrameY = mTop + mRenderNode.getTranslationY();
+
if ((mPrivateFlags & PFLAG_DRAWING_CACHE_VALID) == 0
|| !renderNode.hasDisplayList()
|| (mRecreateDisplayList)) {
@@ -24724,8 +24722,6 @@
mPrivateFlags = (privateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN;
mFrameContentVelocity = -1;
- mLastFrameX = mLeft + mRenderNode.getTranslationX();
- mLastFrameY = mTop + mRenderNode.getTranslationY();
/*
* Draw traversal performs several drawing steps which must be executed
@@ -25474,6 +25470,21 @@
}
private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) {
+ if (mAttachInfo != null) {
+ int narrowSize = mAttachInfo.mSmallSizePixels;
+ int smallSize = narrowSize * FRAME_RATE_SQUARE_SMALL_SIZE_MULTIPLIER;
+ if (newWidth <= narrowSize || newHeight <= narrowSize
+ || (newWidth <= smallSize && newHeight <= smallSize)) {
+ int category = toolkitFrameRateBySizeReadOnly()
+ ? FRAME_RATE_CATEGORY_LOW : FRAME_RATE_CATEGORY_NORMAL;
+ mSizeBasedFrameRateCategoryAndReason = category | FRAME_RATE_CATEGORY_REASON_SMALL;
+ } else {
+ int category = toolkitFrameRateDefaultNormalReadOnly()
+ ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH;
+ mSizeBasedFrameRateCategoryAndReason = category | FRAME_RATE_CATEGORY_REASON_LARGE;
+ }
+ }
+
onSizeChanged(newWidth, newHeight, oldWidth, oldHeight);
if (mOverlay != null) {
mOverlay.getOverlayView().setRight(newWidth);
@@ -32040,6 +32051,13 @@
int mSensitiveViewsCount;
/**
+ * The size used for a View to be considered small for the purposes of using
+ * low refresh rate by default. This is the size in one direction, so a long, thin
+ * item like a progress bar can be compared to this.
+ */
+ final int mSmallSizePixels;
+
+ /**
* Creates a new set of attachment information with the specified
* events handler and thread.
*
@@ -32056,6 +32074,7 @@
mHandler = handler;
mRootCallbacks = effectPlayer;
mTreeObserver = new ViewTreeObserver(context);
+ mSmallSizePixels = (int) (context.getResources().getDisplayMetrics().density * 10);
}
void increaseSensitiveViewsCount() {
@@ -33784,28 +33803,10 @@
*
* @hide
*/
- protected int calculateFrameRateCategory(int width, int height) {
+ protected int calculateFrameRateCategory() {
if (mMinusTwoFrameIntervalMillis + mMinusOneFrameIntervalMillis
< INFREQUENT_UPDATE_INTERVAL_MILLIS) {
- DisplayMetrics displayMetrics = mResources.getDisplayMetrics();
- float density = displayMetrics.density;
- if (density == 0f) {
- density = 1f;
- }
- float widthDp = width / density;
- float heightDp = height / density;
- if (widthDp <= FRAME_RATE_NARROW_THRESHOLD
- || heightDp <= FRAME_RATE_NARROW_THRESHOLD
- || (widthDp <= FRAME_RATE_SMALL_SIZE_THRESHOLD
- && heightDp <= FRAME_RATE_SMALL_SIZE_THRESHOLD)) {
- int category = toolkitFrameRateBySizeReadOnly()
- ? FRAME_RATE_CATEGORY_LOW : FRAME_RATE_CATEGORY_NORMAL;
- return category | FRAME_RATE_CATEGORY_REASON_SMALL;
- } else {
- int category = toolkitFrameRateDefaultNormalReadOnly()
- ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH;
- return category | FRAME_RATE_CATEGORY_REASON_LARGE;
- }
+ return mSizeBasedFrameRateCategoryAndReason;
}
if (mInfrequentUpdateCount == INFREQUENT_UPDATE_COUNTS) {
@@ -33823,7 +33824,14 @@
if (viewVelocityApi()) {
float velocity = mFrameContentVelocity;
if (velocity < 0f) {
- velocity = calculateVelocity();
+ // 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.
+ RenderNode renderNode = mRenderNode;
+ float x = mLeft + renderNode.getTranslationX();
+ float y = mTop + renderNode.getTranslationY();
+
+ velocity = (!Float.isNaN(mLastFrameX) && (x != mLastFrameX || y != mLastFrameY))
+ ? 100_000f : 0f;
}
if (velocity > 0f) {
float frameRate = convertVelocityToFrameRate(velocity);
@@ -33831,43 +33839,55 @@
return;
}
}
- if (sToolkitMetricsForFrameRateDecisionFlagValue) {
- float sizePercentage = getSizePercentage();
- viewRootImpl.recordViewPercentage(sizePercentage);
- }
- int frameRateCategory;
- if (Float.isNaN(mPreferredFrameRate)) {
- frameRateCategory = calculateFrameRateCategory(width, height);
- } else if (mPreferredFrameRate < 0) {
- if (mPreferredFrameRate == REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE) {
- frameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE
- | FRAME_RATE_CATEGORY_REASON_REQUESTED;
- } else if (mPreferredFrameRate == REQUESTED_FRAME_RATE_CATEGORY_LOW) {
- frameRateCategory = FRAME_RATE_CATEGORY_LOW
- | FRAME_RATE_CATEGORY_REASON_REQUESTED;
- } else if (mPreferredFrameRate == REQUESTED_FRAME_RATE_CATEGORY_NORMAL) {
- frameRateCategory = FRAME_RATE_CATEGORY_NORMAL
- | FRAME_RATE_CATEGORY_REASON_REQUESTED;
- } else if (mPreferredFrameRate == REQUESTED_FRAME_RATE_CATEGORY_HIGH) {
- frameRateCategory = FRAME_RATE_CATEGORY_HIGH
- | FRAME_RATE_CATEGORY_REASON_REQUESTED;
- } else {
- // invalid frame rate, use default
- int category = toolkitFrameRateDefaultNormalReadOnly()
- ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH;
- frameRateCategory = category
- | FRAME_RATE_CATEGORY_REASON_INVALID;
+ if (!willNotDraw()) {
+ if (sToolkitMetricsForFrameRateDecisionFlagValue) {
+ float sizePercentage = getSizePercentage();
+ viewRootImpl.recordViewPercentage(sizePercentage);
}
- } else {
- viewRootImpl.votePreferredFrameRate(mPreferredFrameRate,
- mFrameRateCompatibility);
- return;
- }
- int category = frameRateCategory & ~FRAME_RATE_CATEGORY_REASON_MASK;
- int reason = frameRateCategory & FRAME_RATE_CATEGORY_REASON_MASK;
- viewRootImpl.votePreferredFrameRateCategory(category, reason, this);
- mLastFrameRateCategory = frameRateCategory;
+ int frameRateCategory;
+ if (Float.isNaN(mPreferredFrameRate)) {
+ if (mMinusTwoFrameIntervalMillis + mMinusOneFrameIntervalMillis
+ < INFREQUENT_UPDATE_INTERVAL_MILLIS && mAttachInfo != null) {
+ frameRateCategory = mSizeBasedFrameRateCategoryAndReason;
+ } else if (mInfrequentUpdateCount == INFREQUENT_UPDATE_COUNTS) {
+ frameRateCategory =
+ FRAME_RATE_CATEGORY_NORMAL
+ | FRAME_RATE_CATEGORY_REASON_INTERMITTENT;
+ } else {
+ frameRateCategory = mLastFrameRateCategory;
+ }
+ } else if (mPreferredFrameRate < 0) {
+ if (mPreferredFrameRate == REQUESTED_FRAME_RATE_CATEGORY_NO_PREFERENCE) {
+ frameRateCategory = FRAME_RATE_CATEGORY_NO_PREFERENCE
+ | FRAME_RATE_CATEGORY_REASON_REQUESTED;
+ } else if (mPreferredFrameRate == REQUESTED_FRAME_RATE_CATEGORY_LOW) {
+ frameRateCategory = FRAME_RATE_CATEGORY_LOW
+ | FRAME_RATE_CATEGORY_REASON_REQUESTED;
+ } else if (mPreferredFrameRate == REQUESTED_FRAME_RATE_CATEGORY_NORMAL) {
+ frameRateCategory = FRAME_RATE_CATEGORY_NORMAL
+ | FRAME_RATE_CATEGORY_REASON_REQUESTED;
+ } else if (mPreferredFrameRate == REQUESTED_FRAME_RATE_CATEGORY_HIGH) {
+ frameRateCategory = FRAME_RATE_CATEGORY_HIGH
+ | FRAME_RATE_CATEGORY_REASON_REQUESTED;
+ } else {
+ // invalid frame rate, use default
+ int category = toolkitFrameRateDefaultNormalReadOnly()
+ ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH;
+ frameRateCategory = category
+ | FRAME_RATE_CATEGORY_REASON_INVALID;
+ }
+ } else {
+ viewRootImpl.votePreferredFrameRate(mPreferredFrameRate,
+ mFrameRateCompatibility);
+ return;
+ }
+
+ int category = frameRateCategory & ~FRAME_RATE_CATEGORY_REASON_MASK;
+ int reason = frameRateCategory & FRAME_RATE_CATEGORY_REASON_MASK;
+ viewRootImpl.votePreferredFrameRateCategory(category, reason, this);
+ mLastFrameRateCategory = frameRateCategory;
+ }
}
}
@@ -33878,16 +33898,6 @@
return Math.min(140f, 60f + (10f * (float) Math.floor(velocityDps / 300f)));
}
- private float calculateVelocity() {
- // 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.
- float x = mLeft + mRenderNode.getTranslationX();
- float y = mTop + mRenderNode.getTranslationY();
-
- return (!Float.isNaN(mLastFrameX) && (x != mLastFrameX || y != mLastFrameY))
- ? 100_000f : 0f;
- }
-
/**
* Set the current velocity of the View, we only track positive value.
* We will use the velocity information to adjust the frame rate when applicable.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index eb9be18..dd548c6 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -12626,12 +12626,11 @@
}
mHasInvalidation = true;
checkIdleness();
- if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)
- && mPreferredFrameRateCategory != oldCategory
+ if (mPreferredFrameRateCategory != oldCategory
&& mPreferredFrameRateCategory == frameRateCategory
) {
mFrameRateCategoryChangeReason = reason;
- mFrameRateCategoryView = view.getClass().getSimpleName();
+ mFrameRateCategoryView = view == null ? "null" : view.getClass().getSimpleName();
}
}
@@ -12791,7 +12790,6 @@
// uncomment this when we are ready for enabling dVRR
// return sToolkitSetFrameRateReadOnlyFlagValue && isFrameRatePowerSavingsBalanced();
return false;
-
}
private void checkIdleness() {
diff --git a/core/tests/coretests/src/android/view/ViewFrameRateTest.java b/core/tests/coretests/src/android/view/ViewFrameRateTest.java
index 226629e..dcdb8b0 100644
--- a/core/tests/coretests/src/android/view/ViewFrameRateTest.java
+++ b/core/tests/coretests/src/android/view/ViewFrameRateTest.java
@@ -19,7 +19,6 @@
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.flags.Flags.FLAG_TOOLKIT_FRAME_RATE_DEFAULT_NORMAL_READ_ONLY;
import static android.view.flags.Flags.FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY;
import static android.view.flags.Flags.FLAG_VIEW_VELOCITY_API;
import static android.view.flags.Flags.toolkitFrameRateBySizeReadOnly;
@@ -137,8 +136,8 @@
mActivityRule.runOnUiThread(() -> {
float density = mActivity.getResources().getDisplayMetrics().density;
ViewGroup.LayoutParams layoutParams = mMovingView.getLayoutParams();
- layoutParams.height = (int) (40 * density);
- layoutParams.width = (int) (40 * density);
+ layoutParams.height = 4 * ((int) (10 * density));
+ layoutParams.width = 4 * ((int) (10 * density));
mMovingView.setLayoutParams(layoutParams);
mMovingView.getViewTreeObserver().addOnDrawListener(drawLatch1::countDown);
});
@@ -212,8 +211,8 @@
mActivityRule.runOnUiThread(() -> {
float density = mActivity.getResources().getDisplayMetrics().density;
ViewGroup.LayoutParams layoutParams = mMovingView.getLayoutParams();
- layoutParams.height = (int) (40 * density);
- layoutParams.width = (int) Math.ceil(41 * density);
+ layoutParams.height = 4 * ((int) (10 * density));
+ layoutParams.width = 4 * ((int) Math.ceil(10 * density)) + 1;
mMovingView.setLayoutParams(layoutParams);
mMovingView.getViewTreeObserver().addOnDrawListener(drawLatch1::countDown);
});
@@ -237,8 +236,8 @@
mActivityRule.runOnUiThread(() -> {
float density = mActivity.getResources().getDisplayMetrics().density;
ViewGroup.LayoutParams layoutParams = mMovingView.getLayoutParams();
- layoutParams.height = (int) Math.ceil(41 * density);
- layoutParams.width = (int) (40 * density);
+ layoutParams.height = 4 * ((int) Math.ceil(10 * density)) + 1;
+ layoutParams.width = 4 * ((int) (10 * density));
mMovingView.setLayoutParams(layoutParams);
mMovingView.getViewTreeObserver().addOnDrawListener(drawLatch1::countDown);
});
@@ -256,13 +255,14 @@
}
@Test
- @RequiresFlagsEnabled({FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY,
- FLAG_TOOLKIT_FRAME_RATE_DEFAULT_NORMAL_READ_ONLY})
+ @RequiresFlagsEnabled(FLAG_TOOLKIT_SET_FRAME_RATE_READ_ONLY)
public void defaultNormal() throws Throwable {
waitForFrameRateCategoryToSettle();
mActivityRule.runOnUiThread(() -> {
mMovingView.invalidate();
- assertEquals(FRAME_RATE_CATEGORY_NORMAL,
+ int expected = toolkitFrameRateDefaultNormalReadOnly()
+ ? FRAME_RATE_CATEGORY_NORMAL : FRAME_RATE_CATEGORY_HIGH;
+ assertEquals(expected,
mViewRoot.getPreferredFrameRateCategory());
});
}
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
index d95a039..a034f3b 100644
--- a/core/tests/coretests/src/android/view/ViewRootImplTest.java
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -667,7 +667,7 @@
}
/**
- * Test how values of the frame rate cateogry are aggregated.
+ * Test how values of the frame rate category are aggregated.
* It should take the max value among all of the voted categories per frame.
*/
@Test