OSDN Git Service

Early wake-up for transitions (2/2)
authorJorim Jaggi <jjaggi@google.com>
Thu, 22 Mar 2018 22:20:36 +0000 (23:20 +0100)
committerJorim Jaggi <jjaggi@google.com>
Fri, 6 Apr 2018 11:36:14 +0000 (13:36 +0200)
On some devices it's very likely that we fall into GL comp during
app transitions. However, SF offsets are chosen in a way such that
the time to finish a frame is just too tight to be completely jank
free when hitting GL composition in SurfaceFlinger. Thus, we
introduce the concept of a separate early offset, and wakeup
SurfaceFlinger at that time if we think that hitting GL comp is
likely, or we already hit GL comp in the last frame.

Test: Open app, check vsync offsets in systrace
Test: Open many dialogs/apps to fall into GPU comp.
Bug: 75985430
Change-Id: I461fdcd573583f3ea0348c8b23cc9945d33f8976

core/java/android/view/SurfaceControl.java
core/jni/android_view_SurfaceControl.cpp
packages/SystemUI/shared/src/com/android/systemui/shared/system/TransactionCompat.java
packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java
services/core/java/com/android/server/wm/AppWindowToken.java
services/core/java/com/android/server/wm/LocalAnimationAdapter.java
services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
services/core/java/com/android/server/wm/WindowAnimationSpec.java
services/tests/servicestests/src/com/android/server/wm/WindowAnimationSpecTest.java

