Merge "Watch for SurfaceFlinger death" into jb-mr1-dev
diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c
index da00846..cfd7483 100644
--- a/cmds/dumpstate/utils.c
+++ b/cmds/dumpstate/utils.c
@@ -41,6 +41,7 @@
 
 /* list of native processes to include in the native dumps */
 static const char* native_processes_to_dump[] = {
+        "/system/bin/drmserver",
         "/system/bin/mediaserver",
         "/system/bin/sdcard",
         "/system/bin/surfaceflinger",
diff --git a/include/gui/ConsumerBase.h b/include/gui/ConsumerBase.h
index a0ddca8..68cce5a 100644
--- a/include/gui/ConsumerBase.h
+++ b/include/gui/ConsumerBase.h
@@ -152,7 +152,14 @@
     // it is overridden the derived class's implementation must call
     // ConsumerBase::acquireBufferLocked.
     virtual status_t releaseBufferLocked(int buf, EGLDisplay display,
-           EGLSyncKHR eglFence, const sp<Fence>& fence);
+           EGLSyncKHR eglFence);
+
+    // addReleaseFence adds the sync points associated with a fence to the set
+    // of sync points that must be reached before the buffer in the given slot
+    // may be used after the slot has been released.  This should be called by
+    // derived classes each time some asynchronous work is kicked off that
+    // references the buffer.
+    status_t addReleaseFence(int slot, const sp<Fence>& fence);
 
     // Slot contains the information and object references that
     // ConsumerBase maintains about a BufferQueue buffer slot.
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 2570cd9..6e5a478 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -77,6 +77,9 @@
     //
     // This call may only be made while the OpenGL ES context to which the
     // target texture belongs is bound to the calling thread.
+    //
+    // After calling this method the doGLFenceWait method must be called
+    // before issuing OpenGL ES commands that access the texture contents.
     status_t updateTexImage();
 
     // setReleaseFence stores a fence file descriptor that will signal when the
@@ -154,6 +157,12 @@
     // ready to be read from.
     sp<Fence> getCurrentFence() const;
 
+    // doGLFenceWait inserts a wait command into the OpenGL ES command stream
+    // to ensure that it is safe for future OpenGL ES commands to access the
+    // current texture buffer.  This must be called each time updateTexImage
+    // is called before issuing OpenGL ES commands that access the texture.
+    status_t doGLFenceWait() const;
+
     // isSynchronousMode returns whether the SurfaceTexture is currently in
     // synchronous mode.
     bool isSynchronousMode() const;
@@ -220,7 +229,7 @@
     // releaseBufferLocked overrides the ConsumerBase method to update the
     // mEglSlots array in addition to the ConsumerBase.
     virtual status_t releaseBufferLocked(int buf, EGLDisplay display,
-           EGLSyncKHR eglFence, const sp<Fence>& fence);
+           EGLSyncKHR eglFence);
 
     static bool isExternalFormat(uint32_t format);
 
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index 57df39c..74b684f 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -82,8 +82,10 @@
 
     Mutex::Autolock _l(mMutex);
 
+    err = addReleaseFence(item.mBuf, releaseFence);
+
     err = releaseBufferLocked(item.mBuf, EGL_NO_DISPLAY,
-            EGL_NO_SYNC_KHR, releaseFence);
+            EGL_NO_SYNC_KHR);
     if (err != OK) {
         BI_LOGE("Failed to release buffer: %s (%d)",
                 strerror(-err), err);
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 17bbfd1..fd2d1cc 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -185,15 +185,40 @@
         mSlots[item->mBuf].mGraphicBuffer = item->mGraphicBuffer;
     }
 
+    mSlots[item->mBuf].mFence = item->mFence;
+
     CB_LOGV("acquireBufferLocked: -> slot=%d", item->mBuf);
 
     return OK;
 }
 
+status_t ConsumerBase::addReleaseFence(int slot, const sp<Fence>& fence) {
+    CB_LOGV("addReleaseFence: slot=%d", slot);
+
+    if (!mSlots[slot].mFence.get()) {
+        mSlots[slot].mFence = fence;
+    } else {
+        sp<Fence> mergedFence = Fence::merge(
+                String8("ConsumerBase merged release"),
+                mSlots[slot].mFence, fence);
+        if (!mergedFence.get()) {
+            CB_LOGE("failed to merge release fences");
+            // synchronization is broken, the best we can do is hope fences
+            // signal in order so the new fence will act like a union
+            mSlots[slot].mFence = fence;
+            return BAD_VALUE;
+        }
+        mSlots[slot].mFence = mergedFence;
+    }
+
+    return OK;
+}
+
 status_t ConsumerBase::releaseBufferLocked(int slot, EGLDisplay display,
-       EGLSyncKHR eglFence, const sp<Fence>& fence) {
+       EGLSyncKHR eglFence) {
     CB_LOGV("releaseBufferLocked: slot=%d", slot);
-    status_t err = mBufferQueue->releaseBuffer(slot, display, eglFence, fence);
+    status_t err = mBufferQueue->releaseBuffer(slot, display, eglFence,
+            mSlots[slot].mFence);
     if (err == BufferQueue::STALE_BUFFER_SLOT) {
         freeBufferLocked(slot);
     }
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index fc4a854..e1a2838 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -134,7 +134,7 @@
         CC_LOGE("%s: Unable to unlock graphic buffer %d", __FUNCTION__, slotIndex);
         return err;
     }
