Merge "Properly run window animations at vsync-sf (1/2)" into oc-dev
am: d1f55f6302
Change-Id: Ibc28f6019637dbc9696c62f1ad1ce4679954fbd5
This commit is contained in:
@@ -16,6 +16,9 @@
|
|||||||
|
|
||||||
package android.view;
|
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.hardware.display.DisplayManagerGlobal;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
@@ -102,7 +105,20 @@ public final class Choreographer {
|
|||||||
if (looper == null) {
|
if (looper == null) {
|
||||||
throw new IllegalStateException("The current thread must have a looper!");
|
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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -202,10 +218,12 @@ public final class Choreographer {
|
|||||||
|
|
||||||
private static final int CALLBACK_LAST = CALLBACK_COMMIT;
|
private static final int CALLBACK_LAST = CALLBACK_COMMIT;
|
||||||
|
|
||||||
private Choreographer(Looper looper) {
|
private Choreographer(Looper looper, int vsyncSource) {
|
||||||
mLooper = looper;
|
mLooper = looper;
|
||||||
mHandler = new FrameHandler(looper);
|
mHandler = new FrameHandler(looper);
|
||||||
mDisplayEventReceiver = USE_VSYNC ? new FrameDisplayEventReceiver(looper) : null;
|
mDisplayEventReceiver = USE_VSYNC
|
||||||
|
? new FrameDisplayEventReceiver(looper, vsyncSource)
|
||||||
|
: null;
|
||||||
mLastFrameTimeNanos = Long.MIN_VALUE;
|
mLastFrameTimeNanos = Long.MIN_VALUE;
|
||||||
|
|
||||||
mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
|
mFrameIntervalNanos = (long)(1000000000 / getRefreshRate());
|
||||||
@@ -233,6 +251,13 @@ public final class Choreographer {
|
|||||||
return sThreadInstance.get();
|
return sThreadInstance.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static Choreographer getSfInstance() {
|
||||||
|
return sSfThreadInstance.get();
|
||||||
|
}
|
||||||
|
|
||||||
/** Destroys the calling thread's choreographer
|
/** Destroys the calling thread's choreographer
|
||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
@@ -816,8 +841,8 @@ public final class Choreographer {
|
|||||||
private long mTimestampNanos;
|
private long mTimestampNanos;
|
||||||
private int mFrame;
|
private int mFrame;
|
||||||
|
|
||||||
public FrameDisplayEventReceiver(Looper looper) {
|
public FrameDisplayEventReceiver(Looper looper, int vsyncSource) {
|
||||||
super(looper);
|
super(looper, vsyncSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -35,6 +35,23 @@ import java.lang.ref.WeakReference;
|
|||||||
* @hide
|
* @hide
|
||||||
*/
|
*/
|
||||||
public abstract class DisplayEventReceiver {
|
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 static final String TAG = "DisplayEventReceiver";
|
||||||
|
|
||||||
private final CloseGuard mCloseGuard = CloseGuard.get();
|
private final CloseGuard mCloseGuard = CloseGuard.get();
|
||||||
@@ -46,7 +63,7 @@ public abstract class DisplayEventReceiver {
|
|||||||
private MessageQueue mMessageQueue;
|
private MessageQueue mMessageQueue;
|
||||||
|
|
||||||
private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver,
|
private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver,
|
||||||
MessageQueue messageQueue);
|
MessageQueue messageQueue, int vsyncSource);
|
||||||
private static native void nativeDispose(long receiverPtr);
|
private static native void nativeDispose(long receiverPtr);
|
||||||
@FastNative
|
@FastNative
|
||||||
private static native void nativeScheduleVsync(long receiverPtr);
|
private static native void nativeScheduleVsync(long receiverPtr);
|
||||||
@@ -55,14 +72,16 @@ public abstract class DisplayEventReceiver {
|
|||||||
* Creates a display event receiver.
|
* Creates a display event receiver.
|
||||||
*
|
*
|
||||||
* @param looper The looper to use when invoking callbacks.
|
* @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) {
|
if (looper == null) {
|
||||||
throw new IllegalArgumentException("looper must not be null");
|
throw new IllegalArgumentException("looper must not be null");
|
||||||
}
|
}
|
||||||
|
|
||||||
mMessageQueue = looper.getQueue();
|
mMessageQueue = looper.getQueue();
|
||||||
mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue);
|
mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,
|
||||||
|
vsyncSource);
|
||||||
|
|
||||||
mCloseGuard.open("dispose");
|
mCloseGuard.open("dispose");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ static struct {
|
|||||||
class NativeDisplayEventReceiver : public DisplayEventDispatcher {
|
class NativeDisplayEventReceiver : public DisplayEventDispatcher {
|
||||||
public:
|
public:
|
||||||
NativeDisplayEventReceiver(JNIEnv* env,
|
NativeDisplayEventReceiver(JNIEnv* env,
|
||||||
jobject receiverWeak, const sp<MessageQueue>& messageQueue);
|
jobject receiverWeak, const sp<MessageQueue>& messageQueue, jint vsyncSource);
|
||||||
|
|
||||||
void dispose();
|
void dispose();
|
||||||
|
|
||||||
@@ -65,8 +65,9 @@ private:
|
|||||||
|
|
||||||
|
|
||||||
NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
|
NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
|
||||||
jobject receiverWeak, const sp<MessageQueue>& messageQueue) :
|
jobject receiverWeak, const sp<MessageQueue>& messageQueue, jint vsyncSource) :
|
||||||
DisplayEventDispatcher(messageQueue->getLooper()),
|
DisplayEventDispatcher(messageQueue->getLooper(),
|
||||||
|
static_cast<ISurfaceComposer::VsyncSource>(vsyncSource)),
|
||||||
mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
|
mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
|
||||||
mMessageQueue(messageQueue) {
|
mMessageQueue(messageQueue) {
|
||||||
ALOGV("receiver %p ~ Initializing display event receiver.", this);
|
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,
|
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak,
|
||||||
jobject messageQueueObj) {
|
jobject messageQueueObj, jint vsyncSource) {
|
||||||
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
|
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
|
||||||
if (messageQueue == NULL) {
|
if (messageQueue == NULL) {
|
||||||
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
|
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,
|
sp<NativeDisplayEventReceiver> receiver = new NativeDisplayEventReceiver(env,
|
||||||
receiverWeak, messageQueue);
|
receiverWeak, messageQueue, vsyncSource);
|
||||||
status_t status = receiver->initialize();
|
status_t status = receiver->initialize();
|
||||||
if (status) {
|
if (status) {
|
||||||
String8 message;
|
String8 message;
|
||||||
@@ -156,7 +157,7 @@ static void nativeScheduleVsync(JNIEnv* env, jclass clazz, jlong receiverPtr) {
|
|||||||
static const JNINativeMethod gMethods[] = {
|
static const JNINativeMethod gMethods[] = {
|
||||||
/* name, signature, funcPtr */
|
/* name, signature, funcPtr */
|
||||||
{ "nativeInit",
|
{ "nativeInit",
|
||||||
"(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;)J",
|
"(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;I)J",
|
||||||
(void*)nativeInit },
|
(void*)nativeInit },
|
||||||
{ "nativeDispose",
|
{ "nativeDispose",
|
||||||
"(J)V",
|
"(J)V",
|
||||||
|
|||||||
@@ -33,8 +33,9 @@ namespace android {
|
|||||||
// using just a few large reads.
|
// using just a few large reads.
|
||||||
static const size_t EVENT_BUFFER_SIZE = 100;
|
static const size_t EVENT_BUFFER_SIZE = 100;
|
||||||
|
|
||||||
DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper) :
|
DisplayEventDispatcher::DisplayEventDispatcher(const sp<Looper>& looper,
|
||||||
mLooper(looper), mWaitingForVsync(false) {
|
ISurfaceComposer::VsyncSource vsyncSource) :
|
||||||
|
mLooper(looper), mReceiver(vsyncSource), mWaitingForVsync(false) {
|
||||||
ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
|
ALOGV("dispatcher %p ~ Initializing display event dispatcher.", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ namespace android {
|
|||||||
|
|
||||||
class DisplayEventDispatcher : public LooperCallback {
|
class DisplayEventDispatcher : public LooperCallback {
|
||||||
public:
|
public:
|
||||||
DisplayEventDispatcher(const sp<Looper>& looper);
|
DisplayEventDispatcher(const sp<Looper>& looper,
|
||||||
|
ISurfaceComposer::VsyncSource vsyncSource = ISurfaceComposer::eVsyncSourceApp);
|
||||||
|
|
||||||
status_t initialize();
|
status_t initialize();
|
||||||
void dispose();
|
void dispose();
|
||||||
|
|||||||
@@ -668,7 +668,7 @@ final class LocalDisplayAdapter extends DisplayAdapter {
|
|||||||
|
|
||||||
private final class HotplugDisplayEventReceiver extends DisplayEventReceiver {
|
private final class HotplugDisplayEventReceiver extends DisplayEventReceiver {
|
||||||
public HotplugDisplayEventReceiver(Looper looper) {
|
public HotplugDisplayEventReceiver(Looper looper) {
|
||||||
super(looper);
|
super(looper, VSYNC_SOURCE_APP);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -83,10 +83,6 @@ public class WindowAnimator {
|
|||||||
// check if some got replaced and can be removed.
|
// check if some got replaced and can be removed.
|
||||||
private boolean mRemoveReplacedWindows = false;
|
private boolean mRemoveReplacedWindows = false;
|
||||||
|
|
||||||
private long mCurrentFrameTime;
|
|
||||||
private final Runnable mAnimationTick;
|
|
||||||
private final SurfaceFlingerVsyncChoreographer mSfChoreographer;
|
|
||||||
|
|
||||||
private Choreographer mChoreographer;
|
private Choreographer mChoreographer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -95,40 +91,19 @@ public class WindowAnimator {
|
|||||||
*/
|
*/
|
||||||
private boolean mAnimationFrameCallbackScheduled;
|
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) {
|
WindowAnimator(final WindowManagerService service) {
|
||||||
mService = service;
|
mService = service;
|
||||||
mContext = service.mContext;
|
mContext = service.mContext;
|
||||||
mPolicy = service.mPolicy;
|
mPolicy = service.mPolicy;
|
||||||
mWindowPlacerLocked = service.mWindowPlacerLocked;
|
mWindowPlacerLocked = service.mWindowPlacerLocked;
|
||||||
AnimationThread.getHandler().runWithScissors(
|
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 -> {
|
mAnimationFrameCallback = frameTimeNs -> {
|
||||||
synchronized (mService.mWindowMap) {
|
synchronized (mService.mWindowMap) {
|
||||||
mCurrentFrameTime = frameTimeNs;
|
|
||||||
mAnimationFrameCallbackScheduled = false;
|
mAnimationFrameCallbackScheduled = false;
|
||||||
if (mAnimationTickScheduled) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
mAnimationTickScheduled = true;
|
animate(frameTimeNs);
|
||||||
}
|
|
||||||
mSfChoreographer.scheduleAtSfVsync(mAnimationTick);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -422,7 +397,7 @@ public class WindowAnimator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean isAnimationScheduled() {
|
boolean isAnimationScheduled() {
|
||||||
return mAnimationFrameCallbackScheduled || mAnimationTickScheduled;
|
return mAnimationFrameCallbackScheduled;
|
||||||
}
|
}
|
||||||
|
|
||||||
Choreographer getChoreographer() {
|
Choreographer getChoreographer() {
|
||||||
|
|||||||
Reference in New Issue
Block a user