Merge "Add BufferItemConsumer, a simple BufferQueue consumer." into jb-mr1-dev
diff --git a/include/private/gui/LayerState.h b/include/private/gui/LayerState.h
index 9765e28..65d9eb3 100644
--- a/include/private/gui/LayerState.h
+++ b/include/private/gui/LayerState.h
@@ -107,9 +107,11 @@
     };
 
     enum {
-        eSurfaceChanged     = 0x1,
-        eLayerStackChanged  = 0x2,
-        eTransformChanged   = 0x4
+        eSurfaceChanged     = 0x01,
+        eLayerStackChanged  = 0x02,
+        eOrientationChanged = 0x04,
+        eViewportChanged    = 0x08,
+        eFrameChanged       = 0x10
     };
 
     uint32_t what;
diff --git a/include/utils/SortedVector.h b/include/utils/SortedVector.h
index fd1cb82..2d3e82a 100644
--- a/include/utils/SortedVector.h
+++ b/include/utils/SortedVector.h
@@ -98,8 +98,6 @@
     inline  const TYPE&     itemAt(size_t index) const;
     //! stack-usage of the vector. returns the top of the stack (last element)
             const TYPE&     top() const;
-    //! same as operator [], but allows to access the vector backward (from the end) with a negative index
-            const TYPE&     mirrorItemAt(ssize_t index) const;
 
     /*!
      * modifying the array
@@ -200,15 +198,6 @@
 }
 
 template<class TYPE> inline
-const TYPE& SortedVector<TYPE>::mirrorItemAt(ssize_t index) const {
-    const size_t i = index>0 ? index : -index;
-    LOG_FATAL_IF(index>=size(),
-            "%s: index=%u out of range (%u)", __PRETTY_FUNCTION__,
-            int(index), int(size()));
-    return *(array() + i);
-}
-
-template<class TYPE> inline
 const TYPE& SortedVector<TYPE>::top() const {
     return *(array() + size() - 1);
 }
diff --git a/include/utils/Vector.h b/include/utils/Vector.h
index 506acae..7927328 100644
--- a/include/utils/Vector.h
+++ b/include/utils/Vector.h
@@ -99,8 +99,6 @@
     inline  const TYPE&     itemAt(size_t index) const;
     //! stack-usage of the vector. returns the top of the stack (last element)
             const TYPE&     top() const;
-    //! same as operator [], but allows to access the vector backward (from the end) with a negative index
-            const TYPE&     mirrorItemAt(ssize_t index) const;
 
     /*!
      * modifying the array
@@ -284,15 +282,6 @@
 }
 
 template<class TYPE> inline
-const TYPE& Vector<TYPE>::mirrorItemAt(ssize_t index) const {
-    const size_t i = index>0 ? index : -index;
-    LOG_FATAL_IF(index>=size(),
-            "%s: index=%u out of range (%u)", __PRETTY_FUNCTION__,
-            int(index), int(size()));
-    return *(array() + i);
-}
-
-template<class TYPE> inline
 const TYPE& Vector<TYPE>::top() const {
     return *(array() + size() - 1);
 }
diff --git a/include/utils/VectorImpl.h b/include/utils/VectorImpl.h
index b1224c6..c4ec2ff 100644
--- a/include/utils/VectorImpl.h
+++ b/include/utils/VectorImpl.h
@@ -104,6 +104,16 @@
     virtual void            do_splat(void* dest, const void* item, size_t num) const = 0;
     virtual void            do_move_forward(void* dest, const void* from, size_t num) const = 0;
     virtual void            do_move_backward(void* dest, const void* from, size_t num) const = 0;
+
+    // take care of FBC...
+    virtual void            reservedVectorImpl1();
+    virtual void            reservedVectorImpl2();
+    virtual void            reservedVectorImpl3();
+    virtual void            reservedVectorImpl4();
+    virtual void            reservedVectorImpl5();
+    virtual void            reservedVectorImpl6();
+    virtual void            reservedVectorImpl7();
+    virtual void            reservedVectorImpl8();
     
 private:
         void* _grow(size_t where, size_t amount);
@@ -155,6 +165,16 @@
 protected:
     virtual int             do_compare(const void* lhs, const void* rhs) const = 0;
 
+    // take care of FBC...
+    virtual void            reservedSortedVectorImpl1();
+    virtual void            reservedSortedVectorImpl2();
+    virtual void            reservedSortedVectorImpl3();
+    virtual void            reservedSortedVectorImpl4();
+    virtual void            reservedSortedVectorImpl5();
+    virtual void            reservedSortedVectorImpl6();
+    virtual void            reservedSortedVectorImpl7();
+    virtual void            reservedSortedVectorImpl8();
+
 private:
             ssize_t         _indexOrderOf(const void* item, size_t* order = 0) const;
 
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index db86d4a..1e6e1bd 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -326,7 +326,7 @@
     Mutex::Autolock _l(mLock);
     DisplayState& s(getDisplayStateLocked(token));
     s.orientation = orientation;
-    s.what |= DisplayState::eTransformChanged;
+    s.what |= DisplayState::eOrientationChanged;
     mForceSynchronous = true; // TODO: do we actually still need this?
 }
 
@@ -343,7 +343,7 @@
     Mutex::Autolock _l(mLock);
     DisplayState& s(getDisplayStateLocked(token));
     s.viewport = viewport;
-    s.what |= DisplayState::eTransformChanged;
+    s.what |= DisplayState::eViewportChanged;
 }
 
 void Composer::setDisplayFrame(const sp<IBinder>& token,
@@ -351,7 +351,7 @@
     Mutex::Autolock _l(mLock);
     DisplayState& s(getDisplayStateLocked(token));
     s.frame = frame;
-    s.what |= DisplayState::eTransformChanged;
+    s.what |= DisplayState::eFrameChanged;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index 718fe84..18a0c10 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -815,12 +815,16 @@
         ALOGW_IF(res, "failed locking buffer (handle = %p)",
                 backBuffer->handle);
 
-        mLockedBuffer = backBuffer;
-        outBuffer->width  = backBuffer->width;
-        outBuffer->height = backBuffer->height;
-        outBuffer->stride = backBuffer->stride;
-        outBuffer->format = backBuffer->format;
-        outBuffer->bits   = vaddr;
+        if (res != 0) {
+            err = INVALID_OPERATION;
+        } else {
+            mLockedBuffer = backBuffer;
+            outBuffer->width  = backBuffer->width;
+            outBuffer->height = backBuffer->height;
+            outBuffer->stride = backBuffer->stride;
+            outBuffer->format = backBuffer->format;
+            outBuffer->bits   = vaddr;
+        }
     }
     return err;
 }
diff --git a/libs/utils/VectorImpl.cpp b/libs/utils/VectorImpl.cpp
index 020ec15..3855305 100644
--- a/libs/utils/VectorImpl.cpp
+++ b/libs/utils/VectorImpl.cpp
@@ -494,6 +494,15 @@
     do_move_backward(dest, from, num);
 }
 
+void VectorImpl::reservedVectorImpl1() { }
+void VectorImpl::reservedVectorImpl2() { }
+void VectorImpl::reservedVectorImpl3() { }
+void VectorImpl::reservedVectorImpl4() { }
+void VectorImpl::reservedVectorImpl5() { }
+void VectorImpl::reservedVectorImpl6() { }
+void VectorImpl::reservedVectorImpl7() { }
+void VectorImpl::reservedVectorImpl8() { }
+
 /*****************************************************************************/
 
 SortedVectorImpl::SortedVectorImpl(size_t itemSize, uint32_t flags)
