add support hwc 1.1

Bug: 7124069

Change-Id: I53d705105c4ad8954d3f50ee4f4c8b7ec936b871
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 81640af..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,38 +647,43 @@
     return NO_ERROR;
 }
 
-size_t HWComposer::getNumLayers(int32_t id) const {
-    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
-        return 0;
-    }
-    return (mHwc && mDisplayData[id].list) ?
-            mDisplayData[id].list->numHwLayers : 0;
-}
-
 int HWComposer::getVisualID() const {
     if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
-        return HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+        // 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;
     }
 }
 
-int HWComposer::fbPost(buffer_handle_t buffer) {
-    if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
-        return mFbDev->post(mFbDev, buffer);
+bool HWComposer::supportsFramebufferTarget() const {
+    return (mHwc && hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1));
+}
+
+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);
     }
-    return NO_ERROR;
 }
 
 int HWComposer::fbCompositionComplete() {
-    if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
-        if (mFbDev->compositionComplete) {
-            return mFbDev->compositionComplete(mFbDev);
-        } else {
-            return INVALID_OPERATION;
-        }
+    if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1))
+        return NO_ERROR;
+
+    if (mFbDev->compositionComplete) {
+        return mFbDev->compositionComplete(mFbDev);
+    } else {
+        return INVALID_OPERATION;
     }
-    return NO_ERROR;
 }
 
 void HWComposer::fbDump(String8& result) {
@@ -596,7 +695,6 @@
     }
 }
 
-
 /*
  * Helper template to implement a concrete HWCLayer
  * This holds the pointer to the concrete hwc layer type
@@ -733,7 +831,22 @@
  * 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,
@@ -747,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 fe928c5..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,12 +99,18 @@
     // 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;
 
@@ -111,7 +119,7 @@
     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);
 
@@ -253,7 +261,6 @@
     void loadFbHalModule();
 
     LayerListIterator getLayerIterator(int32_t id, size_t index);
-    size_t getNumLayers(int32_t id) const;
 
     struct cb_context;
 
@@ -269,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);
         }
@@ -286,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 f62f075..bdd8c67 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -245,15 +245,6 @@
     EGLConfig* const configs = new EGLConfig[numConfigs];
     eglChooseConfig(dpy, attrs, configs, numConfigs, &n);
 
-    if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
-        // 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
-        *outConfig = configs[0];
-        delete [] configs;
-        return NO_ERROR;
-    }
-
     for (int i=0 ; i<n ; i++) {
         EGLint nativeVisualId = 0;
         eglGetConfigAttrib(dpy, configs[i], EGL_NATIVE_VISUAL_ID, &nativeVisualId);
@@ -273,6 +264,7 @@
     EGLConfig config;
     EGLint dummy;
     status_t err;
+
     EGLint attribs[] = {
             EGL_SURFACE_TYPE,           EGL_WINDOW_BIT,
             EGL_RED_SIZE,               8,
@@ -390,6 +382,9 @@
     mEGLConfig  = selectEGLConfig(mEGLDisplay, format);
     mEGLContext = createGLContext(mEGLDisplay, mEGLConfig);
 
+    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();
@@ -725,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());
             }
         }
     }
@@ -885,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) {
@@ -1160,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);
@@ -1308,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)
@@ -1388,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);