Merge "Support HDMI hotplug." into jb-mr1-dev

This commit is contained in:
Jeff Brown
2012-09-21 15:51:41 -07:00
committed by Android (Google) Code Review
5 changed files with 112 additions and 24 deletions

View File

@@ -16,7 +16,6 @@
package android.view;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManagerGlobal;
import android.os.Handler;
import android.os.Looper;
@@ -685,7 +684,24 @@ public final class Choreographer {
}
@Override
public void onVsync(long timestampNanos, int frame) {
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
// Ignore vsync from secondary display.
// This can be problematic because the call to scheduleVsync() is a one-shot.
// We need to ensure that we will still receive the vsync from the primary
// display which is the one we really care about. Ideally we should schedule
// vsync for a particular display.
// At this time Surface Flinger won't send us vsyncs for secondary displays
// but that could change in the future so let's log a message to help us remember
// that we need to fix this.
if (builtInDisplayId != Surface.BUILT_IN_DISPLAY_ID_MAIN) {
Log.d(TAG, "Received vsync from secondary display, but we don't support "
+ "this case yet. Choreographer needs a way to explicitly request "
+ "vsync for a specific display to ensure it doesn't lose track "
+ "of its scheduled vsync.");
scheduleVsync();
return;
}
// Post the vsync event to the Handler.
// The idea is to prevent incoming vsync events from completely starving
// the message queue. If there are no messages in the queue with timestamps

View File

@@ -101,9 +101,23 @@ public abstract class DisplayEventReceiver {
*
* @param timestampNanos The timestamp of the pulse, in the {@link System#nanoTime()}
* timebase.
* @param builtInDisplayId The surface flinger built-in display id such as
* {@link Surface#BUILT_IN_DISPLAY_ID_MAIN}.
* @param frame The frame number. Increases by one for each vertical sync interval.
*/
public void onVsync(long timestampNanos, int frame) {
public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
}
/**
* Called when a display hotplug event is received.
*
* @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()}
* timebase.
* @param builtInDisplayId The surface flinger built-in display id such as
* {@link Surface#BUILT_IN_DISPLAY_ID_HDMI}.
* @param connected True if the display is connected, false if it disconnected.
*/
public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) {
}
/**
@@ -121,7 +135,13 @@ public abstract class DisplayEventReceiver {
// Called from native code.
@SuppressWarnings("unused")
private void dispatchVsync(long timestampNanos, int frame) {
onVsync(timestampNanos, frame);
private void dispatchVsync(long timestampNanos, int builtInDisplayId, int frame) {
onVsync(timestampNanos, builtInDisplayId, frame);
}
// Called from native code.
@SuppressWarnings("unused")
private void dispatchHotplug(long timestampNanos, int builtInDisplayId, boolean connected) {
onHotplug(timestampNanos, builtInDisplayId, connected);
}
}

View File

@@ -39,6 +39,7 @@ static struct {
jclass clazz;
jmethodID dispatchVsync;
jmethodID dispatchHotplug;
} gDisplayEventReceiverClassInfo;
@@ -61,7 +62,9 @@ private:
bool mWaitingForVsync;
virtual int handleEvent(int receiveFd, int events, void* data);
bool readLastVsyncMessage(nsecs_t* outTimestamp, uint32_t* outCount);
bool readLastVsyncMessage(nsecs_t* outTimestamp, int32_t* id, uint32_t* outCount);
void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count);
void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected);
};
@@ -106,8 +109,9 @@ status_t NativeDisplayEventReceiver::scheduleVsync() {
// Drain all pending events.
nsecs_t vsyncTimestamp;
int32_t vsyncDisplayId;
uint32_t vsyncCount;
readLastVsyncMessage(&vsyncTimestamp, &vsyncCount);
readLastVsyncMessage(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount);
status_t status = mReceiver.requestNextVsync();
if (status) {
@@ -135,39 +139,39 @@ int NativeDisplayEventReceiver::handleEvent(int receiveFd, int events, void* dat
// Drain all pending events, keep the last vsync.
nsecs_t vsyncTimestamp;
int32_t vsyncDisplayId;
uint32_t vsyncCount;
if (!readLastVsyncMessage(&vsyncTimestamp, &vsyncCount)) {
if (!readLastVsyncMessage(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
ALOGV("receiver %p ~ Woke up but there was no vsync pulse!", this);
return 1; // keep the callback, did not obtain a vsync pulse
}
ALOGV("receiver %p ~ Vsync pulse: timestamp=%lld, count=%d",
this, vsyncTimestamp, vsyncCount);
ALOGV("receiver %p ~ Vsync pulse: timestamp=%lld, id=%d, count=%d",
this, vsyncTimestamp, vsyncDisplayId, vsyncCount);
mWaitingForVsync = false;
JNIEnv* env = AndroidRuntime::getJNIEnv();
ALOGV("receiver %p ~ Invoking vsync handler.", this);
env->CallVoidMethod(mReceiverObjGlobal,
gDisplayEventReceiverClassInfo.dispatchVsync, vsyncTimestamp, vsyncCount);
ALOGV("receiver %p ~ Returned from vsync handler.", this);
mMessageQueue->raiseAndClearException(env, "dispatchVsync");
dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
return 1; // keep the callback
}
bool NativeDisplayEventReceiver::readLastVsyncMessage(
nsecs_t* outTimestamp, uint32_t* outCount) {
nsecs_t* outTimestamp, int32_t* outId, uint32_t* outCount) {
DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
ssize_t n;
while ((n = mReceiver.getEvents(buf, EVENT_BUFFER_SIZE)) > 0) {
ALOGV("receiver %p ~ Read %d events.", this, int(n));
while (n-- > 0) {
if (buf[n].header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
*outTimestamp = buf[n].header.timestamp;
*outCount = buf[n].vsync.count;
const DisplayEventReceiver::Event& ev = buf[n];
if (ev.header.type == DisplayEventReceiver::DISPLAY_EVENT_VSYNC) {
*outTimestamp = ev.header.timestamp;
*outId = ev.header.id;
*outCount = ev.vsync.count;
return true; // stop at last vsync in the buffer
}
if (ev.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG) {
dispatchHotplug(ev.header.timestamp, ev.header.id, ev.hotplug.connected);
}
}
}
if (n < 0) {
@@ -176,6 +180,28 @@ bool NativeDisplayEventReceiver::readLastVsyncMessage(
return false;
}
void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
ALOGV("receiver %p ~ Invoking vsync handler.", this);
env->CallVoidMethod(mReceiverObjGlobal,
gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, id, count);
ALOGV("receiver %p ~ Returned from vsync handler.", this);
mMessageQueue->raiseAndClearException(env, "dispatchVsync");
}
void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
ALOGV("receiver %p ~ Invoking hotplug handler.", this);
env->CallVoidMethod(mReceiverObjGlobal,
gDisplayEventReceiverClassInfo.dispatchHotplug, timestamp, id, connected);
ALOGV("receiver %p ~ Returned from hotplug handler.", this);
mMessageQueue->raiseAndClearException(env, "dispatchHotplug");
}
static jint nativeInit(JNIEnv* env, jclass clazz, jobject receiverObj,
jobject messageQueueObj) {
@@ -248,7 +274,10 @@ int register_android_view_DisplayEventReceiver(JNIEnv* env) {
GET_METHOD_ID(gDisplayEventReceiverClassInfo.dispatchVsync,
gDisplayEventReceiverClassInfo.clazz,
"dispatchVsync", "(JI)V");
"dispatchVsync", "(JII)V");
GET_METHOD_ID(gDisplayEventReceiverClassInfo.dispatchHotplug,
gDisplayEventReceiverClassInfo.clazz,
"dispatchHotplug", "(JIZ)V");
return 0;
}

View File

@@ -536,6 +536,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
return;
}
Slog.i(TAG, "Display device added: " + device.getDisplayDeviceInfoLocked());
mDisplayDevices.add(device);
addLogicalDisplayLocked(device);
scheduleTraversalLocked();
@@ -550,6 +552,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
return;
}
Slog.i(TAG, "Display device changed: " + device.getDisplayDeviceInfoLocked());
device.applyPendingDisplayDeviceInfoChangesLocked();
if (updateLogicalDisplaysLocked()) {
scheduleTraversalLocked();
@@ -565,6 +569,8 @@ public final class DisplayManagerService extends IDisplayManager.Stub {
return;
}
Slog.i(TAG, "Display device removed: " + device.getDisplayDeviceInfoLocked());
mRemovedDisplayDevices.add(device);
updateLogicalDisplaysLocked();
scheduleTraversalLocked();

View File

@@ -19,7 +19,9 @@ package com.android.server.display;
import android.content.Context;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.util.SparseArray;
import android.view.DisplayEventReceiver;
import android.view.Surface;
import android.view.Surface.PhysicalDisplayInfo;
@@ -41,12 +43,14 @@ final class LocalDisplayAdapter extends DisplayAdapter {
private final SparseArray<LocalDisplayDevice> mDevices =
new SparseArray<LocalDisplayDevice>();
private final HotplugDisplayEventReceiver mHotplugReceiver;
private final PhysicalDisplayInfo mTempPhys = new PhysicalDisplayInfo();
public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
Context context, Handler handler, Listener listener) {
super(syncRoot, context, handler, listener, TAG);
mHotplugReceiver = new HotplugDisplayEventReceiver(handler.getLooper());
}
@Override
@@ -148,4 +152,17 @@ final class LocalDisplayAdapter extends DisplayAdapter {
pw.println("mPhys=" + mPhys);
}
}
}
private final class HotplugDisplayEventReceiver extends DisplayEventReceiver {
public HotplugDisplayEventReceiver(Looper looper) {
super(looper);
}
@Override
public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) {
synchronized (getSyncRoot()) {
scanDisplaysLocked();
}
}
}
}