@@ -609,6 +618,16 @@
     return i;
 }
 
+void SortedVectorImpl::reservedSortedVectorImpl1() { };
+void SortedVectorImpl::reservedSortedVectorImpl2() { };
+void SortedVectorImpl::reservedSortedVectorImpl3() { };
+void SortedVectorImpl::reservedSortedVectorImpl4() { };
+void SortedVectorImpl::reservedSortedVectorImpl5() { };
+void SortedVectorImpl::reservedSortedVectorImpl6() { };
+void SortedVectorImpl::reservedSortedVectorImpl7() { };
+void SortedVectorImpl::reservedSortedVectorImpl8() { };
+
+
 /*****************************************************************************/
 
 }; // namespace android
diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp
index c79fb5f..ed2bef3 100644
--- a/opengl/libs/EGL/egl_cache.cpp
+++ b/opengl/libs/EGL/egl_cache.cpp
@@ -241,19 +241,11 @@
         }
 
         size_t fileSize = headerSize + cacheSize;
-        if (ftruncate(fd, fileSize) == -1) {
-            ALOGE("error setting cache file size: %s (%d)", strerror(errno),
-                    errno);
-            close(fd);
-            unlink(fname);
-            return;
-        }
 
-        uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(NULL, fileSize,
-                PROT_WRITE, MAP_SHARED, fd, 0));
-        if (buf == MAP_FAILED) {
-            ALOGE("error mmaping cache file: %s (%d)", strerror(errno),
-                    errno);
+        uint8_t* buf = new uint8_t [fileSize];
+        if (!buf) {
+            ALOGE("error allocating buffer for cache contents: %s (%d)",
+                    strerror(errno), errno);
             close(fd);
             unlink(fname);
             return;
@@ -264,7 +256,7 @@
         if (err != OK) {
             ALOGE("error writing cache contents: %s (%d)", strerror(-err),
                     -err);
-            munmap(buf, fileSize);
+            delete [] buf;
             close(fd);
             unlink(fname);
             return;
@@ -275,7 +267,16 @@
         uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4);
         *crc = crc32c(buf + headerSize, cacheSize);
 
-        munmap(buf, fileSize);
+        if (write(fd, buf, fileSize) == -1) {
+            ALOGE("error writing cache file: %s (%d)", strerror(errno),
+                    errno);
+            delete [] buf;
+            close(fd);
+            unlink(fname);
+            return;
+        }
+
+        delete [] buf;
         fchmod(fd, S_IRUSR);
         close(fd);
     }
diff --git a/opengl/libs/GLES_trace/src/gltrace_context.cpp b/opengl/libs/GLES_trace/src/gltrace_context.cpp
index 91b291e..3a8decc 100644
--- a/opengl/libs/GLES_trace/src/gltrace_context.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace_context.cpp
@@ -209,6 +209,8 @@
 
     GLMessage_Function func = msg->function();
     if (func == GLMessage::eglSwapBuffers
+        || func == GLMessage::eglCreateContext
+        || func == GLMessage::eglMakeCurrent
         || func == GLMessage::glDrawArrays
         || func == GLMessage::glDrawElements) {
         mBufferedOutputStream->flush();
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 4cae692..2289444 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -140,6 +140,9 @@
     mFormat  = format;
     mPageFlipCount = 0;
 
+    // external displays are always considered enabled
+    mScreenAcquired = mId >= DisplayDevice::DISPLAY_ID_COUNT;
+
     // initialize the display orientation transform.
     DisplayDevice::setOrientation(DisplayState::eOrientationDefault);
 }
@@ -215,6 +218,18 @@
     return mSecureLayerVisible;
 }
 
+Region DisplayDevice::getDirtyRegion(bool repaintEverything) const {
+    Region dirty;
+    const Transform& planeTransform(mGlobalTransform);
+    if (repaintEverything) {
+        dirty.set(getBounds());
+    } else {
+        dirty = planeTransform.transform(this->dirtyRegion);
+        dirty.andSelf(getBounds());
+    }
+    return dirty;
+}
+
 // ----------------------------------------------------------------------------
 
 bool DisplayDevice::canDraw() const {
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index e9ba5ff..9790699 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -87,6 +87,7 @@
     void                    setVisibleLayersSortedByZ(const Vector< sp<LayerBase> >& layers);
     Vector< sp<LayerBase> > getVisibleLayersSortedByZ() const;
     bool                    getSecureLayerVisible() const;
+    Region                  getDirtyRegion(bool repaintEverything) const;
 
     status_t                setOrientation(int orientation);
     void                    setLayerStack(uint32_t stack);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index c9df7a4..a3ec352 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -334,7 +334,8 @@
     }
 }
 
