Merge changes I53d70510,If34a05f3 into jb-mr1-dev

* changes:
  add support hwc 1.1
  refactor things a bit
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 2c06a0b..72f73f7 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -183,6 +183,32 @@
     mPageFlipCount++;
 }
 
+void DisplayDevice::swapBuffers(HWComposer& hwc) const {
+    if (hwc.initCheck() != NO_ERROR) {
+        // no HWC, we call eglSwapBuffers()
+        eglSwapBuffers(mDisplay, mSurface);
+    } else {
+        if (hwc.hasGlesComposition(mType)) {
+            if (hwc.supportsFramebufferTarget() ||
+                    mType >= DisplayDevice::DISPLAY_VIRTUAL) {
+                // as of hwc 1.1 we always call eglSwapBuffers, however,
+                // on older versions of HWC, we need to call it only on
+                // virtual displays
+                eglSwapBuffers(mDisplay, mSurface);
+            }
+        }
+    }
+}
+
+void DisplayDevice::onSwapBuffersCompleted(HWComposer& hwc) const {
+    if (hwc.initCheck() == NO_ERROR) {
+        if (hwc.supportsFramebufferTarget()) {
+            int fd = hwc.getAndResetReleaseFenceFd(mType);
+            mFramebufferSurface->setReleaseFenceFd(fd);
+        }
+    }
+}
+
 uint32_t DisplayDevice::getFlags() const
 {
     return mFlags;
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 8122b9d..4a3f0a0 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -40,6 +40,7 @@
 class FramebufferSurface;
 class LayerBase;
 class SurfaceFlinger;
+class HWComposer;
 
 class DisplayDevice : public LightRefBase<DisplayDevice>
 {
@@ -106,8 +107,12 @@
     int32_t                 getHwcDisplayId() const { return mHwcDisplayId; }
     const wp<IBinder>&      getDisplayToken() const { return mDisplayToken; }
 
+    void swapBuffers(HWComposer& hwc) const;
     status_t compositionComplete() const;
     
+    // called after h/w composer has completed its set() call
+    void onSwapBuffersCompleted(HWComposer& hwc) const;
+
     Rect getBounds() const {
         return Rect(mDisplayWidth, mDisplayHeight);
     }
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 92a3fcc..a4f8fb6 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -74,15 +74,13 @@
     mBufferQueue->setDefaultMaxBufferCount(NUM_FRAME_BUFFERS);
 }
 
-status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>* buffer) {
+status_t FramebufferSurface::nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence) {
     Mutex::Autolock lock(mMutex);
 
     BufferQueue::BufferItem item;
     status_t err = acquireBufferLocked(&item);
     if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
-        if (buffer != NULL) {
-            *buffer = mCurrentBuffer;
-        }
+        outBuffer = mCurrentBuffer;
         return NO_ERROR;
     } else if (err != NO_ERROR) {
         ALOGE("error acquiring buffer: %s (%d)", strerror(-err), err);
@@ -107,32 +105,24 @@
             return err;
         }
     }
-
     mCurrentBufferSlot = item.mBuf;
     mCurrentBuffer = mSlots[mCurrentBufferSlot].mGraphicBuffer;
-    if (item.mFence != NULL) {
-        item.mFence->wait(Fence::TIMEOUT_NEVER);
-    }
-
-    if (buffer != NULL) {
-        *buffer = mCurrentBuffer;
-    }
-
+    outFence = item.mFence;
+    outBuffer = mCurrentBuffer;
     return NO_ERROR;
 }
 
 // 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.
     sp<GraphicBuffer> buf;
-    status_t err = nextBuffer(&buf);
+    sp<Fence> acquireFence;
+    status_t err = nextBuffer(buf, acquireFence);
     if (err != NO_ERROR) {
-        ALOGE("error latching next FramebufferSurface buffer: %s (%d)",
+        ALOGE("error latching nnext FramebufferSurface buffer: %s (%d)",
                 strerror(-err), err);
         return;
     }
-    err = mHwc.fbPost(buf->handle);
+    err = mHwc.fbPost(0, acquireFence, buf); // FIXME: use real display id
     if (err != NO_ERROR) {
         ALOGE("error posting framebuffer: %d", err);
     }
@@ -145,6 +135,19 @@
     }
 }
 
