Remove JNI per-frame allocations in Choreographer
This removes per-frame allocations created in JNI portion of the Choreographer code: * DisplayEventReceiver$FrameData * DisplayEventReceiver$FrameTimeline[] * DisplayEventReceiver$FrameTimeline Test: atest ChoreographerTest Test: hwui_unit_tests using instructions Test: test app w/ invalidate, android studio profiler Fixes: 258694738 Change-Id: Ifae19e4dff0b980f90021216e4ebc20a99227a8d
This commit is contained in:
@@ -81,7 +81,10 @@ public abstract class DisplayEventReceiver {
|
||||
// GC'd while the native peer of the receiver is using them.
|
||||
private MessageQueue mMessageQueue;
|
||||
|
||||
private final VsyncEventData mVsyncEventData = new VsyncEventData();
|
||||
|
||||
private static native long nativeInit(WeakReference<DisplayEventReceiver> receiver,
|
||||
WeakReference<VsyncEventData> vsyncEventData,
|
||||
MessageQueue messageQueue, int vsyncSource, int eventRegistration, long layerHandle);
|
||||
private static native long nativeGetDisplayEventReceiverFinalizer();
|
||||
@FastNative
|
||||
@@ -124,7 +127,9 @@ public abstract class DisplayEventReceiver {
|
||||
}
|
||||
|
||||
mMessageQueue = looper.getQueue();
|
||||
mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this), mMessageQueue,
|
||||
mReceiverPtr = nativeInit(new WeakReference<DisplayEventReceiver>(this),
|
||||
new WeakReference<VsyncEventData>(mVsyncEventData),
|
||||
mMessageQueue,
|
||||
vsyncSource, eventRegistration, layerHandle);
|
||||
mFreeNativeResources = sNativeAllocationRegistry.registerNativeAllocation(this,
|
||||
mReceiverPtr);
|
||||
@@ -142,9 +147,6 @@ public abstract class DisplayEventReceiver {
|
||||
}
|
||||
|
||||
static final class VsyncEventData {
|
||||
|
||||
static final FrameTimeline[] INVALID_FRAME_TIMELINES =
|
||||
{new FrameTimeline(FrameInfo.INVALID_VSYNC_ID, Long.MAX_VALUE, Long.MAX_VALUE)};
|
||||
// The amount of frame timeline choices.
|
||||
// Must be in sync with VsyncEventData::kFrameTimelinesLength in
|
||||
// frameworks/native/libs/gui/include/gui/VsyncEventData.h. If they do not match, a runtime
|
||||
@@ -152,6 +154,10 @@ public abstract class DisplayEventReceiver {
|
||||
static final int FRAME_TIMELINES_LENGTH = 7;
|
||||
|
||||
public static class FrameTimeline {
|
||||
FrameTimeline() {}
|
||||
|
||||
// Called from native code.
|
||||
@SuppressWarnings("unused")
|
||||
FrameTimeline(long vsyncId, long expectedPresentationTime, long deadline) {
|
||||
this.vsyncId = vsyncId;
|
||||
this.expectedPresentationTime = expectedPresentationTime;
|
||||
@@ -160,14 +166,14 @@ public abstract class DisplayEventReceiver {
|
||||
|
||||
// The frame timeline vsync id, used to correlate a frame
|
||||
// produced by HWUI with the timeline data stored in Surface Flinger.
|
||||
public final long vsyncId;
|
||||
public long vsyncId = FrameInfo.INVALID_VSYNC_ID;
|
||||
|
||||
// The frame timestamp for when the frame is expected to be presented.
|
||||
public final long expectedPresentationTime;
|
||||
public long expectedPresentationTime = Long.MAX_VALUE;
|
||||
|
||||
// The frame deadline timestamp in {@link System#nanoTime()} timebase that it is
|
||||
// allotted for the frame to be completed.
|
||||
public final long deadline;
|
||||
public long deadline = Long.MAX_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -175,11 +181,18 @@ public abstract class DisplayEventReceiver {
|
||||
* {@link FrameInfo#VSYNC} to the current vsync in case Choreographer callback was heavily
|
||||
* delayed by the app.
|
||||
*/
|
||||
public final long frameInterval;
|
||||
public long frameInterval = -1;
|
||||
|
||||
public final FrameTimeline[] frameTimelines;
|
||||
|
||||
public final int preferredFrameTimelineIndex;
|
||||
public int preferredFrameTimelineIndex = 0;
|
||||
|
||||
VsyncEventData() {
|
||||
frameTimelines = new FrameTimeline[FRAME_TIMELINES_LENGTH];
|
||||
for (int i = 0; i < frameTimelines.length; i++) {
|
||||
frameTimelines[i] = new FrameTimeline();
|
||||
}
|
||||
}
|
||||
|
||||
// Called from native code.
|
||||
@SuppressWarnings("unused")
|
||||
@@ -190,12 +203,6 @@ public abstract class DisplayEventReceiver {
|
||||
this.frameInterval = frameInterval;
|
||||
}
|
||||
|
||||
VsyncEventData() {
|
||||
this.frameInterval = -1;
|
||||
this.frameTimelines = INVALID_FRAME_TIMELINES;
|
||||
this.preferredFrameTimelineIndex = 0;
|
||||
}
|
||||
|
||||
public FrameTimeline preferredFrameTimeline() {
|
||||
return frameTimelines[preferredFrameTimelineIndex];
|
||||
}
|
||||
@@ -299,9 +306,8 @@ public abstract class DisplayEventReceiver {
|
||||
|
||||
// Called from native code.
|
||||
@SuppressWarnings("unused")
|
||||
private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame,
|
||||
VsyncEventData vsyncEventData) {
|
||||
onVsync(timestampNanos, physicalDisplayId, frame, vsyncEventData);
|
||||
private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame) {
|
||||
onVsync(timestampNanos, physicalDisplayId, frame, mVsyncEventData);
|
||||
}
|
||||
|
||||
// Called from native code.
|
||||
|
||||
@@ -50,12 +50,22 @@ static struct {
|
||||
|
||||
struct {
|
||||
jclass clazz;
|
||||
|
||||
jmethodID init;
|
||||
|
||||
jfieldID vsyncId;
|
||||
jfieldID expectedPresentationTime;
|
||||
jfieldID deadline;
|
||||
} frameTimelineClassInfo;
|
||||
|
||||
struct {
|
||||
jclass clazz;
|
||||
|
||||
jmethodID init;
|
||||
|
||||
jfieldID frameInterval;
|
||||
jfieldID preferredFrameTimelineIndex;
|
||||
jfieldID frameTimelines;
|
||||
} vsyncEventDataClassInfo;
|
||||
|
||||
} gDisplayEventReceiverClassInfo;
|
||||
@@ -63,7 +73,7 @@ static struct {
|
||||
|
||||
class NativeDisplayEventReceiver : public DisplayEventDispatcher {
|
||||
public:
|
||||
NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak,
|
||||
NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak, jobject vsyncEventDataWeak,
|
||||
const sp<MessageQueue>& messageQueue, jint vsyncSource,
|
||||
jint eventRegistration, jlong layerHandle);
|
||||
|
||||
@@ -74,6 +84,7 @@ protected:
|
||||
|
||||
private:
|
||||
jobject mReceiverWeakGlobal;
|
||||
jobject mVsyncEventDataWeakGlobal;
|
||||
sp<MessageQueue> mMessageQueue;
|
||||
|
||||
void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count,
|
||||
@@ -87,6 +98,7 @@ private:
|
||||
};
|
||||
|
||||
NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, jobject receiverWeak,
|
||||
jobject vsyncEventDataWeak,
|
||||
const sp<MessageQueue>& messageQueue,
|
||||
jint vsyncSource, jint eventRegistration,
|
||||
jlong layerHandle)
|
||||
@@ -98,6 +110,7 @@ NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env, jobject rece
|
||||
reinterpret_cast<IBinder*>(layerHandle))
|
||||
: nullptr),
|
||||
mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
|
||||
mVsyncEventDataWeakGlobal(env->NewGlobalRef(vsyncEventDataWeak)),
|
||||
mMessageQueue(messageQueue) {
|
||||
ALOGV("receiver %p ~ Initializing display event receiver.", this);
|
||||
}
|
||||
@@ -144,12 +157,39 @@ void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDispla
|
||||
JNIEnv* env = AndroidRuntime::getJNIEnv();
|
||||
|
||||
ScopedLocalRef<jobject> receiverObj(env, GetReferent(env, mReceiverWeakGlobal));
|
||||
if (receiverObj.get()) {
|
||||
ScopedLocalRef<jobject> vsyncEventDataObj(env, GetReferent(env, mVsyncEventDataWeakGlobal));
|
||||
if (receiverObj.get() && vsyncEventDataObj.get()) {
|
||||
ALOGV("receiver %p ~ Invoking vsync handler.", this);
|
||||
|
||||
jobject javaVsyncEventData = createJavaVsyncEventData(env, vsyncEventData);
|
||||
env->SetIntField(vsyncEventDataObj.get(),
|
||||
gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo
|
||||
.preferredFrameTimelineIndex,
|
||||
vsyncEventData.preferredFrameTimelineIndex);
|
||||
env->SetLongField(vsyncEventDataObj.get(),
|
||||
gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameInterval,
|
||||
vsyncEventData.frameInterval);
|
||||
|
||||
jobjectArray frameTimelinesObj = reinterpret_cast<jobjectArray>(
|
||||
env->GetObjectField(vsyncEventDataObj.get(),
|
||||
gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo
|
||||
.frameTimelines));
|
||||
for (int i = 0; i < VsyncEventData::kFrameTimelinesLength; i++) {
|
||||
VsyncEventData::FrameTimeline& frameTimeline = vsyncEventData.frameTimelines[i];
|
||||
jobject frameTimelineObj = env->GetObjectArrayElement(frameTimelinesObj, i);
|
||||
env->SetLongField(frameTimelineObj,
|
||||
gDisplayEventReceiverClassInfo.frameTimelineClassInfo.vsyncId,
|
||||
frameTimeline.vsyncId);
|
||||
env->SetLongField(frameTimelineObj,
|
||||
gDisplayEventReceiverClassInfo.frameTimelineClassInfo
|
||||
.expectedPresentationTime,
|
||||
frameTimeline.expectedPresentationTime);
|
||||
env->SetLongField(frameTimelineObj,
|
||||
gDisplayEventReceiverClassInfo.frameTimelineClassInfo.deadline,
|
||||
frameTimeline.deadlineTimestamp);
|
||||
}
|
||||
|
||||
env->CallVoidMethod(receiverObj.get(), gDisplayEventReceiverClassInfo.dispatchVsync,
|
||||
timestamp, displayId.value, count, javaVsyncEventData);
|
||||
timestamp, displayId.value, count);
|
||||
ALOGV("receiver %p ~ Returned from vsync handler.", this);
|
||||
}
|
||||
|
||||
@@ -217,8 +257,9 @@ void NativeDisplayEventReceiver::dispatchFrameRateOverrides(
|
||||
mMessageQueue->raiseAndClearException(env, "dispatchModeChanged");
|
||||
}
|
||||
|
||||
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject messageQueueObj,
|
||||
jint vsyncSource, jint eventRegistration, jlong layerHandle) {
|
||||
static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject vsyncEventDataWeak,
|
||||
jobject messageQueueObj, jint vsyncSource, jint eventRegistration,
|
||||
jlong layerHandle) {
|
||||
sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, messageQueueObj);
|
||||
if (messageQueue == NULL) {
|
||||
jniThrowRuntimeException(env, "MessageQueue is not initialized.");
|
||||
@@ -226,8 +267,8 @@ static jlong nativeInit(JNIEnv* env, jclass clazz, jobject receiverWeak, jobject
|
||||
}
|
||||
|
||||
sp<NativeDisplayEventReceiver> receiver =
|
||||
new NativeDisplayEventReceiver(env, receiverWeak, messageQueue, vsyncSource,
|
||||
eventRegistration, layerHandle);
|
||||
new NativeDisplayEventReceiver(env, receiverWeak, vsyncEventDataWeak, messageQueue,
|
||||
vsyncSource, eventRegistration, layerHandle);
|
||||
status_t status = receiver->initialize();
|
||||
if (status) {
|
||||
String8 message;
|
||||
@@ -274,7 +315,9 @@ static jobject nativeGetLatestVsyncEventData(JNIEnv* env, jclass clazz, jlong re
|
||||
|
||||
static const JNINativeMethod gMethods[] = {
|
||||
/* name, signature, funcPtr */
|
||||
{"nativeInit", "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;IIJ)J",
|
||||
{"nativeInit",
|
||||
"(Ljava/lang/ref/WeakReference;Ljava/lang/ref/WeakReference;Landroid/os/"
|
||||
"MessageQueue;IIJ)J",
|
||||
(void*)nativeInit},
|
||||
{"nativeGetDisplayEventReceiverFinalizer", "()J",
|
||||
(void*)nativeGetDisplayEventReceiverFinalizer},
|
||||
@@ -291,8 +334,7 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) {
|
||||
gDisplayEventReceiverClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
|
||||
|
||||
gDisplayEventReceiverClassInfo.dispatchVsync =
|
||||
GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchVsync",
|
||||
"(JJILandroid/view/DisplayEventReceiver$VsyncEventData;)V");
|
||||
GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.clazz, "dispatchVsync", "(JJI)V");
|
||||
gDisplayEventReceiverClassInfo.dispatchHotplug = GetMethodIDOrDie(env,
|
||||
gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JJZ)V");
|
||||
gDisplayEventReceiverClassInfo.dispatchModeChanged =
|
||||
@@ -318,6 +360,15 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) {
|
||||
gDisplayEventReceiverClassInfo.frameTimelineClassInfo.init =
|
||||
GetMethodIDOrDie(env, gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz,
|
||||
"<init>", "(JJJ)V");
|
||||
gDisplayEventReceiverClassInfo.frameTimelineClassInfo.vsyncId =
|
||||
GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz,
|
||||
"vsyncId", "J");
|
||||
gDisplayEventReceiverClassInfo.frameTimelineClassInfo.expectedPresentationTime =
|
||||
GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz,
|
||||
"expectedPresentationTime", "J");
|
||||
gDisplayEventReceiverClassInfo.frameTimelineClassInfo.deadline =
|
||||
GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.frameTimelineClassInfo.clazz,
|
||||
"deadline", "J");
|
||||
|
||||
jclass vsyncEventDataClazz =
|
||||
FindClassOrDie(env, "android/view/DisplayEventReceiver$VsyncEventData");
|
||||
@@ -329,6 +380,17 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) {
|
||||
"([Landroid/view/"
|
||||
"DisplayEventReceiver$VsyncEventData$FrameTimeline;IJ)V");
|
||||
|
||||
gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.preferredFrameTimelineIndex =
|
||||
GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
|
||||
"preferredFrameTimelineIndex", "I");
|
||||
gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameInterval =
|
||||
GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
|
||||
"frameInterval", "J");
|
||||
gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.frameTimelines =
|
||||
GetFieldIDOrDie(env, gDisplayEventReceiverClassInfo.vsyncEventDataClassInfo.clazz,
|
||||
"frameTimelines",
|
||||
"[Landroid/view/DisplayEventReceiver$VsyncEventData$FrameTimeline;");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user