-status_t HWComposer::createWorkList(int32_t id, size_t numLayers) { // FIXME: handle multiple displays
+status_t HWComposer::createWorkList(int32_t id, size_t numLayers) {
+    // FIXME: handle multiple displays
     if (uint32_t(id) >= MAX_DISPLAYS)
         return BAD_INDEX;
 
@@ -360,6 +361,15 @@
     int err = hwcPrepare(mHwc, 1,
             const_cast<hwc_display_contents_1_t**>(mLists));
     if (err == NO_ERROR) {
+
+        // here we're just making sure that "skip" layers are set
+        // to HWC_FRAMEBUFFER and we're also counting how many layers
+        // we have of each type.
+        // It would be nice if we could get rid of this entirely, which I
+        // think is almost possible.
+
+        // TODO: must handle multiple displays here
+
         size_t numOVLayers = 0;
         size_t numFBLayers = 0;
         size_t count = getNumLayers(0);
@@ -397,7 +407,15 @@
     return (status_t)err;
 }
 
-size_t HWComposer::getLayerCount(int32_t id, int type) const { // FIXME: handle multiple displays
+size_t HWComposer::getLayerCount(int32_t id, int type) const {
+    // FIXME: handle multiple displays
+    if (uint32_t(id) >= MAX_DISPLAYS) {
+        // FIXME: in practice this is only use to know
+        // if we have at least one layer of type.
+        return (type == HWC_FRAMEBUFFER) ? 1 : 0;
+    }
+
+
     switch (type) {
         case HWC_OVERLAY:
             return mNumOVLayers;
@@ -623,7 +641,11 @@
 /*
  * returns an iterator initialized at a given index in the layer list
  */
-HWComposer::LayerListIterator HWComposer::getLayerIterator(int32_t id, size_t index) { // FIXME: handle multiple displays
+HWComposer::LayerListIterator HWComposer::getLayerIterator(int32_t id, size_t index) {
+    // FIXME: handle multiple displays
+    if (uint32_t(id) >= MAX_DISPLAYS)
+        return LayerListIterator();
+
     if (!mHwc || index > hwcNumHwLayers(mHwc, mLists[0]))
         return LayerListIterator();
     if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
@@ -638,14 +660,14 @@
 /*
  * returns an iterator on the beginning of the layer list
  */
-HWComposer::LayerListIterator HWComposer::begin(int32_t id) { // FIXME: handle multiple displays
+HWComposer::LayerListIterator HWComposer::begin(int32_t id) {
     return getLayerIterator(id, 0);
 }
 
 /*
  * returns an iterator on the end of the layer list
  */
-HWComposer::LayerListIterator HWComposer::end(int32_t id) { // FIXME: handle multiple displays
+HWComposer::LayerListIterator HWComposer::end(int32_t id) {
     return getLayerIterator(id, getNumLayers(id));
 }
 
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index 9b61fa9..59390c0 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -19,6 +19,8 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <cutils/compiler.h>
+
 #include <gui/BitTube.h>
 #include <gui/IDisplayEventConnection.h>
 #include <gui/DisplayEventReceiver.h>
@@ -36,10 +38,9 @@
 
 EventThread::EventThread(const sp<SurfaceFlinger>& flinger)
     : mFlinger(flinger),
-      mLastVSyncTimestamp(0),
       mVSyncTimestamp(0),
       mUseSoftwareVSync(false),
-      mDeliveredEvents(0),
+      mVSyncCount(0),
       mDebugVsyncEnabled(false) {
 }
 
@@ -116,133 +117,121 @@
 void EventThread::onVSyncReceived(int, nsecs_t timestamp) {
     Mutex::Autolock _l(mLock);
     mVSyncTimestamp = timestamp;
+    mVSyncCount++;
     mCondition.broadcast();
 }
 
 bool EventThread::threadLoop() {
 
     nsecs_t timestamp;
+    size_t vsyncCount;
     DisplayEventReceiver::Event vsync;
-    Vector< wp<EventThread::Connection> > displayEventConnections;
+    Vector< sp<EventThread::Connection> > activeConnections;
+    Vector< sp<EventThread::Connection> > signalConnections;
 
     do {
+        // release our references
+        signalConnections.clear();
+        activeConnections.clear();
+
         Mutex::Autolock _l(mLock);
-        do {
-            // latch VSYNC event if any
-            timestamp = mVSyncTimestamp;
-            mVSyncTimestamp = 0;
 
-            // check if we should be waiting for VSYNC events
-            bool waitForNextVsync = false;
-            size_t count = mDisplayEventConnections.size();
-            for (size_t i=0 ; i<count ; i++) {
-                sp<Connection> connection =
-                        mDisplayEventConnections.itemAt(i).promote();
-                if (connection!=0 && connection->count >= 0) {
-                    // at least one continuous mode or active one-shot event
-                    waitForNextVsync = true;
-                    break;
-                }
-            }
+        // latch VSYNC event if any
+        bool waitForVSync = false;
+        vsyncCount = mVSyncCount;
+        timestamp = mVSyncTimestamp;
+        mVSyncTimestamp = 0;
 
-            if (timestamp) {
-                if (!waitForNextVsync) {
-                    // we received a VSYNC but we have no clients
-                    // don't report it, and disable VSYNC events
-                    disableVSyncLocked();
-                } else {
-                    // report VSYNC event
-                    break;
-                }
-            } else {
-                // never disable VSYNC events immediately, instead
-                // we'll wait to receive the event and we'll
-                // reevaluate whether we need to dispatch it and/or
-                // disable VSYNC events then.
-                if (waitForNextVsync) {
-                    // enable
-                    enableVSyncLocked();
-                }
-            }
-
-            // wait for something to happen
-            if (mUseSoftwareVSync && waitForNextVsync) {
-                // h/w vsync cannot be used (screen is off), so we use
-                // a  timeout instead. it doesn't matter how imprecise this
-                // is, we just need to make sure to serve the clients
-                if (mCondition.waitRelative(mLock, ms2ns(16)) == TIMED_OUT) {
-                    mVSyncTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
-                }
-            } else {
-                mCondition.wait(mLock);
-            }
-        } while(true);
-
-        // process vsync event
-        mDeliveredEvents++;
-        mLastVSyncTimestamp = timestamp;
-
-        // now see if we still need to report this VSYNC event
-        const size_t count = mDisplayEventConnections.size();
+        // find out connections waiting for VSYNC events
+        size_t count = mDisplayEventConnections.size();
         for (size_t i=0 ; i<count ; i++) {
-            bool reportVsync = false;
-            sp<Connection> connection =
-                    mDisplayEventConnections.itemAt(i).promote();
-            if (connection == 0)
-                continue;
-
-            const int32_t count = connection->count;
-            if (count >= 1) {
-                if (count==1 || (mDeliveredEvents % count) == 0) {
-                    // continuous event, and time to report it
-                    reportVsync = true;
+            sp<Connection> connection(mDisplayEventConnections[i].promote());
+            if (connection != NULL) {
+                activeConnections.add(connection);
+                if (connection->count >= 0) {
+                    // we need vsync events because at least
+                    // one connection is waiting for it
+                    waitForVSync = true;
+                    if (connection->count == 0) {
+                        // fired this time around
+                        if (timestamp) {
+                            // only "consume" this event if we're going to
+                            // report it
+                            connection->count = -1;
+                        }
+                        signalConnections.add(connection);
+                    } else if (connection->count == 1 ||
+                            (vsyncCount % connection->count) == 0) {
+                        // continuous event, and time to report it
+                        signalConnections.add(connection);
+                    }
                 }
-            } else if (count >= -1) {
-                if (count == 0) {
-                    // fired this time around
-                    reportVsync = true;
-                }
-                connection->count--;
-            }
-            if (reportVsync) {
-                displayEventConnections.add(connection);
             }
         }
-    } while (!displayEventConnections.size());
+
+        if (timestamp) {
+            // we have a vsync event we can dispatch
+            if (!waitForVSync) {
+                // we received a VSYNC but we have no clients
+                // don't report it, and disable VSYNC events
+                disableVSyncLocked();
+            } else {
+                // report VSYNC event
+                break;
+            }
+        } else {
+            // never disable VSYNC events immediately, instead
+            // we'll wait to receive the event and we'll
+            // reevaluate whether we need to dispatch it and/or
+            // disable VSYNC events then.
+            if (waitForVSync) {
+                // enable
+                enableVSyncLocked();
+            }
+        }
+
+        // wait for something to happen
+        if (CC_UNLIKELY(mUseSoftwareVSync && waitForVSync)) {
+            // h/w vsync cannot be used (screen is off), so we use
+            // a  timeout instead. it doesn't matter how imprecise this
+            // is, we just need to make sure to serve the clients
+            if (mCondition.waitRelative(mLock, ms2ns(16)) == TIMED_OUT) {
+                mVSyncTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+                mVSyncCount++;
+            }
+        } else {
+            if (!timestamp || signalConnections.isEmpty()) {
+                // This is where we spend most of our time, waiting
+                // for a vsync events and registered clients
+                mCondition.wait(mLock);
+            }
+        }
+    } while (!timestamp || signalConnections.isEmpty());
 
     // dispatch vsync events to listeners...
     vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
     vsync.header.timestamp = timestamp;
-    vsync.vsync.count = mDeliveredEvents;
+    vsync.vsync.count = vsyncCount;
 
-    const size_t count = displayEventConnections.size();
+    const size_t count = signalConnections.size();
     for (size_t i=0 ; i<count ; i++) {
-        sp<Connection> conn(displayEventConnections[i].promote());
-        // make sure the connection didn't die
-        if (conn != NULL) {
-            status_t err = conn->postEvent(vsync);
-            if (err == -EAGAIN || err == -EWOULDBLOCK) {
-                // The destination doesn't accept events anymore, it's probably
-                // full. For now, we just drop the events on the floor.
-                // Note that some events cannot be dropped and would have to be
-                // re-sent later. Right-now we don't have the ability to do
-                // this, but it doesn't matter for VSYNC.
-            } else if (err < 0) {
-                // handle any other error on the pipe as fatal. the only
-                // reasonable thing to do is to clean-up this connection.
-                // The most common error we'll get here is -EPIPE.
-                removeDisplayEventConnection(displayEventConnections[i]);
-            }
-        } else {
-            // somehow the connection is dead, but we still have it in our list
-            // just clean the list.
-            removeDisplayEventConnection(displayEventConnections[i]);
+        const sp<Connection>& conn(signalConnections[i]);
+        // now see if we still need to report this VSYNC event
+        status_t err = conn->postEvent(vsync);
+        if (err == -EAGAIN || err == -EWOULDBLOCK) {
+            // The destination doesn't accept events anymore, it's probably
+            // full. For now, we just drop the events on the floor.
+            // Note that some events cannot be dropped and would have to be
+            // re-sent later. Right-now we don't have the ability to do
+            // this, but it doesn't matter for VSYNC.
+        } else if (err < 0) {
+            // handle any other error on the pipe as fatal. the only
+            // reasonable thing to do is to clean-up this connection.
+            // The most common error we'll get here is -EPIPE.
+            removeDisplayEventConnection(signalConnections[i]);
         }
     }
 
-    // clear all our references without holding mLock
-    displayEventConnections.clear();
-
     return true;
 }
 
@@ -273,7 +262,7 @@
     result.appendFormat("  soft-vsync: %s\n",
             mUseSoftwareVSync?"enabled":"disabled");
     result.appendFormat("  numListeners=%u,\n  events-delivered: %u\n",
-            mDisplayEventConnections.size(), mDeliveredEvents);
+            mDisplayEventConnections.size(), mVSyncCount);
     for (size_t i=0 ; i<mDisplayEventConnections.size() ; i++) {
         sp<Connection> connection =
                 mDisplayEventConnections.itemAt(i).promote();
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index a71d985..aa0ea7f 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -47,7 +47,6 @@
         // count >= 1 : continuous event. count is the vsync rate
         // count == 0 : one-shot event that has not fired
         // count ==-1 : one-shot event that fired this round / disabled
-        // count ==-2 : one-shot event that fired the round before
         int32_t count;
 
     private:
@@ -100,12 +99,9 @@
 
     // protected by mLock
     SortedVector< wp<Connection> > mDisplayEventConnections;
-    nsecs_t mLastVSyncTimestamp;
     nsecs_t mVSyncTimestamp;
     bool mUseSoftwareVSync;
-
-    // main thread only
-    size_t mDeliveredEvents;
+    size_t mVSyncCount;
 
     // for debugging
     bool mDebugVsyncEnabled;
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index e6189f7..2311e6d 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -426,10 +426,10 @@
 
     snprintf(buffer, SIZE,
             "      "
-            "z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), "
+            "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), "
             "isOpaque=%1d, needsDithering=%1d, invalidate=%1d, "
             "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
-            s.z, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h,
+            s.z, s.layerStack, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h,
             s.active.crop.left, s.active.crop.top,
             s.active.crop.right, s.active.crop.bottom,
             isOpaque(), needsDithering(), contentDirty,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 9178dfc..aba701c 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -95,8 +95,7 @@
         mLastSwapBufferTime(0),
         mDebugInTransaction(0),
         mLastTransactionTime(0),
-        mBootFinished(false),
-        mExternalDisplaySurface(EGL_NO_SURFACE)
+        mBootFinished(false)
 {
     ALOGI("SurfaceFlinger is starting");
 
@@ -138,15 +137,8 @@
 {
     // the window manager died on us. prepare its eulogy.
 
-    // reset screen orientation
-    Vector<ComposerState> state;
-    Vector<DisplayState> displays;
-    DisplayState d;
-    d.what = DisplayState::eTransformChanged;
-    d.token = mDefaultDisplays[DisplayDevice::DISPLAY_ID_MAIN];
-    d.orientation = DisplayState::eOrientationDefault;
-    displays.add(d);
-    setTransactionState(state, displays, 0);
+    // restore initial conditions (default device unblank, etc)
+    initializeDisplays();
 
     // restart the boot-animation
     startBootAnim();
@@ -432,6 +424,9 @@
     // We're now ready to accept clients...
     mReadyToRunBarrier.open();
 
+    // set initial conditions (e.g. unblank default device)
+    initializeDisplays();
+
     // start boot animation
     startBootAnim();
 
@@ -555,40 +550,34 @@
     return mEventThread->createEventConnection();
 }
 
-void SurfaceFlinger::connectDisplay(const sp<ISurfaceTexture> display) {
-    EGLSurface result = EGL_NO_SURFACE;
-    EGLSurface old_surface = EGL_NO_SURFACE;
-    sp<SurfaceTextureClient> stc;
+void SurfaceFlinger::connectDisplay(const sp<ISurfaceTexture> surface) {
 
-    if (display != NULL) {
-        stc = new SurfaceTextureClient(display);
-        result = eglCreateWindowSurface(mEGLDisplay,
-                mEGLConfig, (EGLNativeWindowType)stc.get(), NULL);
-        ALOGE_IF(result == EGL_NO_SURFACE,
-                "eglCreateWindowSurface failed (ISurfaceTexture=%p)",
-                display.get());
+    sp<IBinder> token;
+    { // scope for the lock
+        Mutex::Autolock _l(mStateLock);
+        token = mExtDisplayToken;
+    }
+
+    if (token == 0) {
+        token = createDisplay();
     }
 
     { // scope for the lock
         Mutex::Autolock _l(mStateLock);
-        old_surface = mExternalDisplaySurface;
-        mExternalDisplayNativeWindow = stc;
-        mExternalDisplaySurface = result;
-        ALOGD("mExternalDisplaySurface = %p", result);
-    }
+        if (surface == 0) {
+            // release our current display. we're guarantee to have
+            // a reference to it (token), while we hold the lock
+            mExtDisplayToken = 0;
+        } else {
+            mExtDisplayToken = token;
+        }
 
-    if (old_surface != EGL_NO_SURFACE) {
-        // Note: EGL allows to destroy an object while its current
-        // it will fail to become current next time though.
-        eglDestroySurface(mEGLDisplay, old_surface);
+        DisplayDeviceState& info(mCurrentState.displays.editValueFor(token));
+        info.surface = surface;
+        setTransactionFlags(eDisplayTransactionNeeded);
     }
 }
 
-EGLSurface SurfaceFlinger::getExternalDisplaySurface() const {
-    Mutex::Autolock _l(mStateLock);
-    return mExternalDisplaySurface;
-}
-
 // ----------------------------------------------------------------------------
 
 void SurfaceFlinger::waitForEvent() {
@@ -656,20 +645,101 @@
 }
 
 void SurfaceFlinger::handleMessageInvalidate() {
+    ATRACE_CALL();
     handlePageFlip();
 }
 
 void SurfaceFlinger::handleMessageRefresh() {
-    handleRefresh();
+    ATRACE_CALL();
+    preComposition();
+    rebuildLayerStacks();
+    setUpHWComposer();
+    doDebugFlashRegions();
+    doComposition();
+    postComposition();
+}
 
+void SurfaceFlinger::doDebugFlashRegions()
+{
+    // is debugging enabled
+    if (CC_LIKELY(!mDebugRegion))
+        return;
+
+    const bool repaintEverything = mRepaintEverything;
+    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+        const sp<DisplayDevice>& hw(mDisplays[dpy]);
+        if (hw->canDraw()) {
+            // transform the dirty region into this screen's coordinate space
+            const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
+            if (!dirtyRegion.isEmpty()) {
+                // redraw the whole screen
+                doComposeSurfaces(hw, Region(hw->bounds()));
+
+                // and draw the dirty region
+                glDisable(GL_TEXTURE_EXTERNAL_OES);
+                glDisable(GL_TEXTURE_2D);
+                glDisable(GL_BLEND);
+                glColor4f(1, 0, 1, 1);
+                const int32_t height = hw->getHeight();
+                Region::const_iterator it = dirtyRegion.begin();
+                Region::const_iterator const end = dirtyRegion.end();
+                while (it != end) {
+                    const Rect& r = *it++;
+                    GLfloat vertices[][2] = {
+                            { r.left,  height - r.top },
+                            { r.left,  height - r.bottom },
+                            { r.right, height - r.bottom },
+                            { r.right, height - r.top }
+                    };
+                    glVertexPointer(2, GL_FLOAT, 0, vertices);
+                    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+                }
+                hw->compositionComplete();
+                // FIXME
+                if (hw->getDisplayId() >= DisplayDevice::DISPLAY_ID_COUNT) {
+                    eglSwapBuffers(mEGLDisplay, hw->getEGLSurface());
+                }
+            }
+        }
+    }
+
+    postFramebuffer();
+
+    if (mDebugRegion > 1) {
+        usleep(mDebugRegion * 1000);
+    }
+}
+
+void SurfaceFlinger::preComposition()
+{
+    bool needExtraInvalidate = false;
+    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
+    const size_t count = currentLayers.size();
+    for (size_t i=0 ; i<count ; i++) {
+        if (currentLayers[i]->onPreComposition()) {
+            needExtraInvalidate = true;
+        }
+    }
+    if (needExtraInvalidate) {
+        signalLayerUpdate();
+    }
+}
+
+void SurfaceFlinger::postComposition()
+{
+    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
+    const size_t count = currentLayers.size();
+    for (size_t i=0 ; i<count ; i++) {
+        currentLayers[i]->onPostComposition();
+    }
+}
+
+void SurfaceFlinger::rebuildLayerStacks() {
+    // rebuild the visible layer list per screen
     if (CC_UNLIKELY(mVisibleRegionsDirty)) {
+        ATRACE_CALL();
         mVisibleRegionsDirty = false;
         invalidateHwcGeometry();
-
-        /*
-         *  rebuild the visible layer list per screen
-         */
-
         const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
         for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
             const sp<DisplayDevice>& hw(mDisplays[dpy]);
@@ -691,10 +761,13 @@
             }
             hw->setVisibleLayersSortedByZ(layersSortedByZ);
             hw->undefinedRegion.set(hw->getBounds());
-            hw->undefinedRegion.subtractSelf(hw->getTransform().transform(opaqueRegion));
+            hw->undefinedRegion.subtractSelf(
+                    hw->getTransform().transform(opaqueRegion));
         }
     }
+}
 
+void SurfaceFlinger::setUpHWComposer() {
     HWComposer& hwc(getHwComposer());
     if (hwc.initCheck() == NO_ERROR) {
         // build the h/w work list
@@ -702,7 +775,8 @@
         mHwWorkListDirty = false;
         for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
             sp<const DisplayDevice> hw(mDisplays[dpy]);
-            const Vector< sp<LayerBase> >& currentLayers(hw->getVisibleLayersSortedByZ());
+            const Vector< sp<LayerBase> >& currentLayers(
+                    hw->getVisibleLayersSortedByZ());
             const size_t count = currentLayers.size();
 
             const int32_t id = hw->getDisplayId();
@@ -730,76 +804,28 @@
         status_t err = hwc.prepare();
         ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
     }
+}
 
+void SurfaceFlinger::doComposition() {
+    ATRACE_CALL();
     const bool repaintEverything = android_atomic_and(0, &mRepaintEverything);
     for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
         const sp<DisplayDevice>& hw(mDisplays[dpy]);
-
-        // transform the dirty region into this screen's coordinate space
-        const Transform& planeTransform(hw->getTransform());
-        Region dirtyRegion;
-        if (repaintEverything) {
-            dirtyRegion.set(hw->bounds());
-        } else {
-            dirtyRegion = planeTransform.transform(hw->dirtyRegion);
-            dirtyRegion.andSelf(hw->bounds());
-        }
-        hw->dirtyRegion.clear();
-
-        if (!dirtyRegion.isEmpty()) {
-            if (hw->canDraw()) {
+        if (hw->canDraw()) {
+            // transform the dirty region into this screen's coordinate space
+            const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
+            if (!dirtyRegion.isEmpty()) {
                 // repaint the framebuffer (if needed)
-                handleRepaint(hw, dirtyRegion);
+                doDisplayComposition(hw, dirtyRegion);
             }
+            hw->dirtyRegion.clear();
+            hw->flip(hw->swapRegion);
+            hw->swapRegion.clear();
         }
         // inform the h/w that we're done compositing
         hw->compositionComplete();
     }
-
     postFramebuffer();
-
-
-#if 1
-    // render to the external display if we have one
-    EGLSurface externalDisplaySurface = getExternalDisplaySurface();
-    if (externalDisplaySurface != EGL_NO_SURFACE) {
-        EGLSurface cur = eglGetCurrentSurface(EGL_DRAW);
-        EGLBoolean success = eglMakeCurrent(eglGetCurrentDisplay(),
-                externalDisplaySurface, externalDisplaySurface,
-                eglGetCurrentContext());
-
-        ALOGE_IF(!success, "eglMakeCurrent -> external failed");
-
-        if (success) {
-            // redraw the screen entirely...
-            glDisable(GL_TEXTURE_EXTERNAL_OES);
-            glDisable(GL_TEXTURE_2D);
-            glClearColor(0,0,0,1);
-            glClear(GL_COLOR_BUFFER_BIT);
-            glMatrixMode(GL_MODELVIEW);
-            glLoadIdentity();
-
-            const sp<DisplayDevice>& hw(getDisplayDevice(0));
-            const Vector< sp<LayerBase> >& layers( hw->getVisibleLayersSortedByZ() );
-            const size_t count = layers.size();
-            for (size_t i=0 ; i<count ; ++i) {
-                const sp<LayerBase>& layer(layers[i]);
-                layer->draw(hw);
-            }
-
-            success = eglSwapBuffers(eglGetCurrentDisplay(), externalDisplaySurface);
-            ALOGE_IF(!success, "external display eglSwapBuffers failed");
-
-            hw->compositionComplete();
-        }
-
-        success = eglMakeCurrent(eglGetCurrentDisplay(),
-                cur, cur, eglGetCurrentContext());
-
-        ALOGE_IF(!success, "eglMakeCurrent -> internal failed");
-    }
-#endif
-
 }
 
 void SurfaceFlinger::postFramebuffer()
@@ -810,26 +836,13 @@
     mDebugInSwapBuffers = now;
 
     HWComposer& hwc(getHwComposer());
-
-    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
-        const sp<DisplayDevice>& hw(mDisplays[dpy]);
-        if (hwc.initCheck() == NO_ERROR) {
-            const Vector< sp<LayerBase> >& currentLayers(hw->getVisibleLayersSortedByZ());
-            const size_t count = currentLayers.size();
-            const int32_t id = hw->getDisplayId();
-            HWComposer::LayerListIterator cur = hwc.begin(id);
-            const HWComposer::LayerListIterator end = hwc.end(id);
-            for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
-                const sp<LayerBase>& layer(currentLayers[i]);
-                layer->setAcquireFence(hw, *cur);
-            }
-        }
-        hw->flip(hw->swapRegion);
-        hw->swapRegion.clear();
-    }
-
     if (hwc.initCheck() == NO_ERROR) {
         // FIXME: eventually commit() won't take arguments
+        // FIXME: EGL spec says:
+        //   "surface must be bound to the calling thread's current context,
+        //    for the current rendering API."
+        DisplayDevice::makeCurrent(
+                getDisplayDevice(DisplayDevice::DISPLAY_ID_MAIN), mEGLContext);
         hwc.commit(mEGLDisplay, getDefaultDisplayDevice()->getEGLSurface());
     }
 
@@ -845,13 +858,10 @@
                 currentLayers[i]->onLayerDisplayed(hw, &*cur);
             }
         } else {
-            eglSwapBuffers(mEGLDisplay, hw->getEGLSurface());
             for (size_t i = 0; i < count; i++) {
                 currentLayers[i]->onLayerDisplayed(hw, NULL);
             }
         }
-
-        // FIXME: we need to call eglSwapBuffers() on displays that have GL composition
     }
 
     mLastSwapBufferTime = systemTime() - now;
@@ -934,7 +944,7 @@
                 } else {
                     // this display is in both lists. see if something changed.
                     const DisplayDeviceState& state(curr[j]);
-                    if (state.surface != draw[i].surface) {
+                    if (state.surface->asBinder() != draw[i].surface->asBinder()) {
                         // changing the surface is like destroying and
                         // recreating the DisplayDevice
 
@@ -967,7 +977,6 @@
             // (ie: in current state but not in drawing state)
             for (size_t i=0 ; i<cc ; i++) {
                 if (draw.indexOfKey(curr.keyAt(i)) < 0) {
-                    // FIXME: we need to pass the surface here
                     const DisplayDeviceState& state(curr[i]);
                     sp<SurfaceTextureClient> stc(
                             new SurfaceTextureClient(state.surface));
@@ -983,7 +992,8 @@
      * Perform our own transaction if needed
      */
 
-    if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {
+    const LayerVector& previousLayers(mDrawingState.layersSortedByZ);
+    if (currentLayers.size() > previousLayers.size()) {
         // layers have been added
         mVisibleRegionsDirty = true;
     }
@@ -993,7 +1003,6 @@
     if (mLayersRemoved) {
         mLayersRemoved = false;
         mVisibleRegionsDirty = true;
-        const LayerVector& previousLayers(mDrawingState.layersSortedByZ);
         const size_t count = previousLayers.size();
         for (size_t i=0 ; i<count ; i++) {
             const sp<LayerBase>& layer(previousLayers[i]);
@@ -1169,16 +1178,13 @@
 
 void SurfaceFlinger::handlePageFlip()
 {
-    ATRACE_CALL();
     Region dirtyRegion;
 
-    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
-
     bool visibleRegions = false;
+    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
     const size_t count = currentLayers.size();
-    sp<LayerBase> const* layers = currentLayers.array();
     for (size_t i=0 ; i<count ; i++) {
-        const sp<LayerBase>& layer(layers[i]);
+        const sp<LayerBase>& layer(currentLayers[i]);
         const Region dirty(layer->latchBuffer(visibleRegions));
         Layer::State s(layer->drawingState());
         invalidateLayerStack(s.layerStack, dirty);
@@ -1192,36 +1198,15 @@
     mHwWorkListDirty = true;
 }
 
-void SurfaceFlinger::handleRefresh()
-{
-    bool needInvalidate = false;
-    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
-    const size_t count = currentLayers.size();
-    for (size_t i=0 ; i<count ; i++) {
-        const sp<LayerBase>& layer(currentLayers[i]);
-        if (layer->onPreComposition()) {
-            needInvalidate = true;
-        }
-    }
-    if (needInvalidate) {
-        signalLayerUpdate();
-    }
-}
 
-void SurfaceFlinger::handleRepaint(const sp<const DisplayDevice>& hw,
+void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw,
         const Region& inDirtyRegion)
 {
-    ATRACE_CALL();
-
     Region dirtyRegion(inDirtyRegion);
 
     // compute the invalid region
     hw->swapRegion.orSelf(dirtyRegion);
 
-    if (CC_UNLIKELY(mDebugRegion)) {
-        debugFlashRegions(hw, dirtyRegion);
-    }
-
     uint32_t flags = hw->getFlags();
     if (flags & DisplayDevice::SWAP_RECTANGLE) {
         // we can redraw only what's dirty, but since SWAP_RECTANGLE only
@@ -1242,19 +1227,24 @@
         }
     }
 
-    composeSurfaces(hw, dirtyRegion);
+    doComposeSurfaces(hw, dirtyRegion);
 
-    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
-    const size_t count = currentLayers.size();
-    for (size_t i=0 ; i<count ; i++) {
-        currentLayers[i]->onPostComposition();
+    // FIXME: we need to call eglSwapBuffers() on displays that have
+    // GL composition and only on those.
+    // however, currently hwc.commit() already does that for the main
+    // display and never for the other ones
+    if (hw->getDisplayId() >= DisplayDevice::DISPLAY_ID_COUNT) {
+        // FIXME: EGL spec says:
+        //   "surface must be bound to the calling thread's current context,
+        //    for the current rendering API."
+        eglSwapBuffers(mEGLDisplay, hw->getEGLSurface());
     }
 
     // update the swap region and clear the dirty region
     hw->swapRegion.orSelf(dirtyRegion);
 }
 
-void SurfaceFlinger::composeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty)
+void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty)
 {
     HWComposer& hwc(getHwComposer());
     int32_t id = hw->getDisplayId();
@@ -1298,74 +1288,32 @@
         for (size_t i=0 ; i<count ; ++i) {
             const sp<LayerBase>& layer(layers[i]);
             const Region clip(dirty.intersect(tr.transform(layer->visibleRegion)));
-            if (!clip.isEmpty()) {
-                if (cur != end && cur->getCompositionType() == HWC_OVERLAY) {
-                    if (i && (cur->getHints() & HWC_HINT_CLEAR_FB)
-                            && layer->isOpaque()) {
-                        // never clear the very first layer since we're
-                        // guaranteed the FB is already cleared
-                        layer->clearWithOpenGL(hw, clip);
-                    }
-                    ++cur;
-                    continue;
-                }
-                // render the layer
-                layer->draw(hw, clip);
-            }
             if (cur != end) {
+                // we're using h/w composer
+                if (!clip.isEmpty()) {
+                    if (cur->getCompositionType() == HWC_OVERLAY) {
+                        if (i && (cur->getHints() & HWC_HINT_CLEAR_FB)
+                                && layer->isOpaque()) {
+                            // never clear the very first layer since we're
+                            // guaranteed the FB is already cleared
+                            layer->clearWithOpenGL(hw, clip);
+                        }
+                    } else {
+                        layer->draw(hw, clip);
+                    }
+                    layer->setAcquireFence(hw, *cur);
+                }
                 ++cur;
+            } else {
+                // we're not using h/w composer
+                if (!clip.isEmpty()) {
+                    layer->draw(hw, clip);
+                }
             }
         }
     }
 }
 
-void SurfaceFlinger::debugFlashRegions(const sp<const DisplayDevice>& hw,
-        const Region& dirtyRegion)
-{
-    const uint32_t flags = hw->getFlags();
-    const int32_t height = hw->getHeight();
-    if (hw->swapRegion.isEmpty()) {
-        return;
-    }
-
-    if (!(flags & DisplayDevice::SWAP_RECTANGLE)) {
-        const Region repaint((flags & DisplayDevice::PARTIAL_UPDATES) ?
-                dirtyRegion.bounds() : hw->bounds());
-        composeSurfaces(hw, repaint);
-    }
-
-    glDisable(GL_TEXTURE_EXTERNAL_OES);
-    glDisable(GL_TEXTURE_2D);
-    glDisable(GL_BLEND);
-
-    static int toggle = 0;
-    toggle = 1 - toggle;
-    if (toggle) {
-        glColor4f(1, 0, 1, 1);
-    } else {
-        glColor4f(1, 1, 0, 1);
-    }
-
-    Region::const_iterator it = dirtyRegion.begin();
-    Region::const_iterator const end = dirtyRegion.end();
-    while (it != end) {
-        const Rect& r = *it++;
-        GLfloat vertices[][2] = {
-                { r.left,  height - r.top },
-                { r.left,  height - r.bottom },
-                { r.right, height - r.bottom },
-                { r.right, height - r.top }
-        };
-        glVertexPointer(2, GL_FLOAT, 0, vertices);
-        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-    }
-
-    hw->flip(hw->swapRegion);
-
-    if (mDebugRegion > 1)
-        usleep(mDebugRegion * 1000);
-}
-
 void SurfaceFlinger::drawWormhole(const Region& region) const
 {
     glDisable(GL_TEXTURE_EXTERNAL_OES);
@@ -1521,15 +1469,19 @@
                 flags |= eDisplayTransactionNeeded;
             }
         }
-        if (what & DisplayState::eTransformChanged) {
+        if (what & DisplayState::eOrientationChanged) {
             if (disp.orientation != s.orientation) {
                 disp.orientation = s.orientation;
                 flags |= eDisplayTransactionNeeded;
             }
+        }
+        if (what & DisplayState::eFrameChanged) {
             if (disp.frame != s.frame) {
                 disp.frame = s.frame;
                 flags |= eDisplayTransactionNeeded;
             }
+        }
+        if (what & DisplayState::eViewportChanged) {
             if (disp.viewport != s.viewport) {
                 disp.viewport = s.viewport;
                 flags |= eDisplayTransactionNeeded;
@@ -1745,6 +1697,36 @@
 
 // ---------------------------------------------------------------------------
 
+void SurfaceFlinger::onInitializeDisplays() {
+    // reset screen orientation
+    Vector<ComposerState> state;
+    Vector<DisplayState> displays;
+    DisplayState d;
+    d.what = DisplayState::eOrientationChanged;
+    d.token = mDefaultDisplays[DisplayDevice::DISPLAY_ID_MAIN];
+    d.orientation = DisplayState::eOrientationDefault;
+    displays.add(d);
+    setTransactionState(state, displays, 0);
+
+    // XXX: this should init default device to "unblank" and all other devices to "blank"
+    onScreenAcquired();
+}
+
+void SurfaceFlinger::initializeDisplays() {
+    class MessageScreenInitialized : public MessageBase {
+        SurfaceFlinger* flinger;
+    public:
+        MessageScreenInitialized(SurfaceFlinger* flinger) : flinger(flinger) { }
+        virtual bool handler() {
+            flinger->onInitializeDisplays();
+            return true;
+        }
+    };
+    sp<MessageBase> msg = new MessageScreenInitialized(this);
+    postMessageAsync(msg);  // we may be called from main thread, use async message
+}
+
+
 void SurfaceFlinger::onScreenAcquired() {
     ALOGD("Screen about to return, flinger = %p", this);
     sp<const DisplayDevice> hw(getDefaultDisplayDevice()); // XXX: this should be per DisplayDevice
@@ -1951,6 +1933,26 @@
     }
 
     /*
+     * Dump Display state
+     */
+
+    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+        const sp<const DisplayDevice>& hw(mDisplays[dpy]);
+        snprintf(buffer, SIZE,
+                "+ DisplayDevice[%u]\n"
+                "   id=%x, layerStack=%u, (%4dx%4d), orient=%2d, tr=%08x, "
+                "flips=%u, secure=%d, numLayers=%u\n",
+                dpy,
+                hw->getDisplayId(), hw->getLayerStack(),
+                hw->getWidth(), hw->getHeight(),
+                hw->getOrientation(), hw->getTransform().getType(),
+                hw->getPageFlipCount(),
+                hw->getSecureLayerVisible(),
+                hw->getVisibleLayersSortedByZ().size());
+        result.append(buffer);
+    }
+
+    /*
      * Dump SurfaceFlinger global state
      */
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6438bee..b1fe738 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -231,9 +231,11 @@
     void signalLayerUpdate();
     void signalRefresh();
 
-    // called on the main thread in response to screenReleased()
+    // called on the main thread in response to initializeDisplays()
+    void onInitializeDisplays();
+    // called on the main thread in response to blank()
     void onScreenReleased();
-    // called on the main thread in response to screenAcquired()
+    // called on the main thread in response to unblank()
     void onScreenAcquired();
 
     void handleMessageTransaction();
@@ -248,9 +250,6 @@
      */
     void handlePageFlip();
 
-    void handleRefresh();
-    void handleRepaint(const sp<const DisplayDevice>& hw, const Region& dirtyRegion);
-
     /* ------------------------------------------------------------------------
      * Transactions
      */
@@ -324,6 +323,9 @@
     /* ------------------------------------------------------------------------
      * Display and layer stack management
      */
+    // called when starting, or restarting after system_server death
+    void initializeDisplays();
+
     sp<const DisplayDevice> getDisplayDevice(DisplayID dpy) const {
         return mDisplays.valueFor(dpy);
     }
@@ -348,8 +350,19 @@
     void computeVisibleRegions(const LayerVector& currentLayers,
             uint32_t layerStack,
             Region& dirtyRegion, Region& opaqueRegion);
+
+    void preComposition();
+    void postComposition();
+    void rebuildLayerStacks();
+    void setUpHWComposer();
+    void doComposition();
+    void doDebugFlashRegions();
+    void doDisplayComposition(const sp<const DisplayDevice>& hw,
+            const Region& dirtyRegion);
+    void doComposeSurfaces(const sp<const DisplayDevice>& hw,
+            const Region& dirty);
+
     void postFramebuffer();
-    void composeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty);
     void drawWormhole(const Region& region) const;
     GLuint getProtectedTexName() const {
         return mProtectedTexName;
@@ -358,7 +371,6 @@
     /* ------------------------------------------------------------------------
      * Debugging & dumpsys
      */
-    void debugFlashRegions(const sp<const DisplayDevice>& hw, const Region& dirtyReg);
     void listLayersLocked(const Vector<String16>& args, size_t& index,
         String8& result, char* buffer, size_t SIZE) const;
     void dumpStatsLocked(const Vector<String16>& args, size_t& index,
@@ -428,9 +440,7 @@
      * Feature prototyping
      */
 
-    EGLSurface getExternalDisplaySurface() const;
-    sp<SurfaceTextureClient> mExternalDisplayNativeWindow;
-    EGLSurface mExternalDisplaySurface;
+    sp<IBinder> mExtDisplayToken;
 };
 
 // ---------------------------------------------------------------------------