+status_t FramebufferSurface::setReleaseFenceFd(int fenceFd) {
+    status_t err = NO_ERROR;
+    if (fenceFd >= 0) {
+        sp<Fence> fence(new Fence(fenceFd));
+        if (mCurrentBufferSlot != BufferQueue::INVALID_BUFFER_SLOT) {
+            status_t err = addReleaseFence(mCurrentBufferSlot, fence);
+            ALOGE_IF(err, "setReleaseFenceFd: failed to add the fence: %s (%d)",
+                    strerror(-err), err);
+        }
+    }
+    return err;
+}
+
 status_t FramebufferSurface::setUpdateRectangle(const Rect& r)
 {
     return INVALID_OPERATION;
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index fd7c520..717a3f1 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -44,10 +44,13 @@
 
     virtual void dump(String8& result);
 
-    // nextBuffer waits for and then latches the next buffer from the
-    // BufferQueue and releases the previously latched buffer to the
-    // BufferQueue.  The new buffer is returned in the 'buffer' argument.
-    status_t nextBuffer(sp<GraphicBuffer>* buffer);
+    // setReleaseFenceFd stores a fence file descriptor that will signal when the
+    // current buffer is no longer being read. This fence will be returned to
+    // the producer when the current buffer is released by updateTexImage().
+    // Multiple fences can be set for a given buffer; they will be merged into
+    // a single union fence. The SurfaceTexture will close the file descriptor
+    // when finished with it.
+    status_t setReleaseFenceFd(int fenceFd);
 
 private:
     virtual ~FramebufferSurface() { }; // this class cannot be overloaded
@@ -55,6 +58,11 @@
     virtual void onFrameAvailable();
     virtual void freeBufferLocked(int slotIndex);
 
+    // nextBuffer waits for and then latches the next buffer from the
+    // BufferQueue and releases the previously latched buffer to the
+    // BufferQueue.  The new buffer is returned in the 'buffer' argument.
+    status_t nextBuffer(sp<GraphicBuffer>& outBuffer, sp<Fence>& outFence);
+
     // 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.
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 1b55792..9c04fc0 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -26,6 +26,7 @@
 #include <sys/types.h>
 
 #include <utils/Errors.h>
+#include <utils/misc.h>
 #include <utils/String8.h>
 #include <utils/Thread.h>
 #include <utils/Trace.h>
@@ -43,6 +44,7 @@
 #include "LayerBase.h"
 #include "HWComposer.h"
 #include "SurfaceFlinger.h"
+#include <utils/CallStack.h>
 
 namespace android {
 
@@ -111,6 +113,14 @@
     loadFbHalModule();
     loadHwcModule();
 
+    if (mFbDev && mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+        // close FB HAL if we don't needed it.
+        // FIXME: this is temporary until we're not forced to open FB HAL
+        // before HWC.
+        framebuffer_close(mFbDev);
+        mFbDev = NULL;
+    }
+
     // If we have no HWC, or a pre-1.1 HWC, an FB dev is mandatory.
     if ((!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
             && !mFbDev) {
@@ -310,7 +320,7 @@
 #define ANDROID_DENSITY_XHIGH 320
 
 void HWComposer::queryDisplayProperties(int disp) {
-    ALOG_ASSERT(mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1));
+    LOG_ALWAYS_FATAL_IF(!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1));
 
     // use zero as default value for unspecified attributes
     int32_t values[NUM_DISPLAY_ATTRIBUTES - 1];
@@ -319,7 +329,11 @@
     uint32_t config;
     size_t numConfigs = 1;
     status_t err = mHwc->getDisplayConfigs(mHwc, disp, &config, &numConfigs);
+    LOG_ALWAYS_FATAL_IF(err, "getDisplayAttributes failed (%s)", strerror(-err));
+
     if (err == NO_ERROR) {
+        ALOGD("config=%d, numConfigs=%d, NUM_DISPLAY_ATTRIBUTES=%d",
+                config, numConfigs, NUM_DISPLAY_ATTRIBUTES);
         mHwc->getDisplayAttributes(mHwc, disp, config, DISPLAY_ATTRIBUTES,
                 values);
     }
@@ -343,8 +357,8 @@
             mDisplayData[disp].ydpi = values[i] / 1000.0f;
             break;
         default:
-            ALOG_ASSERT(false, "unknown display attribute %#x",
-                    DISPLAY_ATTRIBUTES[i]);
+            ALOG_ASSERT(false, "unknown display attribute[%d] %#x",
+                    i, DISPLAY_ATTRIBUTES[i]);
             break;
         }
     }
@@ -439,13 +453,35 @@
 
     if (mHwc) {
         DisplayData& disp(mDisplayData[id]);
+        if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+            // we need space for the HWC_FRAMEBUFFER_TARGET
+            numLayers++;
+        }
         if (disp.capacity < numLayers || disp.list == NULL) {
-            const size_t size = sizeof(hwc_display_contents_1_t)
+            size_t size = sizeof(hwc_display_contents_1_t)
                     + numLayers * sizeof(hwc_layer_1_t);
             free(disp.list);
             disp.list = (hwc_display_contents_1_t*)malloc(size);
             disp.capacity = numLayers;
         }
+        if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+            disp.framebufferTarget = &disp.list->hwLayers[numLayers - 1];
+            memset(disp.framebufferTarget, 0, sizeof(hwc_layer_1_t));
+            const hwc_rect_t r = { 0, 0, disp.width, disp.height };
+            disp.framebufferTarget->compositionType = HWC_FRAMEBUFFER_TARGET;
+            disp.framebufferTarget->hints = 0;
+            disp.framebufferTarget->flags = 0;
+            disp.framebufferTarget->handle = disp.fbTargetHandle;
+            disp.framebufferTarget->transform = 0;
+            disp.framebufferTarget->blending = HWC_BLENDING_PREMULT;
+            disp.framebufferTarget->sourceCrop = r;
+            disp.framebufferTarget->displayFrame = r;
+            disp.framebufferTarget->visibleRegionScreen.numRects = 1;
+            disp.framebufferTarget->visibleRegionScreen.rects =
+                &disp.framebufferTarget->displayFrame;
+            disp.framebufferTarget->acquireFenceFd = -1;
+            disp.framebufferTarget->releaseFenceFd = -1;
+        }
         disp.list->retireFenceFd = -1;
         disp.list->flags = HWC_GEOMETRY_CHANGED;
         disp.list->numHwLayers = numLayers;