-    releaseBufferLocked(slotIndex, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE);
+    releaseBufferLocked(slotIndex, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
 
     mCurrentLockedBuffers--;
 
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 975eb23..36a2af7 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -39,6 +39,30 @@
 #include <utils/String8.h>
 #include <utils/Trace.h>
 
+// This compile option makes SurfaceTexture use the
+// EGL_ANDROID_native_fence_sync extension to create Android native fences to
+// signal when all GLES reads for a given buffer have completed.  It is not
+// compatible with using the EGL_KHR_fence_sync extension for the same
+// purpose.
+#ifdef USE_NATIVE_FENCE_SYNC
+#ifdef USE_FENCE_SYNC
+#error "USE_NATIVE_FENCE_SYNC and USE_FENCE_SYNC are incompatible"
+#endif
+static const bool useNativeFenceSync = true;
+#else
+static const bool useNativeFenceSync = false;
+#endif
+
+// This compile option makes SurfaceTexture use the EGL_ANDROID_sync_wait
+// extension to insert server-side waits into the GLES command stream.  This
+// feature requires the EGL_ANDROID_native_fence_sync and
+// EGL_ANDROID_wait_sync extensions.
+#ifdef USE_WAIT_SYNC
+static const bool useWaitSync = true;
+#else
+static const bool useWaitSync = false;
+#endif
+
 // This compile option makes SurfaceTexture use the EGL_KHR_fence_sync extension
 // to synchronize access to the buffers.  It will cause dequeueBuffer to stall,
 // waiting for the GL reads for the buffer being dequeued to complete before
@@ -172,9 +196,9 @@
 }
 
 status_t SurfaceTexture::releaseBufferLocked(int buf, EGLDisplay display,
-       EGLSyncKHR eglFence, const sp<Fence>& fence) {
+       EGLSyncKHR eglFence) {
     status_t err = ConsumerBase::releaseBufferLocked(buf, mEglDisplay,
-           eglFence, fence);
+           eglFence);
 
     mEglSlots[mCurrentTexture].mEglFence = EGL_NO_SYNC_KHR;
 
@@ -229,7 +253,7 @@
         // not accept this buffer. this is used by SurfaceFlinger to
         // reject buffers which have the wrong size
         if (rejecter && rejecter->reject(mSlots[buf].mGraphicBuffer, item)) {
-            releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR, item.mFence);
+            releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR);
             glBindTexture(mTexTarget, mTexName);
             return NO_ERROR;
         }
@@ -256,7 +280,7 @@
         if (err != NO_ERROR) {
             // Release the buffer we just acquired.  It's not safe to
             // release the old buffer, so instead we just drop the new frame.
-            releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR, item.mFence);
+            releaseBufferLocked(buf, dpy, EGL_NO_SYNC_KHR);
             return err;
         }
 
