diff options
7 files changed, 68 insertions, 46 deletions
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java index aac5baacdb11..597be6864494 100644 --- a/core/java/android/view/Choreographer.java +++ b/core/java/android/view/Choreographer.java @@ -16,6 +16,9 @@ package android.view; +import static android.view.DisplayEventReceiver.VSYNC_SOURCE_APP; +import static android.view.DisplayEventReceiver.VSYNC_SOURCE_SURFACE_FLINGER; + import android.hardware.display.DisplayManagerGlobal; import android.os.Handler; import android.os.Looper; @@ -102,10 +105,23 @@ public final class Choreographer { if (looper == null) { throw new IllegalStateException("The current thread must have a looper!"); } - return new Choreographer(looper); + return new Choreographer(looper, VSYNC_SOURCE_APP); } }; + // Thread local storage for the SF choreographer. + private static final ThreadLocal<Choreographer> sSfThreadInstance = + new ThreadLocal<Choreographer>() { + @Override + protected Choreographer initialValue() { + Looper looper = Looper.myLooper(); + if (looper == null) { + throw new IllegalStateException("The current thread must have a looper!"); + } + return new Choreographer(looper, VSYNC_SOURCE_SURFACE_FLINGER); + } + }; + // Enable/disable vsync for animations and drawing. private static final boolean USE_VSYNC = SystemProperties.getBoolean( "debug.choreographer.vsync", true); @@ -202,10 +218,12 @@ public final class Choreographer { private static final int CALLBACK_LAST = CALLBACK_COMMIT; - private Choreographer(Looper looper) { + private Choreographer(Looper looper, int vsyncSource) { mLooper = looper; mHandler = new FrameHandler(looper); - mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null; + mDisplayEventReceiver = USE_VSYNC + ? new FrameDisplayEventReceiver(looper, vsyncSource) + : null; mLastFrameTimeNanos = Long.MIN_VALUE; mFrameIntervalNanos = (long)(1000000000 / getRefreshRate()); @@ -233,6 +251,13 @@ public final class Choreographer { return sThreadInstance.get(); } + /** + * @hide + */ + public static Choreographer getSfInstance() { + return sSfThreadInstance.get(); + } + /** Destroys the calling thread's choreographer * @hide */ @@ -816,8 +841,8 @@ public final class Choreographer { private long mTimestampNanos; private int mFrame; - public FrameDisplayEventReceiver(Looper looper) { - super(looper); + public FrameDisplayEventReceiver(Looper looper, int vsyncSource) { + super(looper, vsyncSource); } @Override diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java index 67cdfc53fb39..caadc364a3fb 100644 --- a/core/java/android/view/DisplayEventReceiver.java +++ b/core/java/android/view/DisplayEventReceiver.java @@ -35,6 +35,23 @@ import java.lang.ref.WeakReference; * @hide */ public abstract class DisplayEventReceiver { + + /** + * When retrieving vsync events, this specifies that the vsync event should happen at the normal + * vsync-app tick. + * <p> + * Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h + */ + public static final int VSYNC_SOURCE_APP = 0; + + /** + * When retrieving vsync events, this specifies that the vsync event should happen whenever + * Surface Flinger is processing a frame. + * <p> + * Needs to be kept in sync with frameworks/native/include/gui/ISurfaceComposer.h + */ + public static final int VSYNC_SOURCE_SURFACE_FLINGER = 1; + private static final String TAG = "DisplayEventReceiver"; private final CloseGuard mCloseGuard = CloseGuard.get(); @@ -46,7 +63,7 @@ public abstract class DisplayEventReceiver { private MessageQueue mMessageQueue; private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver, - MessageQueue messageQueue); + MessageQueue messageQueue, int vsyncSource); private static native void nativeDispose(long receiverPtr); @FastNative private static native void nativeScheduleVsync(long receiverPtr); @@ -55,14 +72,16 @@ public abstract class DisplayEventReceiver { * Creates a display event receiver. * * @param looper The looper to use when invoking callbacks. + * @param vsyncSource The source of the vsync tick. Must be on of the VSYNC_SOURCE_* values. */ - public DisplayEventReceiver(Looper looper) { + public DisplayEventReceiver(Looper looper, int vsyncSource) { if (looper == null) { throw new IllegalArgumentException("looper must not be null"); } mMessageQueue = looper.getQueue(); - mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue); + mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue, + vsyncSource); mCloseGuard.open("dispose"); } diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp index 2eada3e51eb3..831393bd0535 100644 --- a/core/jni/android_view_DisplayEventReceiver.cpp +++ b/core/jni/android_view_DisplayEventReceiver.cpp @@ -47,7 +47,7 @@ static struct { class NativeDisplayEventReceiver : public DisplayEventDispatcher { public: NativeDisplayEventReceiver(JNIEnv* env, - jobject receiverWeak, const sp<MessageQueue>& messageQueue); + jobject receiverWeak, const sp<MessageQueue>& messageQueue, jint vsyncSource); void dispose(); @@ -65,8 +65,9 @@ private: NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, - jobject receiverWeak, const sp<MessageQueue>& messageQueue) : - DisplayEventDispatcher(messageQueue->getLooper()), + jobject receiverWeak, const sp<MessageQueue>& messageQueue, jint vsyncSource) : + DisplayEventDispatcher(messageQueue->getLooper(), + static_cast<ISurfaceComposer::VsyncSource>(vsyncSource)), mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)), mMessageQueue(messageQueue) { ALOGV("receiver %p ~ Initializing display event receiver.", this); @@ -113,7 +114,7 @@ void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, int32_t id, static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, - jobject messageQueueObj) { + jobject messageQueueObj, jint vsyncSource) { sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj); if (messageQueue == NULL) { jniThrowRuntimeException(env, "MessageQueue is not initialized."); @@ -121,7 +122,7 @@ static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, } sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env, - receiverWeak, messageQueue); + receiverWeak, messageQueue, vsyncSource); status_t status = receiver->initialize(); if (status) { String8 message; @@ -156,7 +157,7 @@ static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) { static const JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ { "nativeInit", - "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;)J", + "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;I)J", (void*)nativeInit }, { "nativeDispose", "(J)V", diff --git a/libs/androidfw/DisplayEventDispatcher.cpp b/libs/androidfw/DisplayEventDispatcher.cpp index b8ef9ea49293..7708e4340397 100644 --- a/libs/androidfw/DisplayEventDispatcher.cpp +++ b/libs/androidfw/DisplayEventDispatcher.cpp @@ -33,8 +33,9 @@ namespace android { // using just a few large reads. static const size_t EVENT_BUFFER_SIZE = 100; -DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper) : - mLooper(looper), mWaitingForVsync(false) { +DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper, + ISurfaceComposer::VsyncSource vsyncSource) : + mLooper(looper), mReceiver(vsyncSource), mWaitingForVsync(false) { ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this); } diff --git a/libs/androidfw/include/androidfw/DisplayEventDispatcher.h b/libs/androidfw/include/androidfw/DisplayEventDispatcher.h index 3ade2156589a..e1dfb9490c60 100644 --- a/libs/androidfw/include/androidfw/DisplayEventDispatcher.h +++ b/libs/androidfw/include/androidfw/DisplayEventDispatcher.h @@ -22,7 +22,8 @@ namespace android { class DisplayEventDispatcher : public LooperCallback { public: - DisplayEventDispatcher(const sp<Looper>& looper); + DisplayEventDispatcher(const sp<Looper>& looper, + ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp); status_t initialize(); void dispose(); diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java index 841a951923a3..cdc973b079ea 100644 --- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java +++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java @@ -668,7 +668,7 @@ final class LocalDisplayAdapter extends DisplayAdapter { private final class HotplugDisplayEventReceiver extends DisplayEventReceiver { public HotplugDisplayEventReceiver(Looper looper) { - super(looper); + super(looper, VSYNC_SOURCE_APP); } @Override diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java index d85dd0c4cb2d..03b5b827db74 100644 --- a/services/core/java/com/android/server/wm/WindowAnimator.java +++ b/services/core/java/com/android/server/wm/WindowAnimator.java @@ -83,10 +83,6 @@ public class WindowAnimator { // check if some got replaced and can be removed. private boolean mRemoveReplacedWindows = false; - private long mCurrentFrameTime; - private final Runnable mAnimationTick; - private final SurfaceFlingerVsyncChoreographer mSfChoreographer; - private Choreographer mChoreographer; /** @@ -95,40 +91,19 @@ public class WindowAnimator { */ private boolean mAnimationFrameCallbackScheduled; - /** - * Indicates whether we have an animation tick scheduled. The tick is the thing that actually - * executes the animation step, which will happen at vsync-sf. - */ - private boolean mAnimationTickScheduled; - WindowAnimator(final WindowManagerService service) { mService = service; mContext = service.mContext; mPolicy = service.mPolicy; mWindowPlacerLocked = service.mWindowPlacerLocked; AnimationThread.getHandler().runWithScissors( - () -> mChoreographer = Choreographer.getInstance(), 0 /* timeout */); + () -> mChoreographer = Choreographer.getSfInstance(), 0 /* timeout */); - // TODO: Multi-display: If displays have different vsync tick, have a separate tick per - // display. - mSfChoreographer = new SurfaceFlingerVsyncChoreographer(AnimationThread.getHandler(), - mService.getDefaultDisplayContentLocked().getDisplay(), mChoreographer); - mAnimationTick = () -> { - synchronized (mService.mWindowMap) { - mAnimationTickScheduled = false; - } - animate(mCurrentFrameTime); - }; mAnimationFrameCallback = frameTimeNs -> { synchronized (mService.mWindowMap) { - mCurrentFrameTime = frameTimeNs; mAnimationFrameCallbackScheduled = false; - if (mAnimationTickScheduled) { - return; - } - mAnimationTickScheduled = true; } - mSfChoreographer.scheduleAtSfVsync(mAnimationTick); + animate(frameTimeNs); }; } @@ -422,7 +397,7 @@ public class WindowAnimator { } boolean isAnimationScheduled() { - return mAnimationFrameCallbackScheduled || mAnimationTickScheduled; + return mAnimationFrameCallbackScheduled; } Choreographer getChoreographer() { |