@@ -453,9 +489,46 @@
     return NO_ERROR;
 }
 
+status_t HWComposer::setFramebufferTarget(int32_t id,
+        const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf) {
+    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
+        return BAD_INDEX;
+    }
+    DisplayData& disp(mDisplayData[id]);
+    if (!disp.framebufferTarget) {
+        // this should never happen, but apparently eglCreateWindowSurface()
+        // triggers a SurfaceTextureClient::queueBuffer()  on some
+        // devices (!?) -- log and ignore.
+        ALOGE("HWComposer: framebufferTarget is null");
+        CallStack stack;
+        stack.update();
+        stack.dump("");
+        return NO_ERROR;
+    }
+
+    int acquireFenceFd = -1;
+    if (acquireFence != NULL) {
+        acquireFenceFd = acquireFence->dup();
+    }
+
+    // ALOGD("fbPost: handle=%p, fence=%d", buf->handle, acquireFenceFd);
+    disp.fbTargetHandle = buf->handle;
+    disp.framebufferTarget->handle = disp.fbTargetHandle;
+    disp.framebufferTarget->acquireFenceFd = acquireFenceFd;
+    return NO_ERROR;
+}
+
 status_t HWComposer::prepare() {
     for (size_t i=0 ; i<mNumDisplays ; i++) {
-        mLists[i] = mDisplayData[i].list;
+        DisplayData& disp(mDisplayData[i]);
+        if (disp.framebufferTarget) {
+            // make sure to reset the type to HWC_FRAMEBUFFER_TARGET
+            // DO NOT reset the handle field to NULL, because it's possible
+            // that we have nothing to redraw (eg: eglSwapBuffers() not called)
+            // in which case, we should continue to use the same buffer.
+            disp.framebufferTarget->compositionType = HWC_FRAMEBUFFER_TARGET;
+        }
+        mLists[i] = disp.list;
         if (mLists[i]) {
             if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_2)) {
                 mLists[i]->outbuf = NULL;
@@ -472,6 +545,8 @@
     }
 
     int err = mHwc->prepare(mHwc, mNumDisplays, mLists);
+    ALOGE_IF(err, "HWComposer: prepare failed (%s)", strerror(-err));
+
     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
@@ -483,6 +558,10 @@
             if (disp.list) {
                 for (size_t i=0 ; i<disp.list->numHwLayers ; i++) {
                     hwc_layer_1_t& l = disp.list->hwLayers[i];
+
+                    //ALOGD("prepare: %d, type=%d, handle=%p",
+                    //        i, l.compositionType, l.handle);
+
                     if (l.flags & HWC_SKIP_LAYER) {
                         l.compositionType = HWC_FRAMEBUFFER;
                     }
@@ -511,6 +590,21 @@
     return mDisplayData[id].hasFbComp;
 }
 
+int HWComposer::getAndResetReleaseFenceFd(int32_t id) {
+    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
+        return BAD_INDEX;
+
+    int fd = INVALID_OPERATION;
+    if (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+        const DisplayData& disp(mDisplayData[id]);
+        if (disp.framebufferTarget) {
+            fd = disp.framebufferTarget->releaseFenceFd;
+            disp.framebufferTarget->releaseFenceFd = -1;
+        }
+    }
+    return fd;
+}
+
 status_t HWComposer::commit() {
     int err = NO_ERROR;
     if (mHwc) {
@@ -553,21 +647,38 @@
     return NO_ERROR;
 }
 
-size_t HWComposer::getNumLayers(int32_t id) const {
-    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
-        return 0;
+int HWComposer::getVisualID() const {
+    if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+        // FIXME: temporary hack until HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED
+        // is supported by the implementation. we can only be in this case
+        // if we have HWC 1.1
+        return HAL_PIXEL_FORMAT_RGBA_8888;
+        //return HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+    } else {
+        return mFbDev->format;
     }
-    return (mHwc && mDisplayData[id].list) ?
-            mDisplayData[id].list->numHwLayers : 0;
 }
 
-int HWComposer::fbPost(buffer_handle_t buffer)
-{
-    return mFbDev->post(mFbDev, buffer);
+bool HWComposer::supportsFramebufferTarget() const {
+    return (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1));
 }
 
-int HWComposer::fbCompositionComplete()
-{
+int HWComposer::fbPost(int32_t id,
+        const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buffer) {
+    if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+        return setFramebufferTarget(id, acquireFence, buffer);
+    } else {
+        if (acquireFence != NULL) {
+            acquireFence->wait(Fence::TIMEOUT_NEVER);
+        }
+        return mFbDev->post(mFbDev, buffer->handle);
+    }
+}
+
+int HWComposer::fbCompositionComplete() {
+    if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
+        return NO_ERROR;
+
     if (mFbDev->compositionComplete) {
         return mFbDev->compositionComplete(mFbDev);
     } else {
@@ -576,7 +687,7 @@
 }
 
 void HWComposer::fbDump(String8& result) {
-    if (mFbDev->common.version >= 1 && mFbDev->dump) {
+    if (mFbDev && mFbDev->common.version >= 1 && mFbDev->dump) {
         const size_t SIZE = 4096;
         char buffer[SIZE];
         mFbDev->dump(mFbDev, buffer, SIZE);
@@ -584,7 +695,6 @@
     }
 }
 
-
 /*
  * Helper template to implement a concrete HWCLayer
  * This holds the pointer to the concrete hwc layer type
@@ -721,13 +831,28 @@
  * returns an iterator on the end of the layer list
  */
 HWComposer::LayerListIterator HWComposer::end(int32_t id) {
-    return getLayerIterator(id, getNumLayers(id));
+    size_t numLayers = 0;
+    if (uint32_t(id) <= 31 && mAllocatedDisplayIDs.hasBit(id)) {
+        const DisplayData& disp(mDisplayData[id]);
+        if (mHwc && disp.list) {
+            numLayers = disp.list->numHwLayers;
+            if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+                // with HWC 1.1, the last layer is always the HWC_FRAMEBUFFER_TARGET,
+                // which we ignore when iterating through the layer list.
+                ALOGE_IF(!numLayers, "mDisplayData[%d].list->numHwLayers is 0", id);
+                if (numLayers) {
+                    numLayers--;
+                }
+            }
+        }
+    }
+    return getLayerIterator(id, numLayers);
 }
 
 void HWComposer::dump(String8& result, char* buffer, size_t SIZE,
         const Vector< sp<LayerBase> >& visibleLayersSortedByZ) const {
     if (mHwc) {
-        result.append("Hardware Composer state:\n");
+        result.appendFormat("Hardware Composer state (version %8x):\n", hwcApiVersion(mHwc));
         result.appendFormat("  mDebugForceFakeVSync=%d\n", mDebugForceFakeVSync);
         for (size_t i=0 ; i<mNumDisplays ; i++) {
             const DisplayData& disp(mDisplayData[i]);
@@ -735,27 +860,47 @@
                 result.appendFormat("  id=%d, numHwLayers=%u, flags=%08x\n",
                         i, disp.list->numHwLayers, disp.list->flags);
                 result.append(
-                        "   type   |  handle  |   hints  |   flags  | tr | blend |  format  |       source crop         |           frame           name \n"
-                        "----------+----------+----------+----------+----+-------+----------+---------------------------+--------------------------------\n");
-                //      " ________ | ________ | ________ | ________ | __ | _____ | ________ | [_____,_____,_____,_____] | [_____,_____,_____,_____]
+                        "    type    |  handle  |   hints  |   flags  | tr | blend |  format  |       source crop         |           frame           name \n"
+                        "------------+----------+----------+----------+----+-------+----------+---------------------------+--------------------------------\n");
+                //      " __________ | ________ | ________ | ________ | __ | _____ | ________ | [_____,_____,_____,_____] | [_____,_____,_____,_____]
                 for (size_t i=0 ; i<disp.list->numHwLayers ; i++) {
                     const hwc_layer_1_t&l = disp.list->hwLayers[i];
-                    const sp<LayerBase> layer(visibleLayersSortedByZ[i]);
                     int32_t format = -1;
-                    if (layer->getLayer() != NULL) {
-                        const sp<GraphicBuffer>& buffer(
+                    String8 name("unknown");
+                    if (i < visibleLayersSortedByZ.size()) {
+                        const sp<LayerBase>& layer(visibleLayersSortedByZ[i]);
+                        if (layer->getLayer() != NULL) {
+                            const sp<GraphicBuffer>& buffer(
                                 layer->getLayer()->getActiveBuffer());
-                        if (buffer != NULL) {
-                            format = buffer->getPixelFormat();
+                            if (buffer != NULL) {
+                                format = buffer->getPixelFormat();
+                            }
                         }
+                        name = layer->getName();
                     }
+
+                    int type = l.compositionType;
+                    if (type == HWC_FRAMEBUFFER_TARGET) {
+                        name = "HWC_FRAMEBUFFER_TARGET";
+                        format = disp.format;
+                    }
+
+                    static char const* compositionTypeName[] = {
+                            "GLES",
+                            "HWC",
+                            "BACKGROUND",
+                            "FB TARGET",
+                            "UNKNOWN"};
+                    if (type >= NELEM(compositionTypeName))
+                        type = NELEM(compositionTypeName) - 1;
+
                     result.appendFormat(
-                            " %8s | %08x | %08x | %08x | %02x | %05x | %08x | [%5d,%5d,%5d,%5d] | [%5d,%5d,%5d,%5d] %s\n",
-                            l.compositionType ? "OVERLAY" : "FB",
+                            " %10s | %08x | %08x | %08x | %02x | %05x | %08x | [%5d,%5d,%5d,%5d] | [%5d,%5d,%5d,%5d] %s\n",
+                                    compositionTypeName[type],
                                     intptr_t(l.handle), l.hints, l.flags, l.transform, l.blending, format,
                                     l.sourceCrop.left, l.sourceCrop.top, l.sourceCrop.right, l.sourceCrop.bottom,
                                     l.displayFrame.left, l.displayFrame.top, l.displayFrame.right, l.displayFrame.bottom,
-                                    layer->getName().string());
+                                    name.string());
                 }
             }
         }
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 552d42f..f253ecc 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -36,6 +36,7 @@
 
 struct hwc_composer_device_1;
 struct hwc_display_contents_1;
+struct hwc_layer_1;
 struct hwc_procs;
 struct framebuffer_device_t;
 
@@ -43,6 +44,7 @@
 // ---------------------------------------------------------------------------
 
 class GraphicBuffer;
+class Fence;
 class LayerBase;
 class Region;
 class String8;
@@ -97,17 +99,27 @@
     // create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED.
     status_t createWorkList(int32_t id, size_t numLayers);
 
+    bool supportsFramebufferTarget() const;
+
     // does this display have layers handled by HWC
     bool hasHwcComposition(int32_t id) const;
 
     // does this display have layers handled by GLES
     bool hasGlesComposition(int32_t id) const;
 
+    // get the releaseFence file descriptor for the given display
+    // the release fence is only valid after commit()
+    int getAndResetReleaseFenceFd(int32_t id);
+
     // needed forward declarations
     class LayerListIterator;
 
+    // return the visual id to be used to find a suitable EGLConfig for
+    // *ALL* displays.
+    int getVisualID() const;
+
     // Forwarding to FB HAL for pre-HWC-1.1 code (see FramebufferSurface).
-    int fbPost(buffer_handle_t buffer);
+    int fbPost(int32_t id, const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf);
     int fbCompositionComplete();
     void fbDump(String8& result);
 
@@ -249,7 +261,6 @@
     void loadFbHalModule();
 
     LayerListIterator getLayerIterator(int32_t id, size_t index);
-    size_t getNumLayers(int32_t id) const;
 
     struct cb_context;
 
@@ -265,10 +276,15 @@
 
     void queryDisplayProperties(int disp);
 
+    status_t setFramebufferTarget(int32_t id,
+            const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf);
+
+
     struct DisplayData {
         DisplayData() : xdpi(0), ydpi(0), refresh(0),
             hasFbComp(false), hasOvComp(false),
-            capacity(0), list(NULL) { }
+            capacity(0), list(NULL),
+            framebufferTarget(NULL), fbTargetHandle(NULL) { }
         ~DisplayData() {
             free(list);
         }
@@ -282,6 +298,8 @@
         bool hasOvComp;
         size_t capacity;
         hwc_display_contents_1* list;
+        hwc_layer_1* framebufferTarget;
+        buffer_handle_t fbTargetHandle;
     };
 
     sp<SurfaceFlinger>              mFlinger;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 6785ba8..569f6bb 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -523,6 +523,10 @@
     }
 }
 
+bool Layer::isVisible() const {
+    return LayerBaseClient::isVisible() && (mActiveBuffer != NULL);
+}
+
 Region Layer::latchBuffer(bool& recomputeVisibleRegions)
 {
     ATRACE_CALL();
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index b839f8c..6f75d8c 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -82,6 +82,7 @@
     virtual void onRemoved();
     virtual sp<Layer> getLayer() const { return const_cast<Layer*>(this); }
     virtual void setName(const String8& name);
+    virtual bool isVisible() const;
 
     // LayerBaseClient interface
     virtual wp<IBinder> getSurfaceTextureBinder() const;
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index b61770c..99cb8f3 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -321,6 +321,11 @@
     return mFiltering;
 }
 
+bool LayerBase::isVisible() const {
+    const Layer::State& s(mDrawingState);
+    return !(s.flags & layer_state_t::eLayerHidden) && s.alpha;
+}
+
 void LayerBase::draw(const sp<const DisplayDevice>& hw, const Region& clip) const
 {
     onDraw(hw, clip);
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index 7326f53..9994994 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -211,6 +211,11 @@
      */
     virtual bool isProtected() const   { return false; }
 
+    /*
+     * isVisible - true if this layer is visibile, false otherwise
+     */
+    virtual bool isVisible() const;
+
     /** called with the state lock when the surface is removed from the
      *  current list */
     virtual void onRemoved() { }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f1d790d..bdd8c67 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -43,6 +43,7 @@
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/PixelFormat.h>
 
+#include <utils/misc.h>
 #include <utils/String8.h>
 #include <utils/String16.h>
 #include <utils/StopWatch.h>
@@ -243,6 +244,7 @@
     eglGetConfigs(dpy, NULL, 0, &numConfigs);
     EGLConfig* const configs = new EGLConfig[numConfigs];
     eglChooseConfig(dpy, attrs, configs, numConfigs, &n);
+
     for (int i=0 ; i<n ; i++) {
         EGLint nativeVisualId = 0;
         eglGetConfigAttrib(dpy, configs[i], EGL_NATIVE_VISUAL_ID, &nativeVisualId);
@@ -262,8 +264,14 @@
     EGLConfig config;
     EGLint dummy;
     status_t err;
+
     EGLint attribs[] = {
             EGL_SURFACE_TYPE,           EGL_WINDOW_BIT,
+            EGL_RED_SIZE,               8,
+            EGL_GREEN_SIZE,             8,
+            EGL_BLUE_SIZE,              8,
+            // EGL_RECORDABLE_ANDROID must be last so that we can retry
+            // without it easily (see below)
             EGL_RECORDABLE_ANDROID,     EGL_TRUE,
             EGL_NONE
     };
@@ -271,7 +279,7 @@
     if (err) {
         // maybe we failed because of EGL_RECORDABLE_ANDROID
         ALOGW("couldn't find an EGLConfig with EGL_RECORDABLE_ANDROID");
-        attribs[2] = EGL_NONE;
+        attribs[NELEM(attribs) - 3] = EGL_NONE;
         err = selectConfigForPixelFormat(display, attribs, nativeVisualId, &config);
     }
     ALOGE_IF(err, "couldn't find an EGLConfig matching the screen format");
@@ -297,13 +305,7 @@
     return ctxt;
 }
 
-void SurfaceFlinger::initializeGL(EGLDisplay display, const sp<DisplayDevice>& hw) {
-    EGLBoolean result = DisplayDevice::makeCurrent(display, hw, mEGLContext);
-    if (!result) {
-        ALOGE("Couldn't create a working GLES context. check logs. exiting...");
-        exit(0);
-    }
-
+void SurfaceFlinger::initializeGL(EGLDisplay display) {
     GLExtensions& extensions(GLExtensions::getInstance());
     extensions.initWithGLStrings(
             glGetString(GL_VENDOR),
@@ -375,39 +377,48 @@
     mHwc = new HWComposer(this,
             *static_cast<HWComposer::EventHandler *>(this));
 
-    // Initialize the main display
-    // create native window to main display
-    sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc);
-    if (fbs == NULL) {
-        ALOGE("Display subsystem failed to initialize. check logs. exiting...");
-        exit(0);
-    }
-
-    sp<SurfaceTextureClient> stc(new SurfaceTextureClient(
-            static_cast<sp<ISurfaceTexture> >(fbs->getBufferQueue())));
-
     // initialize the config and context
-    int format;
-    ANativeWindow* const anw = stc.get();
-    anw->query(anw, NATIVE_WINDOW_FORMAT, &format);
+    EGLint format = mHwc->getVisualID();
     mEGLConfig  = selectEGLConfig(mEGLDisplay, format);
     mEGLContext = createGLContext(mEGLDisplay, mEGLConfig);
 
-    // initialize our main display hardware
+    LOG_ALWAYS_FATAL_IF(mEGLContext == EGL_NO_CONTEXT,
+            "couldn't create EGLContext");
 
+    // initialize our non-virtual displays
     for (size_t i=0 ; i<DisplayDevice::NUM_DISPLAY_TYPES ; i++) {
         mDefaultDisplays[i] = new BBinder();
         mCurrentState.displays.add(mDefaultDisplays[i],
-                DisplayDeviceState((DisplayDevice::DisplayType)i));
+                DisplayDeviceState(DisplayDevice::DisplayType(i)));
     }
+
+    // The main display is a bit special and always exists
+    //
+    // if we didn't add it here, it would be added automatically during the
+    // first transaction, however this would also create some difficulties:
+    //
+    // - there would be a race where a client could call getDisplayInfo(),
+    //   for instance before the DisplayDevice is created.
+    //
+    // - we need a GL context current in a few places, when initializing
+    //   OpenGL ES (see below), or creating a layer,
+    //   or when a texture is (asynchronously) destroyed, and for that
+    //   we need a valid surface, so it's conveniant to use the main display
+    //   for that.
+
+    sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc);
+    sp<SurfaceTextureClient> stc = new SurfaceTextureClient(
+                static_cast< sp<ISurfaceTexture> >(fbs->getBufferQueue()));
     sp<DisplayDevice> hw = new DisplayDevice(this,
             DisplayDevice::DISPLAY_PRIMARY,
             mDefaultDisplays[DisplayDevice::DISPLAY_PRIMARY],
-            anw, fbs, mEGLConfig);
+            stc, fbs, mEGLConfig);
     mDisplays.add(mDefaultDisplays[DisplayDevice::DISPLAY_PRIMARY], hw);
 
+
     //  initialize OpenGL ES
-    initializeGL(mEGLDisplay, hw);
+    DisplayDevice::makeCurrent(mEGLDisplay, hw, mEGLContext);
+    initializeGL(mEGLDisplay);
 
     // start the EventThread
     mEventThread = new EventThread(this);
@@ -416,6 +427,7 @@
     // initialize our drawing state
     mDrawingState = mCurrentState;
 
+
     // We're now ready to accept clients...
     mReadyToRunBarrier.open();
 
@@ -708,10 +720,7 @@
                     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
                 }
                 hw->compositionComplete();
-                // FIXME
-                if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
-                    eglSwapBuffers(mEGLDisplay, hw->getEGLSurface());
-                }
+                hw->swapBuffers(getHwComposer());
             }
         }
     }