@@ -268,8 +292,7 @@
         // release old buffer
         if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
             status_t status = releaseBufferLocked(mCurrentTexture, dpy,
-                    mEglSlots[mCurrentTexture].mEglFence,
-                    mSlots[mCurrentTexture].mFence);
+                    mEglSlots[mCurrentTexture].mEglFence);
             if (status != NO_ERROR && status != BufferQueue::STALE_BUFFER_SLOT) {
                 ST_LOGE("updateTexImage: failed to release buffer: %s (%d)",
                        strerror(-status), status);
@@ -304,20 +327,10 @@
     sp<Fence> fence(new Fence(fenceFd));
     if (fenceFd == -1 || mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT)
         return;
-    if (!mSlots[mCurrentTexture].mFence.get()) {
-        mSlots[mCurrentTexture].mFence = fence;
-    } else {
-        sp<Fence> mergedFence = Fence::merge(
-                String8("SurfaceTexture merged release"),
-                mSlots[mCurrentTexture].mFence, fence);
-        if (!mergedFence.get()) {
-            ST_LOGE("failed to merge release fences");
-            // synchronization is broken, the best we can do is hope fences
-            // signal in order so the new fence will act like a union
-            mSlots[mCurrentTexture].mFence = fence;
-            return;
-        }
-        mSlots[mCurrentTexture].mFence = mergedFence;
+    status_t err = addReleaseFence(mCurrentTexture, fence);
+    if (err != OK) {
+        ST_LOGE("setReleaseFence: failed to add the fence: %s (%d)",
+                strerror(-err), err);
     }
 }
 
@@ -454,36 +467,61 @@
 status_t SurfaceTexture::syncForReleaseLocked(EGLDisplay dpy) {
     ST_LOGV("syncForReleaseLocked");
 
-    if (mUseFenceSync && mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
-        EGLSyncKHR fence = mEglSlots[mCurrentTexture].mEglFence;
-        if (fence != EGL_NO_SYNC_KHR) {
-            // There is already a fence for the current slot.  We need to wait
-            // on that before replacing it with another fence to ensure that all
-            // outstanding buffer accesses have completed before the producer
-            // accesses it.
-            EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
-            if (result == EGL_FALSE) {
-                ST_LOGE("syncForReleaseLocked: error waiting for previous "
-                        "fence: %#x", eglGetError());
+    if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
+        if (useNativeFenceSync) {
+            EGLSyncKHR sync = eglCreateSyncKHR(dpy,
+                    EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
+            if (sync == EGL_NO_SYNC_KHR) {
+                ST_LOGE("syncForReleaseLocked: error creating EGL fence: %#x",
+                        eglGetError());
                 return UNKNOWN_ERROR;
-            } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
-                ST_LOGE("syncForReleaseLocked: timeout waiting for previous "
-                        "fence");
-                return TIMED_OUT;
             }
-            eglDestroySyncKHR(dpy, fence);
-        }
+            glFlush();
+            int fenceFd = eglDupNativeFenceFDANDROID(dpy, sync);
+            eglDestroySyncKHR(dpy, sync);
+            if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+                ST_LOGE("syncForReleaseLocked: error dup'ing native fence "
+                        "fd: %#x", eglGetError());
+                return UNKNOWN_ERROR;
+            }
+            sp<Fence> fence(new Fence(fenceFd));
+            status_t err = addReleaseFence(mCurrentTexture, fence);
+            if (err != OK) {
+                ST_LOGE("syncForReleaseLocked: error adding release fence: "
+                        "%s (%d)", strerror(-err), err);
+                return err;
+            }
+        } else if (mUseFenceSync) {
+            EGLSyncKHR fence = mEglSlots[mCurrentTexture].mEglFence;
+            if (fence != EGL_NO_SYNC_KHR) {
+                // There is already a fence for the current slot.  We need to
+                // wait on that before replacing it with another fence to
+                // ensure that all outstanding buffer accesses have completed
+                // before the producer accesses it.
+                EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
+                if (result == EGL_FALSE) {
+                    ST_LOGE("syncForReleaseLocked: error waiting for previous "
+                            "fence: %#x", eglGetError());
+                    return UNKNOWN_ERROR;
+                } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+                    ST_LOGE("syncForReleaseLocked: timeout waiting for previous "
+                            "fence");
+                    return TIMED_OUT;
+                }
+                eglDestroySyncKHR(dpy, fence);
+            }
 
-        // Create a fence for the outstanding accesses in the current OpenGL ES
-        // context.
-        fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
-        if (fence == EGL_NO_SYNC_KHR) {
-            ST_LOGE("syncForReleaseLocked: error creating fence: %#x",
-                    eglGetError());
-            return UNKNOWN_ERROR;
+            // Create a fence for the outstanding accesses in the current
+            // OpenGL ES context.
+            fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
+            if (fence == EGL_NO_SYNC_KHR) {
+                ST_LOGE("syncForReleaseLocked: error creating fence: %#x",
+                        eglGetError());
+                return UNKNOWN_ERROR;
+            }
+            glFlush();
+            mEglSlots[mCurrentTexture].mEglFence = fence;
         }
-        glFlush();
-        mEglSlots[mCurrentTexture].mEglFence = fence;
     }
 
     return OK;
@@ -698,6 +736,66 @@
     return mCurrentFence;
 }
 
+status_t SurfaceTexture::doGLFenceWait() const {
+    Mutex::Autolock lock(mMutex);
+
+    EGLDisplay dpy = eglGetCurrentDisplay();
+    EGLContext ctx = eglGetCurrentContext();
+
+    if (mEglDisplay != dpy || mEglDisplay == EGL_NO_DISPLAY) {
+        ST_LOGE("doGLFenceWait: invalid current EGLDisplay");
+        return INVALID_OPERATION;
+    }
+
+    if (mEglContext != ctx || mEglContext == EGL_NO_CONTEXT) {
+        ST_LOGE("doGLFenceWait: invalid current EGLContext");
+        return INVALID_OPERATION;
+    }
+
+    if (mCurrentFence != NULL) {
+        if (useWaitSync) {
+            // Create an EGLSyncKHR from the current fence.
+            int fenceFd = mCurrentFence->dup();
+            if (fenceFd == -1) {
+                ST_LOGE("doGLFenceWait: error dup'ing fence fd: %d", errno);
+                return -errno;
+            }
+            EGLint attribs[] = {
+                EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd,
+                EGL_NONE
+            };
+            EGLSyncKHR sync = eglCreateSyncKHR(dpy,
+                    EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
+            if (sync == EGL_NO_SYNC_KHR) {
+                close(fenceFd);
+                ST_LOGE("doGLFenceWait: error creating EGL fence: %#x",
+                        eglGetError());
+                return UNKNOWN_ERROR;
+            }
+
+            // XXX: The spec draft is inconsistent as to whether this should
+            // return an EGLint or void.  Ignore the return value for now, as
+            // it's not strictly needed.
+            eglWaitSyncANDROID(dpy, sync, 0);
+            EGLint eglErr = eglGetError();
+            eglDestroySyncKHR(dpy, sync);
+            if (eglErr != EGL_SUCCESS) {
+                ST_LOGE("doGLFenceWait: error waiting for EGL fence: %#x",
+                        eglErr);
+                return UNKNOWN_ERROR;
+            }
+        } else {
+            status_t err = mCurrentFence->wait(Fence::TIMEOUT_NEVER);
+            if (err != NO_ERROR) {
+                ST_LOGE("doGLFenceWait: error waiting for fence: %d", err);
+                return err;
+            }
+        }
+    }
+
+    return NO_ERROR;
+}
+
 bool SurfaceTexture::isSynchronousMode() const {
     Mutex::Autolock lock(mMutex);
     return mBufferQueue->isSynchronousMode();
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 2d41aa7..5cfa0db 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -270,6 +270,30 @@
 typedef EGLBoolean (EGLAPIENTRYP PFEGLAWAKENPROCESSIMGPROC)(void);
 #endif
 
+/* EGL_ANDROID_native_fence_sync
+ */
+#ifndef EGL_ANDROID_native_fence_sync
+#define EGL_ANDROID_native_fence_sync 1
+#define EGL_SYNC_NATIVE_FENCE_ANDROID                 0x3144
+#define EGL_SYNC_NATIVE_FENCE_FD_ANDROID              0x3145
+#define EGL_NO_NATIVE_FENCE_FD_ANDROID                -1
+#define EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID        0x3146
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLint EGLAPIENTRY eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync);
+#endif
+typedef EGLint (EGLAPIENTRYP PFNEGLDUPNATIVEFENCEFDANDROID) (EGLDisplay dpy, EGLSyncKHR sync);
+#endif
+
+/* EGL_ANDROID_wait_sync
+ */
+#ifndef EGL_ANDROID_wait_sync
+#define EGL_ANDROID_wait_sync
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLint EGLAPIENTRY eglWaitSyncANDROID(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags);
+#endif
+typedef EGLint (EGLAPIENTRYP PFNEGLWAITSYNCANDROID) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 1bc4eb7..91b4567 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -652,6 +652,8 @@
     // These extensions should not be exposed to applications. They're used
     // internally by the Android EGL layer.
     if (!strcmp(procname, "eglSetBlobCacheFuncsANDROID") ||
+        !strcmp(procname, "eglDupNativeFenceFDANDROID") ||
+        !strcmp(procname, "eglWaitSyncANDROID") ||
         !strcmp(procname, "eglHibernateProcessIMG") ||
         !strcmp(procname, "eglAwakenProcessIMG")) {
         return NULL;
@@ -1190,7 +1192,35 @@
 // ANDROID extensions
 // ----------------------------------------------------------------------------
 
-/* ANDROID extensions entry-point go here */
+EGLint eglDupNativeFenceFDANDROID(EGLDisplay dpy, EGLSyncKHR sync)
+{
+    clearError();
+
+    const egl_display_ptr dp = validate_display(dpy);
+    if (!dp) return EGL_NO_NATIVE_FENCE_FD_ANDROID;
+
+    EGLint result = EGL_NO_NATIVE_FENCE_FD_ANDROID;
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (cnx->dso && cnx->egl.eglDupNativeFenceFDANDROID) {
+        result = cnx->egl.eglDupNativeFenceFDANDROID(dp->disp.dpy, sync);
+    }
+    return result;
+}
+
+EGLint eglWaitSyncANDROID(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags)
+{
+    clearError();
+
+    const egl_display_ptr dp = validate_display(dpy);
+    if (!dp) return EGL_NO_NATIVE_FENCE_FD_ANDROID;
+
+    EGLint result = EGL_FALSE;
+    egl_connection_t* const cnx = &gEGLImpl;
+    if (cnx->dso && cnx->egl.eglWaitSyncANDROID) {
+        result = cnx->egl.eglWaitSyncANDROID(dp->disp.dpy, sync, flags);
+    }
+    return result;
+}
 
 // ----------------------------------------------------------------------------
 // NVIDIA extensions
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 80072ab..371df43 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -59,6 +59,7 @@
 // extensions not exposed to applications but used by the ANDROID system
 //      "EGL_ANDROID_recordable "               // mandatory
 //      "EGL_ANDROID_blob_cache "               // strongly recommended
+//      "EGL_ANDROID_native_fence_sync "        // strongly recommended
 //      "EGL_IMG_hibernate_process "            // optional
 
 extern void initEglTraceLevel();
diff --git a/opengl/libs/EGL/egl_entries.in b/opengl/libs/EGL/egl_entries.in
index 9feb716..2ffd417 100644
--- a/opengl/libs/EGL/egl_entries.in
+++ b/opengl/libs/EGL/egl_entries.in
@@ -62,6 +62,8 @@
 
 EGL_ENTRY(EGLBoolean, eglSetSwapRectangleANDROID, EGLDisplay, EGLSurface, EGLint, EGLint, EGLint, EGLint)
 EGL_ENTRY(EGLClientBuffer, eglGetRenderBufferANDROID, EGLDisplay, EGLSurface)
+EGL_ENTRY(EGLint, eglDupNativeFenceFDANDROID, EGLDisplay, EGLSyncKHR)
+EGL_ENTRY(EGLint, eglWaitSyncANDROID, EGLDisplay, EGLSyncKHR, EGLint)
 
 /* NVIDIA extensions */
 
diff --git a/opengl/specs/EGL_ANDROID_native_fence_sync.txt b/opengl/specs/EGL_ANDROID_native_fence_sync.txt
index bd1cdda..8273be4 100644
--- a/opengl/specs/EGL_ANDROID_native_fence_sync.txt
+++ b/opengl/specs/EGL_ANDROID_native_fence_sync.txt
@@ -20,7 +20,7 @@
 
 Version
 
-    Version 2, July 23, 2012
+    Version 3, September 4, 2012
 
 Number
 
@@ -74,7 +74,7 @@
     Accepted by the <attrib_list> parameter of eglCreateSyncKHR, and returned
     by eglDupNativeFenceFDANDROID in the event of an error:
 
-    EGL_NO_NATIVE_FENCE_ANDROID            -1
+    EGL_NO_NATIVE_FENCE_FD_ANDROID         -1
 
     Returned in <value> when eglGetSyncAttribKHR is called with <attribute>
     EGL_SYNC_CONDITION_KHR:
@@ -90,7 +90,7 @@
     object is created. In this case the EGL_SYNC_NATIVE_FENCE_FD_ANDROID
     attribute may optionally be specified. If this attribute is specified, it
     must be set to either a file descriptor that refers to a native fence
-    object or to the value EGL_NO_NATIVE_FENCE_ANDROID.
+    object or to the value EGL_NO_NATIVE_FENCE_FD_ANDROID.
 
     The default values for the EGL native fence sync object attributes are as
     follows:
@@ -202,7 +202,7 @@
     The command
 
         EGLint eglDupNativeFenceFDANDROID(
-                            EGLdisplay dpy,
+                            EGLDisplay dpy,
                             EGLSyncKHR sync);
 
     duplicates the file descriptor stored in the
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 7fb1159..5fba3f6 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -33,21 +33,12 @@
 #include <ui/GraphicBuffer.h>
 
 #include "DisplayHardware/FramebufferSurface.h"
+#include "DisplayHardware/HWComposer.h"
 
 // ----------------------------------------------------------------------------
 namespace android {
 // ----------------------------------------------------------------------------
 
-sp<FramebufferSurface> FramebufferSurface::create() {
-    sp<FramebufferSurface> result = new FramebufferSurface();
-    if (result->fbDev == NULL) {
-        result = NULL;
-    }
-    return result;
-}
-
-// ----------------------------------------------------------------------------
-
 class GraphicBufferAlloc : public BnGraphicBufferAlloc {
 public:
     GraphicBufferAlloc() { };
@@ -66,36 +57,21 @@
  *
  */
 
-FramebufferSurface::FramebufferSurface():
+FramebufferSurface::FramebufferSurface(HWComposer& hwc) :
     ConsumerBase(new BufferQueue(true, new GraphicBufferAlloc())),
-    fbDev(0),
     mCurrentBufferSlot(-1),
-    mCurrentBuffer(0)
+    mCurrentBuffer(0),
+    mHwc(hwc)
 {
-    hw_module_t const* module;
-
-    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) == 0) {
-        int stride;
-        int err;
-        int i;
-        err = framebuffer_open(module, &fbDev);
-        ALOGE_IF(err, "couldn't open framebuffer HAL (%s)", strerror(-err));
-
-        // bail out if we can't initialize the modules
-        if (!fbDev)
-            return;
-
-        mName = "FramebufferSurface";
-        mBufferQueue->setConsumerName(mName);
-        mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |
-                GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER);
-        mBufferQueue->setDefaultBufferFormat(fbDev->format);
-        mBufferQueue->setDefaultBufferSize(fbDev->width, fbDev->height);
-        mBufferQueue->setSynchronousMode(true);
-        mBufferQueue->setDefaultMaxBufferCount(NUM_FRAME_BUFFERS);
-    } else {
-        ALOGE("Couldn't get gralloc module");
-    }
+    mName = "FramebufferSurface";
+    mBufferQueue->setConsumerName(mName);
+    mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_FB |
+                                       GRALLOC_USAGE_HW_RENDER | GRALLOC_USAGE_HW_COMPOSER);
+    mBufferQueue->setDefaultBufferFormat(mHwc.getFormat(HWC_DISPLAY_PRIMARY));
+    mBufferQueue->setDefaultBufferSize(mHwc.getResolutionX(HWC_DISPLAY_PRIMARY),
+                                       mHwc.getResolutionY(HWC_DISPLAY_PRIMARY));
+    mBufferQueue->setSynchronousMode(true);
+    mBufferQueue->setDefaultMaxBufferCount(NUM_FRAME_BUFFERS);
 }
 
 status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>* buffer) {
@@ -125,7 +101,7 @@
         item.mBuf != mCurrentBufferSlot) {
         // Release the previous buffer.
         err = releaseBufferLocked(mCurrentBufferSlot, EGL_NO_DISPLAY,
-                EGL_NO_SYNC_KHR, Fence::NO_FENCE);
+                EGL_NO_SYNC_KHR);
         if (err != NO_ERROR && err != BufferQueue::STALE_BUFFER_SLOT) {
             ALOGE("error releasing buffer: %s (%d)", strerror(-err), err);
             return err;
@@ -145,12 +121,7 @@
     return NO_ERROR;
 }
 
