From 41ffa8dd060015434131a6d4c2d248effe899202 Mon Sep 17 00:00:00 2001 From: Marin Shalamanov Date: Tue, 13 Oct 2020 12:35:20 +0200 Subject: [PATCH] Add shouldBeSeamless param to Surface.setFrameRate This CL adds a new parameter shouldBeSeamless to the existing setFrameRate APIs. This parameter indicates whether the desired refresh rate should be achieved only seamlessly or also switches with visual interruptions for the user are allowed. The default value of the new parameter is "true". Test: atest SetFrameRateTest Test: atest RefreshRateConfigsTest Test: atest libsurfaceflinger_unittest Bug: 161776961 Change-Id: Ic2446d278e4f57fe507d30a0a18ef7b85909da4b --- core/api/current.txt | 2 ++ core/java/android/view/Surface.java | 26 ++++++++++++++++--- core/java/android/view/SurfaceControl.java | 29 +++++++++++++++++++--- core/jni/android_view_Surface.cpp | 7 +++--- core/jni/android_view_SurfaceControl.cpp | 7 +++--- native/android/libandroid.map.txt | 1 + native/android/surface_control.cpp | 11 +++++++- 7 files changed, 68 insertions(+), 15 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index 629bfe9fa269a..ba52ccae153d8 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -52173,6 +52173,7 @@ package android.view { method public android.graphics.Canvas lockHardwareCanvas(); method public void readFromParcel(android.os.Parcel); method public void release(); + method public void setFrameRate(@FloatRange(from=0.0) float, int, boolean); method public void setFrameRate(@FloatRange(from=0.0) float, int); method @Deprecated public void unlockCanvas(android.graphics.Canvas); method public void unlockCanvasAndPost(android.graphics.Canvas); @@ -52220,6 +52221,7 @@ package android.view { method @NonNull public android.view.SurfaceControl.Transaction setAlpha(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0, to=1.0) float); method @NonNull public android.view.SurfaceControl.Transaction setBufferSize(@NonNull android.view.SurfaceControl, @IntRange(from=0) int, @IntRange(from=0) int); method @NonNull public android.view.SurfaceControl.Transaction setFrameRate(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0) float, int); + method @NonNull public android.view.SurfaceControl.Transaction setFrameRate(@NonNull android.view.SurfaceControl, @FloatRange(from=0.0) float, int, boolean); method @NonNull public android.view.SurfaceControl.Transaction setGeometry(@NonNull android.view.SurfaceControl, @Nullable android.graphics.Rect, @Nullable android.graphics.Rect, int); method @NonNull public android.view.SurfaceControl.Transaction setLayer(@NonNull android.view.SurfaceControl, @IntRange(from=java.lang.Integer.MIN_VALUE, to=java.lang.Integer.MAX_VALUE) int); method @NonNull public android.view.SurfaceControl.Transaction setVisibility(@NonNull android.view.SurfaceControl, boolean); diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 5b79174a6cd81..a2777fe985d50 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -97,7 +97,7 @@ public class Surface implements Parcelable { private static native int nativeSetAutoRefreshEnabled(long nativeObject, boolean enabled); private static native int nativeSetFrameRate( - long nativeObject, float frameRate, int compatibility); + long nativeObject, float frameRate, int compatibility, boolean shouldBeSeamless); public static final @android.annotation.NonNull Parcelable.Creator CREATOR = new Parcelable.Creator() { @@ -915,13 +915,20 @@ public class Surface implements Parcelable { * compatibility value may influence the system's choice of display frame rate. See * the FRAME_RATE_COMPATIBILITY_* values for more info. * + * @param shouldBeSeamless Whether display refresh rate transitions should be seamless. A + * seamless transition is one that doesn't have any visual interruptions, such as a black + * screen for a second or two. True indicates that any frame rate changes caused by this + * request should be seamless. False indicates that non-seamless refresh rates are also + * acceptable. + * * @throws IllegalArgumentException If frameRate or compatibility are invalid. */ - public void setFrameRate( - @FloatRange(from = 0.0) float frameRate, @FrameRateCompatibility int compatibility) { + public void setFrameRate(@FloatRange(from = 0.0) float frameRate, + @FrameRateCompatibility int compatibility, boolean shouldBeSeamless) { synchronized (mLock) { checkNotReleasedLocked(); - int error = nativeSetFrameRate(mNativeObject, frameRate, compatibility); + int error = nativeSetFrameRate(mNativeObject, frameRate, compatibility, + shouldBeSeamless); if (error == -EINVAL) { throw new IllegalArgumentException("Invalid argument to Surface.setFrameRate()"); } else if (error != 0) { @@ -930,6 +937,17 @@ public class Surface implements Parcelable { } } + /** + * Sets the intended frame rate for this surface. Any switching of refresh rates is + * most probably going to be seamless. + * + * @see #setFrameRate(float, int, boolean) + */ + public void setFrameRate( + @FloatRange(from = 0.0) float frameRate, @FrameRateCompatibility int compatibility) { + setFrameRate(frameRate, compatibility, /* shouldBeSeamless = */ true); + } + /** * Exception thrown when a Canvas couldn't be locked with {@link Surface#lockCanvas}, or * when a SurfaceTexture could not successfully be allocated. diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index af31b817d5202..d7ee6ad151669 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -212,8 +212,8 @@ public final class SurfaceControl implements Parcelable { private static native void nativeSetGlobalShadowSettings(@Size(4) float[] ambientColor, @Size(4) float[] spotColor, float lightPosY, float lightPosZ, float lightRadius); - private static native void nativeSetFrameRate( - long transactionObj, long nativeObject, float frameRate, int compatibility); + private static native void nativeSetFrameRate(long transactionObj, long nativeObject, + float frameRate, int compatibility, boolean shouldBeSeamless); private static native long nativeGetHandle(long nativeObject); private static native long nativeAcquireFrameRateFlexibilityToken(); @@ -3255,6 +3255,19 @@ public final class SurfaceControl implements Parcelable { return this; } + /** + * Sets the intended frame rate for this surface. Any switching of refresh rates is + * most probably going to be seamless. + * + * @see #setFrameRate(SurfaceControl, float, int, boolean) + */ + @NonNull + public Transaction setFrameRate(@NonNull SurfaceControl sc, + @FloatRange(from = 0.0) float frameRate, + @Surface.FrameRateCompatibility int compatibility) { + return setFrameRate(sc, frameRate, compatibility, /*shouldBeSeamless*/ true); + } + /** * Sets the intended frame rate for the surface {@link SurfaceControl}. *

@@ -3275,14 +3288,22 @@ public final class SurfaceControl implements Parcelable { * @param compatibility The frame rate compatibility of this surface. The compatibility * value may influence the system's choice of display frame rate. See * the Surface.FRAME_RATE_COMPATIBILITY_* values for more info. + * @param shouldBeSeamless Whether display refresh rate transitions should be seamless. A + * seamless transition is one that doesn't have any visual + * interruptions, such as a black screen for a second or two. True + * indicates that any frame rate changes caused by this request + * should be seamless. False indicates that non-seamless refresh + * rates are also acceptable. * @return This transaction object. */ @NonNull public Transaction setFrameRate(@NonNull SurfaceControl sc, @FloatRange(from = 0.0) float frameRate, - @Surface.FrameRateCompatibility int compatibility) { + @Surface.FrameRateCompatibility int compatibility, + boolean shouldBeSeamless) { checkPreconditions(sc); - nativeSetFrameRate(mNativeObject, sc.mNativeObject, frameRate, compatibility); + nativeSetFrameRate(mNativeObject, sc.mNativeObject, frameRate, compatibility, + shouldBeSeamless); return this; } diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index 3a1ccd9de79e7..5b29f0bb89326 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -438,14 +438,15 @@ static jint nativeSetAutoRefreshEnabled(JNIEnv* env, jclass clazz, jlong nativeO } static jint nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat frameRate, - jint compatibility) { + jint compatibility, jboolean shouldBeSeamless) { Surface* surface = reinterpret_cast(nativeObject); ANativeWindow* anw = static_cast(surface); // Our compatibility is a Surface.FRAME_RATE_COMPATIBILITY_* value, and // NATIVE_WINDOW_SET_FRAME_RATE takes an // ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value. The values are identical // though, so no need to explicitly convert. - return anw->perform(surface, NATIVE_WINDOW_SET_FRAME_RATE, float(frameRate), compatibility); + return anw->perform(surface, NATIVE_WINDOW_SET_FRAME_RATE, double(frameRate), compatibility, + int(shouldBeSeamless)); } // ---------------------------------------------------------------------------- @@ -474,7 +475,7 @@ static const JNINativeMethod gSurfaceMethods[] = { (void*)nativeAttachAndQueueBufferWithColorSpace}, {"nativeSetSharedBufferModeEnabled", "(JZ)I", (void*)nativeSetSharedBufferModeEnabled}, {"nativeSetAutoRefreshEnabled", "(JZ)I", (void*)nativeSetAutoRefreshEnabled}, - {"nativeSetFrameRate", "(JFI)I", (void*)nativeSetFrameRate}, + {"nativeSetFrameRate", "(JFIZ)I", (void*)nativeSetFrameRate}, {"nativeGetFromBlastBufferQueue", "(JJ)J", (void*)nativeGetFromBlastBufferQueue}, }; diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index f1ec85a8570fb..6ec656c167904 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -738,14 +738,15 @@ static void nativeSetShadowRadius(JNIEnv* env, jclass clazz, jlong transactionOb } static void nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject, - jfloat frameRate, jint compatibility) { + jfloat frameRate, jint compatibility, jboolean shouldBeSeamless) { auto transaction = reinterpret_cast(transactionObj); const auto ctrl = reinterpret_cast(nativeObject); // Our compatibility is a Surface.FRAME_RATE_COMPATIBILITY_* value, and // Transaction::setFrameRate() takes an ANATIVEWINDOW_FRAME_RATE_COMPATIBILITY_* value. The // values are identical though, so no need to convert anything. - transaction->setFrameRate(ctrl, frameRate, static_cast(compatibility)); + transaction->setFrameRate(ctrl, frameRate, static_cast(compatibility), + bool(shouldBeSeamless)); } static jlong nativeAcquireFrameRateFlexibilityToken(JNIEnv* env, jclass clazz) { @@ -1668,7 +1669,7 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeSetBlurRegions }, {"nativeSetShadowRadius", "(JJF)V", (void*)nativeSetShadowRadius }, - {"nativeSetFrameRate", "(JJFI)V", + {"nativeSetFrameRate", "(JJFIZ)V", (void*)nativeSetFrameRate }, {"nativeAcquireFrameRateFlexibilityToken", "()J", (void*)nativeAcquireFrameRateFlexibilityToken }, diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index 3027eac3a2248..d134b37c6b706 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -247,6 +247,7 @@ LIBANDROID { ASurfaceTransaction_setDamageRegion; # introduced=29 ASurfaceTransaction_setDesiredPresentTime; # introduced=29 ASurfaceTransaction_setFrameRate; # introduced=30 + ASurfaceTransaction_setFrameRateWithSeamlessness; # introduced=31 ASurfaceTransaction_setGeometry; # introduced=29 ASurfaceTransaction_setHdrMetadata_cta861_3; # introduced=29 ASurfaceTransaction_setHdrMetadata_smpte2086; # introduced=29 diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp index c503721319fb1..189be800e0189 100644 --- a/native/android/surface_control.cpp +++ b/native/android/surface_control.cpp @@ -560,9 +560,18 @@ void ASurfaceTransaction_setColor(ASurfaceTransaction* aSurfaceTransaction, void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl, float frameRate, int8_t compatibility) { + ASurfaceTransaction_setFrameRateWithSeamlessness(aSurfaceTransaction, aSurfaceControl, + frameRate, compatibility, + /*shouldBeSeamless*/ true); +} + +void ASurfaceTransaction_setFrameRateWithSeamlessness(ASurfaceTransaction* aSurfaceTransaction, + ASurfaceControl* aSurfaceControl, + float frameRate, int8_t compatibility, + bool shouldBeSeamless) { CHECK_NOT_NULL(aSurfaceTransaction); CHECK_NOT_NULL(aSurfaceControl); Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction); sp surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl); - transaction->setFrameRate(surfaceControl, frameRate, compatibility); + transaction->setFrameRate(surfaceControl, frameRate, compatibility, shouldBeSeamless); }