@@ -868,6 +877,7 @@
     for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
         sp<const DisplayDevice> hw(mDisplays[dpy]);
         const Vector< sp<LayerBase> >& currentLayers(hw->getVisibleLayersSortedByZ());
+        hw->onSwapBuffersCompleted(hwc);
         const size_t count = currentLayers.size();
         int32_t id = hw->getHwcDisplayId();
         if (id >=0 && hwc.initCheck() == NO_ERROR) {
@@ -1009,16 +1019,41 @@
             for (size_t i=0 ; i<cc ; i++) {
                 if (draw.indexOfKey(curr.keyAt(i)) < 0) {
                     const DisplayDeviceState& state(curr[i]);
-                    if (state.surface != NULL) {
-                        sp<SurfaceTextureClient> stc(
-                                new SurfaceTextureClient(state.surface));
-                        const wp<IBinder>& display(curr.keyAt(i));
-                        sp<DisplayDevice> disp = new DisplayDevice(this,
-                                state.type, display, stc, 0, mEGLConfig);
-                        disp->setLayerStack(state.layerStack);
-                        disp->setProjection(state.orientation,
+
+                    sp<FramebufferSurface> fbs;
+                    sp<SurfaceTextureClient> stc;
+                    if (!state.isVirtualDisplay()) {
+
+                        ALOGE_IF(state.surface!=NULL,
+                                "adding a supported display, but rendering "
+                                "surface is provided (%p), ignoring it",
+                                state.surface.get());
+
+                        // for supported (by hwc) displays we provide our
+                        // own rendering surface
+                        fbs = new FramebufferSurface(*mHwc);
+                        stc = new SurfaceTextureClient(
+                                static_cast< sp<ISurfaceTexture> >(fbs->getBufferQueue()));
+                    } else {
+                        if (state.surface != NULL) {
+                            stc = new SurfaceTextureClient(state.surface);
+                        }
+                    }
+
+                    const wp<IBinder>& display(curr.keyAt(i));
+                    if (stc != NULL) {
+                        sp<DisplayDevice> hw = new DisplayDevice(this,
+                                state.type, display, stc, fbs, mEGLConfig);
+                        hw->setLayerStack(state.layerStack);
+                        hw->setProjection(state.orientation,
                                 state.viewport, state.frame);
-                        mDisplays.add(display, disp);
+                        mDisplays.add(display, hw);
+                        if (hw->getDisplayType() < DisplayDevice::NUM_DISPLAY_TYPES) {
+                            // notify the system that this display is now up
+                            // (note onScreenAcquired() is safe to call from
+                            // here because we're in the main thread)
+                            onScreenAcquired(hw);
+                        }
                     }
                 }
             }
@@ -1118,7 +1153,7 @@
 
 
         // handle hidden surfaces by setting the visible region to empty
-        if (CC_LIKELY(!(s.flags & layer_state_t::eLayerHidden) && s.alpha)) {
+        if (CC_LIKELY(layer->isVisible())) {
             const bool translucent = !layer->isOpaque();
             Rect bounds(layer->computeBounds());
             visibleRegion.set(bounds);
@@ -1266,20 +1301,11 @@
 
     doComposeSurfaces(hw, dirtyRegion);
 
-    // 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 (if there is a hwc) and never for the other ones
-    if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL ||
-            getHwComposer().initCheck() != NO_ERROR) {
-        // 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);
+
+    // swap buffers (presentation)
+    hw->swapBuffers(getHwComposer());
 }
 
 void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty)
@@ -1346,6 +1372,12 @@
                         layer->draw(hw, clip);
                         break;
                     }
+                    case HWC_FRAMEBUFFER_TARGET: {
+                        // this should not happen as the iterator shouldn't
+                        // let us get there.
+                        ALOGW("HWC_FRAMEBUFFER_TARGET found in hwc list (index=%d)", i);
+                        break;
+                    }
                 }
             }
             layer->setAcquireFence(hw, *cur);
