Add compatibility param to setFrameRate() api

Add a compatiblity param to the setFrameRate() api, so the system has
more info to decide the device frame rate when there are multiple
competing preferences.

I also changed the plumbing for setFrameRate() to go directly to surface
flinger, instead of through buffer queue. We're trying to avoid changes
to buffer queue code, to avoid disturbing the prebuilts.

Bug: 137287430

Test: Added new cts tests to verify behavior of the compatibility param.
      cts-tradefed run commandAndExit cts-dev --module CtsGraphicsTestCases --test android.graphics.cts.SetFrameRateTest

Test: /data/nativetest64/SurfaceFlinger_test/SurfaceFlinger_test --gtest_filter='SetFrameRateTest.*'

Change-Id: I9123afee2ba63d01ff35fb2b257a1ee0e4928ddd
This commit is contained in:
Steven Thomas
2020-01-31 18:50:02 -08:00
parent 0d8fea17d3
commit dd7bf2fea5
6 changed files with 72 additions and 26 deletions

View File

@@ -53250,11 +53250,13 @@ 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);
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);
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.view.Surface> CREATOR;
field public static final int FRAME_RATE_COMPATIBILITY_DEFAULT = 0; // 0x0
field public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1; // 0x1
field public static final int ROTATION_0 = 0; // 0x0
field public static final int ROTATION_180 = 2; // 0x2
field public static final int ROTATION_270 = 3; // 0x3
@@ -53294,7 +53296,7 @@ package android.view {
method @NonNull public android.view.SurfaceControl.Transaction reparent(@NonNull android.view.SurfaceControl, @Nullable android.view.SurfaceControl);
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);
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 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);

View File