index d4610a5..5deee11 100644 (file)
@@ -87,6 +87,7 @@ public class SurfaceControl implements Parcelable {
     private static native void nativeMergeTransaction(long transactionObj,
             long otherTransactionObj);
     private static native void nativeSetAnimationTransaction(long transactionObj);
+    private static native void nativeSetEarlyWakeup(long transactionObj);
 
     private static native void nativeSetLayer(long transactionObj, long nativeObject, int zorder);
     private static native void nativeSetRelativeLayer(long transactionObj, long nativeObject,
@@ -1642,6 +1643,19 @@ public class SurfaceControl implements Parcelable {
         }
 
         /**
+         * Indicate that SurfaceFlinger should wake up earlier than usual as a result of this
+         * transaction. This should be used when the caller thinks that the scene is complex enough
+         * that it's likely to hit GL composition, and thus, SurfaceFlinger needs to more time in
+         * order not to miss frame deadlines.
+         * <p>
+         * Corresponds to setting ISurfaceComposer::eEarlyWakeup
+         */
+        public Transaction setEarlyWakeup() {
+            nativeSetEarlyWakeup(mNativeObject);
+            return this;
+        }
+
+        /**
          * Merge the other transaction into this transaction, clearing the
          * other transaction as if it had been applied.
          */
index b0f68cd..3f58afa 100644 (file)
@@ -327,6 +327,11 @@ static void nativeSetAnimationTransaction(JNIEnv* env, jclass clazz, jlong trans
     transaction->setAnimationTransaction();
 }
 
+static void nativeSetEarlyWakeup(JNIEnv* env, jclass clazz, jlong transactionObj) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+    transaction->setEarlyWakeup();
+}
+
 static void nativeSetLayer(JNIEnv* env, jclass clazz, jlong transactionObj,
         jlong nativeObject, jint zorder) {
     auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
@@ -934,6 +939,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
             (void*)nativeMergeTransaction },
     {"nativeSetAnimationTransaction", "(J)V",
             (void*)nativeSetAnimationTransaction },
+    {"nativeSetEarlyWakeup", "(J)V",
+            (void*)nativeSetEarlyWakeup },
     {"nativeSetLayer", "(JJI)V",
             (void*)nativeSetLayer },
     {"nativeSetRelativeLayer", "(JJLandroid/os/IBinder;I)V",
index c82c519..9975c41 100644 (file)
@@ -101,6 +101,11 @@ public class TransactionCompat {
         return this;
     }
 
+    public TransactionCompat setEarlyWakeup() {
+        mTransaction.setEarlyWakeup();
+        return this;
+    }
+
     public TransactionCompat setColor(SurfaceControlCompat surfaceControl, float[] color) {
         mTransaction.setColor(surfaceControl.mSurfaceControl, color);
         return this;
index 3bbfe3c..b8bce95 100644 (file)
@@ -238,6 +238,7 @@ public class ActivityLaunchAnimator {
                 t.deferTransactionUntilSurface(app.leash, systemUiSurface,
                         systemUiSurface.getNextFrameNumber());
             }
+            t.setEarlyWakeup();
             t.apply();
         }
 
index 8fa94fb..9a4db65 100644 (file)
@@ -1714,7 +1714,8 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
                     adapter = new LocalAnimationAdapter(
                             new WindowAnimationSpec(a, mTmpPoint, mTmpRect,
                                     mService.mAppTransition.canSkipFirstFrame(),
-                                    mService.mAppTransition.getAppStackClipMode()),
+                                    mService.mAppTransition.getAppStackClipMode(),
+                                    true /* isAppAnimation */),
                             mService.mSurfaceAnimationRunner);
                     if (a.getZAdjustment() == Animation.ZORDER_TOP) {
                         mNeedsZBoost = true;
index 529aacc..d89d6f0 100644 (file)
@@ -146,6 +146,13 @@ class LocalAnimationAdapter implements AnimationAdapter {
             return false;
         }
 
+        /**
+         * @return {@code true} if we need to wake-up SurfaceFlinger earlier during this animation.
+         *
+         * @see Transaction#setEarlyWakeup
+         */
+        default boolean needsEarlyWakeup() { return false; }
+
         void dump(PrintWriter pw, String prefix);
 
         default void writeToProto(ProtoOutputStream proto, long fieldId) {
index 98fcb0b..7211533 100644 (file)
@@ -220,6 +220,9 @@ class SurfaceAnimationRunner {
     }
 
     private void applyTransformation(RunningAnimation a, Transaction t, long currentPlayTime) {
+        if (a.mAnimSpec.needsEarlyWakeup()) {
+            t.setEarlyWakeup();
+        }
         a.mAnimSpec.apply(t, a.mLeash, currentPlayTime);
     }
 
index 7b7cb30..548e23a 100644 (file)
@@ -47,21 +47,24 @@ public class WindowAnimationSpec implements AnimationSpec {
     private final Point mPosition = new Point();
     private final ThreadLocal<TmpValues> mThreadLocalTmps = ThreadLocal.withInitial(TmpValues::new);
     private final boolean mCanSkipFirstFrame;
+    private final boolean mIsAppAnimation;
     private final Rect mStackBounds = new Rect();
     private int mStackClipMode;
     private final Rect mTmpRect = new Rect();
 
     public WindowAnimationSpec(Animation animation, Point position, boolean canSkipFirstFrame)  {
-        this(animation, position, null /* stackBounds */, canSkipFirstFrame, STACK_CLIP_NONE);
+        this(animation, position, null /* stackBounds */, canSkipFirstFrame, STACK_CLIP_NONE,
+                false /* isAppAnimation */);
     }
 
     public WindowAnimationSpec(Animation animation, Point position, Rect stackBounds,
-            boolean canSkipFirstFrame, int stackClipMode) {
+            boolean canSkipFirstFrame, int stackClipMode, boolean isAppAnimation) {
         mAnimation = animation;
         if (position != null) {
             mPosition.set(position.x, position.y);
         }
         mCanSkipFirstFrame = canSkipFirstFrame;
+        mIsAppAnimation = isAppAnimation;
         mStackClipMode = stackClipMode;
         if (stackBounds != null) {
             mStackBounds.set(stackBounds);
@@ -135,6 +138,11 @@ public class WindowAnimationSpec implements AnimationSpec {
     }
 
     @Override
+    public boolean needsEarlyWakeup() {
+        return mIsAppAnimation;
+    }
+
+    @Override
     public void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.println(mAnimation);
     }
index 794d033..ca520ed 100644 (file)
@@ -56,7 +56,8 @@ public class WindowAnimationSpecTest {
         Rect windowCrop = new Rect(0, 0, 20, 20);
         Animation a = createClipRectAnimation(windowCrop, windowCrop);
         WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(a, null,
-                mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_NONE);
+                mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_NONE,
+                true /* isAppAnimation */);
         windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
         verify(mTransaction).setWindowCrop(eq(mSurfaceControl),
                 argThat(rect -> rect.equals(windowCrop)));
@@ -65,7 +66,8 @@ public class WindowAnimationSpecTest {
     @Test
     public void testApply_clipAfter() {
         WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(mAnimation, null,
-                mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_AFTER_ANIM);
+                mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_AFTER_ANIM,
+                true /* isAppAnimation */);
         windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
         verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(Rect::isEmpty));
         verify(mTransaction).setFinalCrop(eq(mSurfaceControl),
@@ -77,7 +79,8 @@ public class WindowAnimationSpecTest {
         // Stack bounds is (0, 0, 10, 10) position is (20, 40)
         WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(mAnimation,
                 new Point(20, 40), mStackBounds, false /* canSkipFirstFrame */,
-                STACK_CLIP_AFTER_ANIM);
+                STACK_CLIP_AFTER_ANIM,
+                true /* isAppAnimation */);
         windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
         verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(Rect::isEmpty));
         verify(mTransaction).setFinalCrop(eq(mSurfaceControl),
@@ -89,7 +92,8 @@ public class WindowAnimationSpecTest {
     public void testApply_clipBeforeNoAnimationBounds() {
         // Stack bounds is (0, 0, 10, 10) animation clip is (0, 0, 0, 0)
         WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(mAnimation, null,
-                mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM);
+                mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM,
+                true /* isAppAnimation */);
         windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
         verify(mTransaction).setWindowCrop(eq(mSurfaceControl),
                 argThat(rect -> rect.equals(mStackBounds)));
@@ -102,7 +106,8 @@ public class WindowAnimationSpecTest {
         Animation a = createClipRectAnimation(windowCrop, windowCrop);
         a.initialize(0, 0, 0, 0);
         WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(a, null,
-                null, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM);
+                null, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM,
+                true /* isAppAnimation */);
         windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
         verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(Rect::isEmpty));
     }
@@ -113,7 +118,8 @@ public class WindowAnimationSpecTest {
         Rect windowCrop = new Rect(0, 0, 5, 5);
         Animation a = createClipRectAnimation(windowCrop, windowCrop);
         WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(a, null,
-                mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM);
+                mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM,
+                true /* isAppAnimation */);
         windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
         verify(mTransaction).setWindowCrop(eq(mSurfaceControl),
                 argThat(rect -> rect.equals(windowCrop)));
@@ -125,7 +131,8 @@ public class WindowAnimationSpecTest {
         Rect windowCrop = new Rect(0, 0, 20, 20);
         Animation a = createClipRectAnimation(windowCrop, windowCrop);
         WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(a, null,
-                mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM);
+                mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_BEFORE_ANIM,
+                true /* isAppAnimation */);
         windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
         verify(mTransaction).setWindowCrop(eq(mSurfaceControl),
                 argThat(rect -> rect.equals(mStackBounds)));