@@ -1753,9 +1785,7 @@
     d.viewport.makeInvalid();
     displays.add(d);
     setTransactionState(state, displays, 0);
-
-    // XXX: this should init default device to "unblank" and all other devices to "blank"
-    onScreenAcquired();
+    onScreenAcquired(getDefaultDisplayDevice());
 }
 
 void SurfaceFlinger::initializeDisplays() {
@@ -1773,21 +1803,25 @@
 }
 
 
-void SurfaceFlinger::onScreenAcquired() {
+void SurfaceFlinger::onScreenAcquired(const sp<const DisplayDevice>& hw) {
     ALOGD("Screen about to return, flinger = %p", this);
-    sp<const DisplayDevice> hw(getDefaultDisplayDevice()); // XXX: this should be per DisplayDevice
     getHwComposer().acquire();
     hw->acquireScreen();
-    mEventThread->onScreenAcquired();
+    if (hw->getDisplayType() == DisplayDevice::DISPLAY_PRIMARY) {
+        // FIXME: eventthread only knows about the main display right now
+        mEventThread->onScreenAcquired();
+    }
     mVisibleRegionsDirty = true;
     repaintEverything();
 }
 
-void SurfaceFlinger::onScreenReleased() {
+void SurfaceFlinger::onScreenReleased(const sp<const DisplayDevice>& hw) {
     ALOGD("About to give-up screen, flinger = %p", this);
-    sp<const DisplayDevice> hw(getDefaultDisplayDevice()); // XXX: this should be per DisplayDevice
     if (hw->isScreenAcquired()) {
-        mEventThread->onScreenReleased();
+        if (hw->getDisplayType() == DisplayDevice::DISPLAY_PRIMARY) {
+            // FIXME: eventthread only knows about the main display right now
+            mEventThread->onScreenReleased();
+        }
         hw->releaseScreen();
         getHwComposer().release();
         mVisibleRegionsDirty = true;
@@ -1801,7 +1835,8 @@
     public:
         MessageScreenAcquired(SurfaceFlinger* flinger) : flinger(flinger) { }
         virtual bool handler() {
-            flinger->onScreenAcquired();
+            // FIXME: should this be per-display?
+            flinger->onScreenAcquired(flinger->getDefaultDisplayDevice());
             return true;
         }
     };
@@ -1815,7 +1850,8 @@
     public:
         MessageScreenReleased(SurfaceFlinger* flinger) : flinger(flinger) { }
         virtual bool handler() {
-            flinger->onScreenReleased();
+            // FIXME: should this be per-display?
+            flinger->onScreenReleased(flinger->getDefaultDisplayDevice());
             return true;
         }
     };
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ffe68c6..a648621 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -166,6 +166,7 @@
         DisplayDeviceState(DisplayDevice::DisplayType type);
         bool isValid() const { return type >= 0; }
         bool isMainDisplay() const { return type == DisplayDevice::DISPLAY_PRIMARY; }
+        bool isVirtualDisplay() const { return type >= DisplayDevice::DISPLAY_VIRTUAL; }
         DisplayDevice::DisplayType type;
         sp<ISurfaceTexture> surface;
         uint32_t layerStack;
@@ -238,9 +239,9 @@
     // called on the main thread in response to initializeDisplays()
     void onInitializeDisplays();
     // called on the main thread in response to blank()
-    void onScreenReleased();
+    void onScreenReleased(const sp<const DisplayDevice>& hw);
     // called on the main thread in response to unblank()
-    void onScreenAcquired();
+    void onScreenAcquired(const sp<const DisplayDevice>& hw);
 
     void handleMessageTransaction();
     void handleMessageInvalidate();
@@ -320,7 +321,7 @@
         EGLint const* attrs, PixelFormat format, EGLConfig* outConfig);
     static EGLConfig selectEGLConfig(EGLDisplay disp, EGLint visualId);
     static EGLContext createGLContext(EGLDisplay disp, EGLConfig config);
-    void initializeGL(EGLDisplay display, const sp<DisplayDevice>& hw);
+    void initializeGL(EGLDisplay display);
     uint32_t getMaxTextureSize() const;
     uint32_t getMaxViewportDims() const;