@@ -16,6 +16,8 @@
package android.view;
import static android.system.OsConstants.EINVAL;
import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.NonNull;
@@ -89,7 +91,8 @@ public class Surface implements Parcelable {
private static native int nativeSetSharedBufferModeEnabled(long nativeObject, boolean enabled);
private static native int nativeSetAutoRefreshEnabled(long nativeObject, boolean enabled);
private static native int nativeSetFrameRate(long nativeObject, float frameRate);
private static native int nativeSetFrameRate(
long nativeObject, float frameRate, int compatibility);
public static final @android.annotation.NonNull Parcelable.Creator<Surface> CREATOR =
new Parcelable.Creator<Surface>() {
@@ -184,6 +187,28 @@ public class Surface implements Parcelable {
*/
public static final int ROTATION_270 = 3;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = {"FRAME_RATE_COMPATIBILITY_"},
value = {FRAME_RATE_COMPATIBILITY_DEFAULT, FRAME_RATE_COMPATIBILITY_FIXED_SOURCE})
public @interface FrameRateCompatibility {}
// From native_window.h. Keep these in sync.
/**
* There are no inherent restrictions on the frame rate of this surface.
*/
public static final int FRAME_RATE_COMPATIBILITY_DEFAULT = 0;
/**
* This surface is being used to display content with an inherently fixed frame rate,
* e.g. a video that has a specific frame rate. When the system selects a frame rate
* other than what the app requested, the app will need to do pull down or use some
* other technique to adapt to the system's frame rate. The user experience is likely
* to be worse (e.g. more frame stuttering) than it would be if the system had chosen
* the app's requested frame rate.
*/
public static final int FRAME_RATE_COMPATIBILITY_FIXED_SOURCE = 1;
/**
* Create an empty surface, which will later be filled in by readFromParcel().
* @hide
@@ -864,11 +889,23 @@ public class Surface implements Parcelable {
* called. The frameRate param does *not* need to be a valid refresh rate for this
* device's display - e.g., it's fine to pass 30fps to a device that can only run the
* display at 60fps.
*
* @param compatibility The frame rate compatibility of this surface. The
* compatibility value may influence the system's choice of display frame rate. See
* the FRAME_RATE_COMPATIBILITY_* values for more info.
*
* @throws IllegalArgumentException If frameRate or compatibility are invalid.
*/
public void setFrameRate(@FloatRange(from = 0.0) float frameRate) {
int error = nativeSetFrameRate(mNativeObject, frameRate);
if (error != 0) {
throw new RuntimeException("Failed to set frame rate on Surface");
public void setFrameRate(
@FloatRange(from = 0.0) float frameRate, @FrameRateCompatibility int compatibility) {
synchronized (mLock) {
checkNotReleasedLocked();
int error = nativeSetFrameRate(mNativeObject, frameRate, compatibility);
if (error == -EINVAL) {
throw new IllegalArgumentException("Invalid argument to Surface.setFrameRate()");
} else if (error != 0) {
throw new RuntimeException("Failed to set frame rate on Surface");
}
}
}

View File

@@ -213,7 +213,7 @@ public final class SurfaceControl implements Parcelable {
@Size(4) float[] spotColor, float lightPosY, float lightPosZ, float lightRadius);
private static native void nativeSetFrameRate(
long transactionObj, long nativeObject, float frameRate);
long transactionObj, long nativeObject, float frameRate, int compatibility);
private final CloseGuard mCloseGuard = CloseGuard.get();
private String mName;
@@ -2735,13 +2735,17 @@ public final class SurfaceControl implements Parcelable {
* isn't called. The frameRate param does *not* need to be a valid refresh
* rate for this device's display - e.g., it's fine to pass 30fps to a
* device that can only run the display at 60fps.
* @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.
* @return This transaction object.
*/
@NonNull
public Transaction setFrameRate(
@NonNull SurfaceControl sc, @FloatRange(from = 0.0) float frameRate) {
public Transaction setFrameRate(@NonNull SurfaceControl sc,
@FloatRange(from = 0.0) float frameRate,
@Surface.FrameRateCompatibility int compatibility) {
checkPreconditions(sc);
nativeSetFrameRate(mNativeObject, sc.mNativeObject, frameRate);
nativeSetFrameRate(mNativeObject, sc.mNativeObject, frameRate, compatibility);
return this;
}

View File

@@ -413,10 +413,15 @@ static jint nativeSetAutoRefreshEnabled(JNIEnv* env, jclass clazz, jlong nativeO
return anw->perform(surface, NATIVE_WINDOW_SET_AUTO_REFRESH, int(enabled));
}
static jint nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat frameRate) {
static jint nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat frameRate,
jint compatibility) {
Surface* surface = reinterpret_cast<Surface*>(nativeObject);
ANativeWindow* anw = static_cast<ANativeWindow*>(surface);
return anw->perform(surface, NATIVE_WINDOW_SET_FRAME_RATE, float(frameRate));
// 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);
}
// ----------------------------------------------------------------------------
@@ -453,7 +458,7 @@ static const JNINativeMethod gSurfaceMethods[] = {
(void*)nativeAttachAndQueueBufferWithColorSpace},
{"nativeSetSharedBufferModeEnabled", "(JZ)I", (void*)nativeSetSharedBufferModeEnabled},
{"nativeSetAutoRefreshEnabled", "(JZ)I", (void*)nativeSetAutoRefreshEnabled},
{"nativeSetFrameRate", "(JF)I", (void*)nativeSetFrameRate},
{"nativeSetFrameRate", "(JFI)I", (void*)nativeSetFrameRate},
};
int register_android_view_Surface(JNIEnv* env)

View File

@@ -593,11 +593,14 @@ static void nativeSetShadowRadius(JNIEnv* env, jclass clazz, jlong transactionOb
}
static void nativeSetFrameRate(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject,
jfloat frameRate) {
jfloat frameRate, jint compatibility) {
auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
const auto ctrl = reinterpret_cast<SurfaceControl*>(nativeObject);
transaction->setFrameRate(ctrl, frameRate);
// 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<int8_t>(compatibility));
}
static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) {
@@ -1410,7 +1413,7 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeSetLayerStack },
{"nativeSetShadowRadius", "(JJF)V",
(void*)nativeSetShadowRadius },
{"nativeSetFrameRate", "(JJF)V",
{"nativeSetFrameRate", "(JJFI)V",
(void*)nativeSetFrameRate },
{"nativeGetPhysicalDisplayIds", "()[J",
(void*)nativeGetPhysicalDisplayIds },

View File

@@ -547,16 +547,11 @@ void ASurfaceTransaction_setColor(ASurfaceTransaction* aSurfaceTransaction,
}
void ASurfaceTransaction_setFrameRate(ASurfaceTransaction* aSurfaceTransaction,
ASurfaceControl* aSurfaceControl, float frameRate) {
ASurfaceControl* aSurfaceControl, float frameRate,
int8_t compatibility) {
CHECK_NOT_NULL(aSurfaceTransaction);
CHECK_NOT_NULL(aSurfaceControl);
sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
if (frameRate < 0) {
ALOGE("Failed to set frame ate - invalid frame rate");
return;
}
Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
transaction->setFrameRate(surfaceControl, frameRate);
sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl);
transaction->setFrameRate(surfaceControl, frameRate, compatibility);
}