-FramebufferSurface::~FramebufferSurface() {
-    if (fbDev) {
-        framebuffer_close(fbDev);
-    }
-}
-
+// Overrides ConsumerBase::onFrameAvailable(), does not call base class impl.
 void FramebufferSurface::onFrameAvailable() {
     // XXX: The following code is here temporarily as part of the transition
     // away from the framebuffer HAL.
@@ -161,7 +132,7 @@
                 strerror(-err), err);
         return;
     }
-    err = fbDev->post(fbDev, buf->handle);
+    err = mHwc.fbPost(buf->handle);
     if (err != NO_ERROR) {
         ALOGE("error posting framebuffer: %d", err);
     }
@@ -181,19 +152,11 @@
 
 status_t FramebufferSurface::compositionComplete()
 {
-    if (fbDev->compositionComplete) {
-        return fbDev->compositionComplete(fbDev);
-    }
-    return INVALID_OPERATION;
+    return mHwc.fbCompositionComplete();
 }
 
 void FramebufferSurface::dump(String8& result) {
-    if (fbDev->common.version >= 1 && fbDev->dump) {
-        const size_t SIZE = 4096;
-        char buffer[SIZE];
-        fbDev->dump(fbDev, buffer, SIZE);
-        result.append(buffer);
-    }
+    mHwc.fbDump(result);
     ConsumerBase::dump(result);
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index bfa500b..fd7c520 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -30,13 +30,13 @@
 
 class Rect;
 class String8;
+class HWComposer;
 
 // ---------------------------------------------------------------------------
 
 class FramebufferSurface : public ConsumerBase {
 public:
-
-    static sp<FramebufferSurface> create();
+    FramebufferSurface(HWComposer& hwc);
 
     bool isUpdateOnDemand() const { return false; }
     status_t setUpdateRectangle(const Rect& updateRect);
@@ -49,22 +49,12 @@
     // BufferQueue.  The new buffer is returned in the 'buffer' argument.
     status_t nextBuffer(sp<GraphicBuffer>* buffer);
 
-    // FIXME: currently there are information we can only get from the
-    // FB HAL, and FB HAL can only be instantiated once on some devices.
-    // Eventually this functionality will have to move in HWC or somewhere else.
-    const framebuffer_device_t* getFbHal() const {
-        return fbDev;
-    }
-
 private:
-    FramebufferSurface();
-    virtual ~FramebufferSurface(); // this class cannot be overloaded
+    virtual ~FramebufferSurface() { }; // this class cannot be overloaded
 
     virtual void onFrameAvailable();
     virtual void freeBufferLocked(int slotIndex);
 
-    framebuffer_device_t* fbDev;
-
     // mCurrentBufferIndex is the slot index of the current buffer or
     // INVALID_BUFFER_SLOT to indicate that either there is no current buffer
     // or the buffer is not associated with a slot.
@@ -73,6 +63,9 @@
     // mCurrentBuffer is the current buffer or NULL to indicate that there is
     // no current buffer.
     sp<GraphicBuffer> mCurrentBuffer;
+
+    // Hardware composer, owned by SurfaceFlinger.
+    HWComposer& mHwc;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index dca27ba..75b8ad8 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -90,10 +90,9 @@
 
 HWComposer::HWComposer(
         const sp<SurfaceFlinger>& flinger,
-        EventHandler& handler,
-        framebuffer_device_t const* fbDev)
+        EventHandler& handler)
     : mFlinger(flinger),
-      mModule(0), mHwc(0), mNumDisplays(1),
+      mFbDev(0), mHwc(0), mNumDisplays(1),
       mCBContext(new cb_context),
       mEventHandler(handler),
       mVSyncCount(0), mDebugForceFakeVSync(false)
@@ -107,71 +106,68 @@
     mDebugForceFakeVSync = atoi(value);
 
     bool needVSyncThread = true;
-    int err = hw_get_module(HWC_HARDWARE_MODULE_ID, &mModule);
-    ALOGW_IF(err, "%s module not found", HWC_HARDWARE_MODULE_ID);
-    if (err == 0) {
-        err = hwc_open_1(mModule, &mHwc);
-        ALOGE_IF(err, "%s device failed to initialize (%s)",
-                HWC_HARDWARE_COMPOSER, strerror(-err));
-        if (err == 0) {
-            if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_0) ||
-                    hwcHeaderVersion(mHwc) < MIN_HWC_HEADER_VERSION ||
-                    hwcHeaderVersion(mHwc) > HWC_HEADER_VERSION) {
-                ALOGE("%s device version %#x unsupported, will not be used",
-                        HWC_HARDWARE_COMPOSER, mHwc->common.version);
-                hwc_close_1(mHwc);
-                mHwc = NULL;
-            }
+
+    // Note: some devices may insist that the FB HAL be opened before HWC.
+    loadFbHalModule();
+    loadHwcModule();
+
+    if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1) && !mFbDev) {
+        ALOGE("ERROR: failed to open framebuffer, aborting");
+        // FB mandatory on <= 1.0, give up
+        abort();
+    }
+
+    if (mHwc) {
+        ALOGI("Using %s version %u.%u", HWC_HARDWARE_COMPOSER,
+              (hwcApiVersion(mHwc) >> 24) & 0xff,
+              (hwcApiVersion(mHwc) >> 16) & 0xff);
+        if (mHwc->registerProcs) {
+            mCBContext->hwc = this;
+            mCBContext->procs.invalidate = &hook_invalidate;
+            mCBContext->procs.vsync = &hook_vsync;
+            if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
+                mCBContext->procs.hotplug = &hook_hotplug;
+            else
+                mCBContext->procs.hotplug = NULL;
+            memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));
+            mHwc->registerProcs(mHwc, &mCBContext->procs);
         }
 
