Add two new display info fields
This adds SurfaceFlinger's app VSYNC offset and buffer deadline
values to DisplayInfo. The values will be available to apps
through queries on a Display object (currently hidden).
Bug 14612039
Change-Id: I48760f58a9d74d99651b02a9d595f420410f2bb5
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index d7a913d..181f77e 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -599,6 +599,42 @@
}
/**
+ * Gets the app VSYNC offset, in nanoseconds. This is a positive value indicating
+ * the phase offset of the VSYNC events provided by Choreographer relative to the
+ * display refresh. For example, if Choreographer reports that the refresh occurred
+ * at time N, it actually occurred at (N - appVsyncOffset).
+ * <p>
+ * Apps generally do not need to be aware of this. It's only useful for fine-grained
+ * A/V synchronization.
+ * @hide
+ */
+ public long getAppVsyncOffsetNanos() {
+ synchronized (this) {
+ updateDisplayInfoLocked();
+ return mDisplayInfo.appVsyncOffsetNanos;
+ }
+ }
+
+ /**
+ * This is how far in advance a buffer must be queued for presentation at
+ * a given time. If you want a buffer to appear on the screen at
+ * time N, you must submit the buffer before (N - presentationDeadline).
+ * <p>
+ * The desired presentation time for GLES rendering may be set with
+ * {@link android.opengl.EGLExt#eglPresentationTimeANDROID}. For video decoding, use
+ * {@link android.media.MediaCodec#releaseOutputBuffer(int, long)}. Times are
+ * expressed in nanoseconds, using the system monotonic clock
+ * ({@link System#nanoTime}).
+ * @hide
+ */
+ public long getPresentationDeadlineNanos() {
+ synchronized (this) {
+ updateDisplayInfoLocked();
+ return mDisplayInfo.presentationDeadlineNanos;
+ }
+ }
+
+ /**
* Gets display metrics that describe the size and density of this display.
* <p>
* The size is adjusted based on the current rotation of the display.
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index b0fe0fa..98696c7 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -180,6 +180,20 @@
public float physicalYDpi;
/**
+ * This is a positive value indicating the phase offset of the VSYNC events provided by
+ * Choreographer relative to the display refresh. For example, if Choreographer reports
+ * that the refresh occurred at time N, it actually occurred at (N - appVsyncOffsetNanos).
+ */
+ public long appVsyncOffsetNanos;
+
+ /**
+ * This is how far in advance a buffer must be queued for presentation at
+ * a given time. If you want a buffer to appear on the screen at
+ * time N, you must submit the buffer before (N - bufferDeadlineNanos).
+ */
+ public long presentationDeadlineNanos;
+
+ /**
* The state of the display, such as {@link android.view.Display#STATE_ON}.
*/
public int state;
@@ -253,6 +267,8 @@
&& logicalDensityDpi == other.logicalDensityDpi
&& physicalXDpi == other.physicalXDpi
&& physicalYDpi == other.physicalYDpi
+ && appVsyncOffsetNanos == other.appVsyncOffsetNanos
+ && presentationDeadlineNanos == other.presentationDeadlineNanos
&& state == other.state
&& ownerUid == other.ownerUid
&& Objects.equal(ownerPackageName, other.ownerPackageName);
@@ -286,6 +302,8 @@
logicalDensityDpi = other.logicalDensityDpi;
physicalXDpi = other.physicalXDpi;
physicalYDpi = other.physicalYDpi;
+ appVsyncOffsetNanos = other.appVsyncOffsetNanos;
+ presentationDeadlineNanos = other.presentationDeadlineNanos;
state = other.state;
ownerUid = other.ownerUid;
ownerPackageName = other.ownerPackageName;
@@ -314,6 +332,8 @@
logicalDensityDpi = source.readInt();
physicalXDpi = source.readFloat();
physicalYDpi = source.readFloat();
+ appVsyncOffsetNanos = source.readLong();
+ presentationDeadlineNanos = source.readLong();
state = source.readInt();
ownerUid = source.readInt();
ownerPackageName = source.readString();
@@ -343,6 +363,8 @@
dest.writeInt(logicalDensityDpi);
dest.writeFloat(physicalXDpi);
dest.writeFloat(physicalYDpi);
+ dest.writeLong(appVsyncOffsetNanos);
+ dest.writeLong(presentationDeadlineNanos);
dest.writeInt(state);
dest.writeInt(ownerUid);
dest.writeString(ownerPackageName);
@@ -450,6 +472,10 @@
sb.append(physicalYDpi);
sb.append(") dpi, layerStack ");
sb.append(layerStack);
+ sb.append(", appVsyncOff ");
+ sb.append(appVsyncOffsetNanos);
+ sb.append(", presDeadline ");
+ sb.append(presentationDeadlineNanos);
sb.append(", type ");
sb.append(Display.typeToString(type));
if (address != null) {
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 79f19b5..94d8f70 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -458,6 +458,8 @@
public float xDpi;
public float yDpi;
public boolean secure;
+ public long appVsyncOffsetNanos;
+ public long presentationDeadlineNanos;
public PhysicalDisplayInfo() {
}
@@ -479,7 +481,9 @@
&& density == other.density
&& xDpi == other.xDpi
&& yDpi == other.yDpi
- && secure == other.secure;
+ && secure == other.secure
+ && appVsyncOffsetNanos == other.appVsyncOffsetNanos
+ && presentationDeadlineNanos == other.presentationDeadlineNanos;
}
@Override
@@ -495,6 +499,8 @@
xDpi = other.xDpi;
yDpi = other.yDpi;
secure = other.secure;
+ appVsyncOffsetNanos = other.appVsyncOffsetNanos;
+ presentationDeadlineNanos = other.presentationDeadlineNanos;
}
// For debugging purposes
@@ -502,7 +508,8 @@
public String toString() {
return "PhysicalDisplayInfo{" + width + " x " + height + ", " + refreshRate + " fps, "
+ "density " + density + ", " + xDpi + " x " + yDpi + " dpi, secure " + secure
- + "}";
+ + ", appVsyncOffset " + appVsyncOffsetNanos
+ + ", bufferDeadline " + presentationDeadlineNanos + "}";
}
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index c0d5221..cfc8eb8 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -61,6 +61,8 @@
jfieldID xDpi;
jfieldID yDpi;
jfieldID secure;
+ jfieldID appVsyncOffsetNanos;
+ jfieldID presentationDeadlineNanos;
} gPhysicalDisplayInfoClassInfo;
static struct {
@@ -392,6 +394,10 @@
env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.xDpi, info.xdpi);
env->SetFloatField(infoObj, gPhysicalDisplayInfoClassInfo.yDpi, info.ydpi);
env->SetBooleanField(infoObj, gPhysicalDisplayInfoClassInfo.secure, info.secure);
+ env->SetLongField(infoObj, gPhysicalDisplayInfoClassInfo.appVsyncOffsetNanos,
+ info.appVsyncOffset);
+ env->SetLongField(infoObj, gPhysicalDisplayInfoClassInfo.presentationDeadlineNanos,
+ info.presentationDeadline);
env->SetObjectArrayElement(configArray, static_cast<jsize>(c), infoObj);
env->DeleteLocalRef(infoObj);
}
@@ -648,6 +654,10 @@
gPhysicalDisplayInfoClassInfo.xDpi = env->GetFieldID(clazz, "xDpi", "F");
gPhysicalDisplayInfoClassInfo.yDpi = env->GetFieldID(clazz, "yDpi", "F");
gPhysicalDisplayInfoClassInfo.secure = env->GetFieldID(clazz, "secure", "Z");
+ gPhysicalDisplayInfoClassInfo.appVsyncOffsetNanos = env->GetFieldID(clazz,
+ "appVsyncOffsetNanos", "J");
+ gPhysicalDisplayInfoClassInfo.presentationDeadlineNanos = env->GetFieldID(clazz,
+ "presentationDeadlineNanos", "J");
jclass rectClazz = env->FindClass("android/graphics/Rect");
gRectClassInfo.bottom = env->GetFieldID(rectClazz, "bottom", "I");