Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3ca59713 authored by Jeff Brown's avatar Jeff Brown Committed by Android (Google) Code Review
Browse files

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

parents 063d15ff e87bf030
Loading
Loading
Loading
Loading
+18 −2
Original line number Diff line number Diff line
@@ -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
+23 −3
Original line number Diff line number Diff line
@@ -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);
    }
}
+47 −18
Original line number Diff line number Diff line
@@ -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;
}

+6 −0
Original line number Diff line number Diff line
@@ -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();
+18 −1
Original line number Diff line number Diff line
@@ -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();
            }
        }
    }
}
 No newline at end of file