-        if (mHwc) {
-            ALOGI("Using %s version %u.%u", HWC_HARDWARE_COMPOSER,
-                    (hwcApiVersion(mHwc) >> 24) & 0xff,
-                    (hwcApiVersion(mHwc) >> 16) & 0xff);
-            if (mHwc->registerProcs) {
-                mCBContext->hwc = this;
-                mCBContext->procs.invalidate = &hook_invalidate;
-                mCBContext->procs.vsync = &hook_vsync;
-                if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
-                    mCBContext->procs.hotplug = &hook_hotplug;
-                else
-                    mCBContext->procs.hotplug = NULL;
-                memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));
-                mHwc->registerProcs(mHwc, &mCBContext->procs);
-            }
+        // don't need a vsync thread if we have a hardware composer
+        needVSyncThread = false;
+        // always turn vsync off when we start
+        mHwc->eventControl(mHwc, HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
 
-            // always turn vsync off when we start
-            needVSyncThread = false;
-            mHwc->eventControl(mHwc, HWC_DISPLAY_PRIMARY, HWC_EVENT_VSYNC, 0);
+        // these IDs are always reserved
+        for (size_t i=0 ; i<HWC_NUM_DISPLAY_TYPES ; i++) {
+            mAllocatedDisplayIDs.markBit(i);
+        }
 
-            // these IDs are always reserved
-            for (size_t i=0 ; i<HWC_NUM_DISPLAY_TYPES ; i++) {
-                mAllocatedDisplayIDs.markBit(i);
-            }
-
-            // the number of displays we actually have depends on the
-            // hw composer version
-            if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_2)) {
-                // 1.2 adds support for virtual displays
-                mNumDisplays = MAX_DISPLAYS;
-            } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
-                // 1.1 adds support for multiple displays
-                mNumDisplays = HWC_NUM_DISPLAY_TYPES;
-            } else {
-                mNumDisplays = 1;
-            }
+        // the number of displays we actually have depends on the
+        // hw composer version
+        if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_2)) {
+            // 1.2 adds support for virtual displays
+            mNumDisplays = MAX_DISPLAYS;
+        } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+            // 1.1 adds support for multiple displays
+            mNumDisplays = HWC_NUM_DISPLAY_TYPES;
+        } else {
+            mNumDisplays = 1;
         }
     }
 
