Merge "Properly run window animations at vsync-sf (1/2)" into oc-dev

This commit is contained in:
Jorim Jaggi
2017-06-09 04:06:38 +00:00
committed by Android (Google) Code Review
7 changed files with 68 additions and 46 deletions

View File

@@ -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

View File

@@ -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");
}

View File

@@ -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",

View File

@@ -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);
}

View File

@@ -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();

View File

@@ -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

View File

@@ -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() {