-    if (fbDev) {
+    if (mFbDev) {
         ALOG_ASSERT(!(mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)),
                 "should only have fbdev if no hwc or hwc is 1.0");
 
         DisplayData& disp(mDisplayData[HWC_DISPLAY_PRIMARY]);
-        disp.xdpi = fbDev->xdpi;
-        disp.ydpi = fbDev->ydpi;
+        disp.xres = mFbDev->width;
+        disp.yres = mFbDev->height;
+        disp.format = mFbDev->format;
+        disp.xdpi = mFbDev->xdpi;
+        disp.ydpi = mFbDev->ydpi;
         if (disp.refresh == 0) {
-            disp.refresh = nsecs_t(1e9 / fbDev->fps);
+            disp.refresh = nsecs_t(1e9 / mFbDev->fps);
             ALOGW("getting VSYNC period from fb HAL: %lld", disp.refresh);
         }
         if (disp.refresh == 0) {
@@ -197,9 +193,57 @@
     if (mHwc) {
         hwc_close_1(mHwc);
     }
+    if (mFbDev) {
+        framebuffer_close(mFbDev);
+    }
     delete mCBContext;
 }
 
+// Load and prepare the hardware composer module.  Sets mHwc.
+void HWComposer::loadHwcModule()
+{
+    hw_module_t const* module;
+
+    if (hw_get_module(HWC_HARDWARE_MODULE_ID, &module) != 0) {
+        ALOGE("%s module not found", HWC_HARDWARE_MODULE_ID);
+        return;
+    }
+
+    int err = hwc_open_1(module, &mHwc);
+    if (err) {
+        ALOGE("%s device failed to initialize (%s)",
+              HWC_HARDWARE_COMPOSER, strerror(-err));
+        return;
+    }
+
+    if (!hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_0) ||
+            hwcHeaderVersion(mHwc) < MIN_HWC_HEADER_VERSION ||
+            hwcHeaderVersion(mHwc) > HWC_HEADER_VERSION) {
+        ALOGE("%s device version %#x unsupported, will not be used",
+              HWC_HARDWARE_COMPOSER, mHwc->common.version);
+        hwc_close_1(mHwc);
+        mHwc = NULL;
+        return;
+    }
+}
+
+// Load and prepare the FB HAL, which uses the gralloc module.  Sets mFbDev.
+void HWComposer::loadFbHalModule()
+{
+    hw_module_t const* module;
+
+    if (hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &module) != 0) {
+        ALOGE("%s module not found", GRALLOC_HARDWARE_MODULE_ID);
+        return;
+    }
+
+    int err = framebuffer_open(module, &mFbDev);
+    if (err) {
+        ALOGE("framebuffer_open failed (%s)", strerror(-err));
+        return;
+    }
+}
+
 status_t HWComposer::initCheck() const {
     return mHwc ? NO_ERROR : NO_INIT;
 }
@@ -265,6 +309,7 @@
 void HWComposer::queryDisplayProperties(int disp) {
     ALOG_ASSERT(mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1));
 
+    // use zero as default value for unspecified attributes
     int32_t values[NUM_DISPLAY_ATTRIBUTES - 1];
     memset(values, 0, sizeof(values));
 
@@ -283,12 +328,10 @@
             mDisplayData[disp].refresh = nsecs_t(values[i]);
             break;
         case HWC_DISPLAY_RESOLUTION_X:
-            // TODO: we'll probably want to remember this eventually
-            w = values[i];
+            mDisplayData[disp].xres = values[i];
             break;
         case HWC_DISPLAY_RESOLUTION_Y:
-            // TODO: we'll probably want to remember this eventually
-            h = values[i];
+            mDisplayData[disp].yres = values[i];
             break;
         case HWC_DISPLAY_DPI_X:
             mDisplayData[disp].xdpi = values[i] / 1000.0f;
@@ -336,25 +379,37 @@
     return NO_ERROR;
 }
 
-nsecs_t HWComposer::getRefreshPeriod() const {
-    return mDisplayData[HWC_DISPLAY_PRIMARY].refresh;
+nsecs_t HWComposer::getRefreshPeriod(int disp) const {
+    return mDisplayData[disp].refresh;
 }
 
-nsecs_t HWComposer::getRefreshTimestamp() const {
+nsecs_t HWComposer::getRefreshTimestamp(int disp) const {
     // this returns the last refresh timestamp.
     // if the last one is not available, we estimate it based on
     // the refresh period and whatever closest timestamp we have.
     Mutex::Autolock _l(mLock);
     nsecs_t now = systemTime(CLOCK_MONOTONIC);
-    return now - ((now - mLastHwVSync) %  mDisplayData[HWC_DISPLAY_PRIMARY].refresh);
+    return now - ((now - mLastHwVSync) %  mDisplayData[disp].refresh);
 }
 
-float HWComposer::getDpiX() const {
-    return mDisplayData[HWC_DISPLAY_PRIMARY].xdpi;
+uint32_t HWComposer::getResolutionX(int disp) const {
+    return mDisplayData[disp].xres;
 }
 
-float HWComposer::getDpiY() const {
-    return mDisplayData[HWC_DISPLAY_PRIMARY].ydpi;
+uint32_t HWComposer::getResolutionY(int disp) const {
+    return mDisplayData[disp].yres;
+}
+
+uint32_t HWComposer::getFormat(int disp) const {
+    return mDisplayData[disp].format;
+}
+
+float HWComposer::getDpiX(int disp) const {
+    return mDisplayData[disp].xdpi;
+}
+
+float HWComposer::getDpiY(int disp) const {
+    return mDisplayData[disp].ydpi;
 }
 
 void HWComposer::eventControl(int event, int enabled) {
@@ -493,6 +548,30 @@
             mDisplayData[id].list->numHwLayers : 0;
 }
 
+int HWComposer::fbPost(buffer_handle_t buffer)
+{
+    return mFbDev->post(mFbDev, buffer);
+}
+
+int HWComposer::fbCompositionComplete()
+{
+    if (mFbDev->compositionComplete) {
+        return mFbDev->compositionComplete(mFbDev);
+    } else {
+        return INVALID_OPERATION;
+    }
+}
+
+void HWComposer::fbDump(String8& result) {
+    if (mFbDev->common.version >= 1 && mFbDev->dump) {
+        const size_t SIZE = 4096;
+        char buffer[SIZE];
+        mFbDev->dump(mFbDev, buffer, SIZE);
+        result.append(buffer);
+    }
+}
+
+
 /*
  * Helper template to implement a concrete HWCLayer
  * This holds the pointer to the concrete hwc layer type
@@ -680,7 +759,7 @@
 HWComposer::VSyncThread::VSyncThread(HWComposer& hwc)
     : mHwc(hwc), mEnabled(false),
       mNextFakeVSync(0),
-      mRefreshPeriod(hwc.getRefreshPeriod())
+      mRefreshPeriod(hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY))
 {
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index a49a023..4c520b1 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -64,8 +64,7 @@
 
     HWComposer(
             const sp<SurfaceFlinger>& flinger,
-            EventHandler& handler,
-            framebuffer_device_t const* fbDev);
+            EventHandler& handler);
 
     ~HWComposer();
 
@@ -107,6 +106,11 @@
     // needed forward declarations
     class LayerListIterator;
 
+    // Forwarding to FB HAL for pre-HWC-1.1 code (see FramebufferSurface).
+    int fbPost(buffer_handle_t buffer);
+    int fbCompositionComplete();
+    void fbDump(String8& result);
+
     /*
      * Interface to hardware composer's layers functionality.
      * This abstracts the HAL interface to layers which can evolve in
@@ -208,10 +212,15 @@
 
     void eventControl(int event, int enabled);
 
-    nsecs_t getRefreshPeriod() const;
-    nsecs_t getRefreshTimestamp() const;
-    float getDpiX() const;
-    float getDpiY() const;
+    // Query display parameters.  Pass in a display index (e.g.
+    // HWC_DISPLAY_PRIMARY).
+    nsecs_t getRefreshPeriod(int disp) const;
+    nsecs_t getRefreshTimestamp(int disp) const;
+    uint32_t getResolutionX(int disp) const;
+    uint32_t getResolutionY(int disp) const;
+    uint32_t getFormat(int disp) const;
+    float getDpiX(int disp) const;
+    float getDpiY(int disp) const;
 
     // this class is only used to fake the VSync event on systems that don't
     // have it.
@@ -236,6 +245,8 @@
             const Vector< sp<LayerBase> >& visibleLayersSortedByZ) const;
 
 private:
+    void loadHwcModule();
+    void loadFbHalModule();
 
     LayerListIterator getLayerIterator(int32_t id, size_t index);
     size_t getNumLayers(int32_t id) const;
@@ -261,6 +272,9 @@
         ~DisplayData() {
             free(list);
         }
+        uint32_t xres;
+        uint32_t yres;
+        uint32_t format;    // pixel format from FB hal, for pre-hwc-1.1
         float xdpi;
         float ydpi;
         nsecs_t refresh;
@@ -271,7 +285,7 @@
     };
 
     sp<SurfaceFlinger>              mFlinger;
-    hw_module_t const*              mModule;
+    framebuffer_device_t*           mFbDev;
     struct hwc_composer_device_1*   mHwc;
     // invariant: mLists[0] != NULL iff mHwc != NULL
     // mLists[i>0] can be NULL. that display is to be ignored
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f39de4a..75eff9f 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -333,11 +333,9 @@
         return;
     }
 
-    // TODO: replace this with a server-side wait
-    sp<Fence> fence = mSurfaceTexture->getCurrentFence();
-    if (fence.get()) {
-        status_t err = fence->wait(Fence::TIMEOUT_NEVER);
-        ALOGW_IF(err != OK, "Layer::onDraw: failed waiting for fence: %d", err);
+    status_t err = mSurfaceTexture->doGLFenceWait();
+    if (err != OK) {
+        ALOGE("onDraw: failed waiting for fence: %d", err);
         // Go ahead and draw the buffer anyway; no matter what we do the screen
         // is probably going to have something visibly wrong.
     }
@@ -517,7 +515,7 @@
         const size_t offset = mFrameLatencyOffset;
         mFrameStats[offset].timestamp = mSurfaceTexture->getTimestamp();
         mFrameStats[offset].set = systemTime();
-        mFrameStats[offset].vsync = hwc.getRefreshTimestamp();
+        mFrameStats[offset].vsync = hwc.getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
         mFrameLatencyOffset = (mFrameLatencyOffset + 1) % 128;
         mFrameLatencyNeeded = false;
     }
@@ -728,7 +726,8 @@
 {
     LayerBaseClient::dumpStats(result, buffer, SIZE);
     const size_t o = mFrameLatencyOffset;
-    const nsecs_t period = mFlinger->getHwComposer().getRefreshPeriod();
+    const nsecs_t period =
+            mFlinger->getHwComposer().getRefreshPeriod(HWC_DISPLAY_PRIMARY);
     result.appendFormat("%lld\n", period);
     for (size_t i=0 ; i<128 ; i++) {
         const size_t index = (o+i) % 128;
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 311d95f..b61770c 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -439,7 +439,7 @@
             "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.layerStack, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h,
+            s.layerStack, s.z, 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 08cb345..058ba45 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -366,13 +366,18 @@
     ALOGI(  "SurfaceFlinger's main thread ready to run. "
             "Initializing graphics H/W...");
 
-    // initialize EGL
+    // initialize EGL for the default display
     mEGLDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     eglInitialize(mEGLDisplay, NULL, NULL);
 
+    // Initialize the H/W composer object.  There may or may not be an
+    // actual hardware composer underneath.
+    mHwc = new HWComposer(this,
+            *static_cast<HWComposer::EventHandler *>(this));
+
     // Initialize the main display
     // create native window to main display
-    sp<FramebufferSurface> fbs = FramebufferSurface::create();
+    sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc);
     if (fbs == NULL) {
         ALOGE("Display subsystem failed to initialize. check logs. exiting...");
         exit(0);
@@ -408,11 +413,6 @@
     mEventThread = new EventThread(this);
     mEventQueue.setEventThread(mEventThread);
 
-    // initialize the H/W composer
-    mHwc = new HWComposer(this,
-            *static_cast<HWComposer::EventHandler *>(this),
-            fbs->getFbHal());
-
     // initialize our drawing state
     mDrawingState = mCurrentState;
 
@@ -500,8 +500,8 @@
     }
 
     const HWComposer& hwc(getHwComposer());
-    float xdpi = hwc.getDpiX();
-    float ydpi = hwc.getDpiY();
+    float xdpi = hwc.getDpiX(HWC_DISPLAY_PRIMARY);
+    float ydpi = hwc.getDpiY(HWC_DISPLAY_PRIMARY);
 
     // TODO: Not sure if display density should handled by SF any longer
     class Density {
@@ -538,7 +538,7 @@
     info->h = hw->getHeight();
     info->xdpi = xdpi;
     info->ydpi = ydpi;
-    info->fps = float(1e9 / hwc.getRefreshPeriod());
+    info->fps = float(1e9 / hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY));
     info->density = density;
     info->orientation = hw->getOrientation();
     // TODO: this needs to go away (currently needed only by webkit)
@@ -618,6 +618,13 @@
 }
 
 void SurfaceFlinger::onVSyncReceived(int type, nsecs_t timestamp) {
+    if (mEventThread == NULL) {
+        // This is a temporary workaround for b/7145521.  A non-null pointer
+        // does not mean EventThread has finished initializing, so this
+        // is not a correct fix.
+        ALOGW("WARNING: EventThread not started, ignoring vsync");
+        return;
+    }
     if (uint32_t(type) < DisplayDevice::NUM_DISPLAY_TYPES) {
         // we should only receive DisplayDevice::DisplayType from the vsync callback
         const wp<IBinder>& token(mDefaultDisplays[type]);
@@ -977,7 +984,7 @@
                                 || (state.frame != draw[i].frame))
                         {
                             disp->setProjection(state.orientation,
-                                    state.viewport, state.viewport);
+                                    state.viewport, state.frame);
                         }
                     }
                 }
@@ -996,7 +1003,7 @@
                                 state.type, display, stc, 0, mEGLConfig);
                         disp->setLayerStack(state.layerStack);
                         disp->setProjection(state.orientation,
-                                state.viewport, state.viewport);
+                                state.viewport, state.frame);
                         mDisplays.add(display, disp);
                     }
                 }
@@ -1728,6 +1735,8 @@
     d.what = DisplayState::eDisplayProjectionChanged;
     d.token = mDefaultDisplays[DisplayDevice::DISPLAY_PRIMARY];
     d.orientation = DisplayState::eOrientationDefault;
+    d.frame.makeInvalid();
+    d.viewport.makeInvalid();
     displays.add(d);
     setTransactionState(state, displays, 0);
 
@@ -1963,7 +1972,7 @@
         const sp<const DisplayDevice>& hw(mDisplays[dpy]);
         snprintf(buffer, SIZE,
                 "+ DisplayDevice[%u]\n"
-                "   id=%x, layerStack=%u, (%4dx%4d), orient=%2d (type=%08x), "
+                "   type=%x, layerStack=%u, (%4dx%4d), orient=%2d (type=%08x), "
                 "flips=%u, secure=%d, numLayers=%u, v:[%d,%d,%d,%d], f:[%d,%d,%d,%d]\n",
                 dpy,
                 hw->getDisplayType(), hw->getLayerStack(),
@@ -2016,9 +2025,9 @@
             mLastSwapBufferTime/1000.0,
             mLastTransactionTime/1000.0,
             mTransactionFlags,
-            1e9 / hwc.getRefreshPeriod(),
-            hwc.getDpiX(),
-            hwc.getDpiY());
+            1e9 / hwc.getRefreshPeriod(HWC_DISPLAY_PRIMARY),
+            hwc.getDpiX(HWC_DISPLAY_PRIMARY),
+            hwc.getDpiY(HWC_DISPLAY_PRIMARY));
     result.append(buffer);
 
     snprintf(buffer, SIZE, "  eglSwapBuffers time: %f us\n",
diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp
index ca3fa6e..aca90e0 100644
--- a/services/surfaceflinger/Transform.cpp
+++ b/services/surfaceflinger/Transform.cpp
@@ -192,7 +192,6 @@
 
 void Transform::transform(float* point, int x, int y) const
 {
-    const mat33& M(mMatrix);
     vec2 v(x, y);
     v = transform(v);
     point[0] = v[0];