Merge "SurfaceTexture: inherit from ConsumerBase (try 2)" into jb-mr1-dev
diff --git a/include/gui/BufferItemConsumer.h b/include/gui/BufferItemConsumer.h
new file mode 100644
index 0000000..cd4df25
--- /dev/null
+++ b/include/gui/BufferItemConsumer.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_GUI_BUFFERITEMCONSUMER_H
+#define ANDROID_GUI_BUFFERITEMCONSUMER_H
+
+#include <gui/ConsumerBase.h>
+
+#include <ui/GraphicBuffer.h>
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+
+#define ANDROID_GRAPHICS_BUFFERITEMCONSUMER_JNI_ID "mBufferItemConsumer"
+
+namespace android {
+
+/**
+ * BufferItemConsumer is a BufferQueue consumer endpoint that allows clients
+ * access to the whole BufferItem entry from BufferQueue. Multiple buffers may
+ * be acquired at once, to be used concurrently by the client. This consumer can
+ * operate either in synchronous or asynchronous mode.
+ */
+class BufferItemConsumer: public ConsumerBase
+{
+  public:
+    typedef ConsumerBase::FrameAvailableListener FrameAvailableListener;
+
+    typedef BufferQueue::BufferItem BufferItem;
+
+    enum { INVALID_BUFFER_SLOT = BufferQueue::INVALID_BUFFER_SLOT };
+    enum { NO_BUFFER_AVAILABLE = BufferQueue::NO_BUFFER_AVAILABLE };
+
+    // Create a new buffer item consumer. The consumerUsage parameter determines
+    // the consumer usage flags passed to the graphics allocator. The
+    // bufferCount parameter specifies how many buffers can be locked for user
+    // access at the same time.
+    BufferItemConsumer(uint32_t consumerUsage,
+            int bufferCount = BufferQueue::MIN_UNDEQUEUED_BUFFERS,
+            bool synchronousMode = false);
+
+    virtual ~BufferItemConsumer();
+
+    // set the name of the BufferItemConsumer that will be used to identify it in
+    // log messages.
+    void setName(const String8& name);
+
+    // Gets the next graphics buffer from the producer, filling out the
+    // passed-in BufferItem structure. Returns NO_BUFFER_AVAILABLE if the queue
+    // of buffers is empty, and INVALID_OPERATION if the maximum number of
+    // buffers is already acquired.
+    //
+    // Only a fixed number of buffers can be acquired at a time, determined by
+    // the construction-time bufferCount parameter. If INVALID_OPERATION is
+    // returned by acquireBuffer, then old buffers must be returned to the
+    // queue by calling releaseBuffer before more buffers can be acquired.
+    //
+    // If waitForFence is true, and the acquired BufferItem has a valid fence object,
+    // acquireBuffer will wait on the fence with no timeout before returning.
+    status_t acquireBuffer(BufferItem *item, bool waitForFence = true);
+
+    // Returns an acquired buffer to the queue, allowing it to be reused. Since
+    // only a fixed number of buffers may be acquired at a time, old buffers
+    // must be released by calling releaseBuffer to ensure new buffers can be
+    // acquired by acquireBuffer. Once a BufferItem is released, the caller must
+    // not access any members of the BufferItem, and should immediately remove
+    // all of its references to the BufferItem itself.
+    status_t releaseBuffer(const BufferItem &item,
+            const sp<Fence>& releaseFence = Fence::NO_FENCE);
+
+    sp<ISurfaceTexture> getProducerInterface() const { return getBufferQueue(); }
+
+};
+
+} // namespace android
+
+#endif // ANDROID_GUI_CPUCONSUMER_H
diff --git a/include/gui/CpuConsumer.h b/include/gui/CpuConsumer.h
index 49c90db..807a4b5 100644
--- a/include/gui/CpuConsumer.h
+++ b/include/gui/CpuConsumer.h
@@ -59,6 +59,8 @@
     // how many buffers can be locked for user access at the same time.
     CpuConsumer(uint32_t maxLockedBuffers);
 
+    virtual ~CpuConsumer();
+
     // set the name of the CpuConsumer that will be used to identify it in
     // log messages.
     void setName(const String8& name);
@@ -86,7 +88,7 @@
     // Maximum number of buffers that can be locked at a time
     uint32_t mMaxLockedBuffers;
 
-    void freeBufferLocked(int slotIndex);
+    virtual void freeBufferLocked(int slotIndex);
 
     // Array for tracking pointers passed to the consumer, matching the
     // mSlots indexing
diff --git a/include/ui/Fence.h b/include/ui/Fence.h
index 17cb018..b516a22 100644
--- a/include/ui/Fence.h
+++ b/include/ui/Fence.h
@@ -18,7 +18,6 @@
 #define ANDROID_FENCE_H
 
 #include <stdint.h>
-#include <limits.h>
 #include <sys/types.h>
 
 #include <ui/ANativeObjectBase.h>
@@ -65,7 +64,7 @@
 
     // TIMEOUT_NEVER may be passed to the wait method to indicate that it
     // should wait indefinitely for the fence to signal.
-    enum { TIMEOUT_NEVER = UINT_MAX };
+    enum { TIMEOUT_NEVER = -1 };
 
     // merge combines two Fence objects, creating a new Fence object that
     // becomes signaled when both f1 and f2 are signaled (even if f1 or f2 is
diff --git a/include/utils/VectorImpl.h b/include/utils/VectorImpl.h
index b1224c6..c4ec2ff 100644
--- a/include/utils/VectorImpl.h
+++ b/include/utils/VectorImpl.h
@@ -104,6 +104,16 @@
     virtual void            do_splat(void* dest, const void* item, size_t num) const = 0;
     virtual void            do_move_forward(void* dest, const void* from, size_t num) const = 0;
     virtual void            do_move_backward(void* dest, const void* from, size_t num) const = 0;
+
+    // take care of FBC...
+    virtual void            reservedVectorImpl1();
+    virtual void            reservedVectorImpl2();
+    virtual void            reservedVectorImpl3();
+    virtual void            reservedVectorImpl4();
+    virtual void            reservedVectorImpl5();
+    virtual void            reservedVectorImpl6();
+    virtual void            reservedVectorImpl7();
+    virtual void            reservedVectorImpl8();
     
 private:
         void* _grow(size_t where, size_t amount);
@@ -155,6 +165,16 @@
 protected:
     virtual int             do_compare(const void* lhs, const void* rhs) const = 0;
 
+    // take care of FBC...
+    virtual void            reservedSortedVectorImpl1();
+    virtual void            reservedSortedVectorImpl2();
+    virtual void            reservedSortedVectorImpl3();
+    virtual void            reservedSortedVectorImpl4();
+    virtual void            reservedSortedVectorImpl5();
+    virtual void            reservedSortedVectorImpl6();
+    virtual void            reservedSortedVectorImpl7();
+    virtual void            reservedSortedVectorImpl8();
+
 private:
             ssize_t         _indexOrderOf(const void* item, size_t* order = 0) const;
 
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index 3aa3a50..2bf363f 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -23,7 +23,8 @@
 	Surface.cpp \
 	SurfaceComposerClient.cpp \
 	DummyConsumer.cpp \
-	CpuConsumer.cpp
+	CpuConsumer.cpp \
+	BufferItemConsumer.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libbinder \
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
new file mode 100644
index 0000000..218d929
--- /dev/null
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "BufferItemConsumer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include <utils/Log.h>
+
+#include <gui/BufferItemConsumer.h>
+
+#define BI_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define BI_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define BI_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define BI_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define BI_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
+
+namespace android {
+
+BufferItemConsumer::BufferItemConsumer(uint32_t consumerUsage,
+        int bufferCount, bool synchronousMode) :
+    ConsumerBase(new BufferQueue(true, bufferCount) )
+{
+    mBufferQueue->setConsumerUsageBits(consumerUsage);
+    mBufferQueue->setSynchronousMode(synchronousMode);
+}
+
+BufferItemConsumer::~BufferItemConsumer() {
+}
+
+void BufferItemConsumer::setName(const String8& name) {
+    Mutex::Autolock _l(mMutex);
+    mName = name;
+    mBufferQueue->setConsumerName(name);
+}
+
+status_t BufferItemConsumer::acquireBuffer(BufferItem *item, bool waitForFence) {
+    status_t err;
+
+    if (!item) return BAD_VALUE;
+
+    Mutex::Autolock _l(mMutex);
+
+    err = acquireBufferLocked(item);
+    if (err != OK) {
+        if (err != NO_BUFFER_AVAILABLE) {
+            BI_LOGE("Error acquiring buffer: %s (%d)", strerror(err), err);
+        }
+        return err;
+    }
+
+    if (waitForFence && item->mFence.get()) {
+        err = item->mFence->wait(Fence::TIMEOUT_NEVER);
+        if (err != OK) {
+            BI_LOGE("Failed to wait for fence of acquired buffer: %s (%d)",
+                    strerror(-err), err);
+            return err;
+        }
+    }
+
+    item->mGraphicBuffer = mSlots[item->mBuf].mGraphicBuffer;
+
+    return OK;
+}
+
+status_t BufferItemConsumer::releaseBuffer(const BufferItem &item,
+        const sp<Fence>& releaseFence) {
+    status_t err;
+
+    Mutex::Autolock _l(mMutex);
+
+    err = releaseBufferLocked(item.mBuf, EGL_NO_DISPLAY,
+            EGL_NO_SYNC_KHR, releaseFence);
+    if (err != OK) {
+        BI_LOGE("Failed to release buffer: %s (%d)",
+                strerror(-err), err);
+    }
+    return err;
+}
+
+} // namespace android
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index 90c8ea6..242ac45 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -43,6 +43,9 @@
     mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN);
 }
 
+CpuConsumer::~CpuConsumer() {
+}
+
 void CpuConsumer::setName(const String8& name) {
     Mutex::Autolock _l(mMutex);
     mName = name;
diff --git a/libs/utils/VectorImpl.cpp b/libs/utils/VectorImpl.cpp
index 020ec15..3855305 100644
--- a/libs/utils/VectorImpl.cpp
+++ b/libs/utils/VectorImpl.cpp
@@ -494,6 +494,15 @@
     do_move_backward(dest, from, num);
 }
 
+void VectorImpl::reservedVectorImpl1() { }
+void VectorImpl::reservedVectorImpl2() { }
+void VectorImpl::reservedVectorImpl3() { }
+void VectorImpl::reservedVectorImpl4() { }
+void VectorImpl::reservedVectorImpl5() { }
+void VectorImpl::reservedVectorImpl6() { }
+void VectorImpl::reservedVectorImpl7() { }
+void VectorImpl::reservedVectorImpl8() { }
+
 /*****************************************************************************/
 
 SortedVectorImpl::SortedVectorImpl(size_t itemSize, uint32_t flags)
@@ -609,6 +618,16 @@
     return i;
 }
 
+void SortedVectorImpl::reservedSortedVectorImpl1() { };
+void SortedVectorImpl::reservedSortedVectorImpl2() { };
+void SortedVectorImpl::reservedSortedVectorImpl3() { };
+void SortedVectorImpl::reservedSortedVectorImpl4() { };
+void SortedVectorImpl::reservedSortedVectorImpl5() { };
+void SortedVectorImpl::reservedSortedVectorImpl6() { };
+void SortedVectorImpl::reservedSortedVectorImpl7() { };
+void SortedVectorImpl::reservedSortedVectorImpl8() { };
+
+
 /*****************************************************************************/
 
 }; // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 2289444..821a329 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -68,12 +68,12 @@
 
 DisplayDevice::DisplayDevice(
         const sp<SurfaceFlinger>& flinger,
-        int display,
+        int32_t display, int32_t hwcDisplayId,
         const sp<ANativeWindow>& nativeWindow,
         const sp<FramebufferSurface>& framebufferSurface,
         EGLConfig config)
     : mFlinger(flinger),
-      mId(display),
+      mId(display), mHwcDisplayId(hwcDisplayId),
       mNativeWindow(nativeWindow),
       mFramebufferSurface(framebufferSurface),
       mDisplay(EGL_NO_DISPLAY),
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 9790699..ea56d90 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -28,6 +28,8 @@
 #include <utils/Mutex.h>
 #include <utils/Timers.h>
 
+#include <hardware/hwcomposer_defs.h>
+
 #include "Transform.h"
 
 struct ANativeWindow;
@@ -50,9 +52,9 @@
     Region undefinedRegion;
 
     enum {
-        DISPLAY_ID_MAIN = 0,
-        DISPLAY_ID_HDMI = 1,
-        DISPLAY_ID_COUNT
+        DISPLAY_ID_MAIN = HWC_DISPLAY_PRIMARY,
+        DISPLAY_ID_HDMI = HWC_DISPLAY_EXTERNAL,
+        DISPLAY_ID_COUNT = HWC_NUM_DISPLAY_TYPES
     };
 
     enum {
@@ -62,7 +64,7 @@
 
     DisplayDevice(
             const sp<SurfaceFlinger>& flinger,
-            int dpy,
+            int32_t dpy, int32_t hwcDisplayId,
             const sp<ANativeWindow>& nativeWindow,
             const sp<FramebufferSurface>& framebufferSurface,
             EGLConfig config);
@@ -96,6 +98,7 @@
     const Transform&        getTransform() const { return mGlobalTransform; }
     uint32_t                getLayerStack() const { return mLayerStack; }
     int32_t                 getDisplayId() const { return mId; }
+    int32_t                 getHwcDisplayId() const { return mHwcDisplayId; }
 
     status_t compositionComplete() const;
     
@@ -132,6 +135,7 @@
      */
     sp<SurfaceFlinger> mFlinger;
     int32_t mId;
+    int32_t mHwcDisplayId;
 
     // ANativeWindow this display is rendering into
     sp<ANativeWindow> mNativeWindow;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index a3ec352..b1f8328 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -17,7 +17,7 @@
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
 // Uncomment this to remove support for HWC_DEVICE_API_VERSION_0_3 and older
-// #define HWC_REMOVE_DEPRECATED_VERSIONS 1
+#define HWC_REMOVE_DEPRECATED_VERSIONS 1
 
 #include <stdint.h>
 #include <stdio.h>
@@ -46,120 +46,8 @@
 
 namespace android {
 
-// ---------------------------------------------------------------------------
-// Support for HWC_DEVICE_API_VERSION_0_3 and older:
-// Since v0.3 is deprecated and support will be dropped soon, as much as
-// possible the code is written to target v1.0. When using a v0.3 HWC, we
-// allocate v0.3 structures, but assign them to v1.0 pointers.
-
-#if HWC_REMOVE_DEPRECATED_VERSIONS
-// We need complete types to satisfy semantic checks, even though the code
-// paths that use these won't get executed at runtime (and will likely be dead-
-// code-eliminated). When we remove the code to support v0.3 we can remove
-// these as well.
-typedef hwc_layer_1_t hwc_layer_t;
-typedef hwc_display_contents_1_t hwc_layer_list_t;
-typedef hwc_composer_device_1_t hwc_composer_device_t;
-#endif
-
-// This function assumes we've already rejected HWC's with lower-than-required
-// versions. Don't use it for the initial "does HWC meet requirements" check!
 static bool hwcHasVersion(const hwc_composer_device_1_t* hwc, uint32_t version) {
-    if (HWC_REMOVE_DEPRECATED_VERSIONS &&
-            version <= HWC_DEVICE_API_VERSION_1_0) {
-        return true;
-    } else {
-        return hwc->common.version >= version;
-    }
-}
-
-static bool hwcHasVsyncEvent(const hwc_composer_device_1_t* hwc) {
-    return hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_0_3);
-}
-
-static size_t sizeofHwcLayerList(const hwc_composer_device_1_t* hwc,
-        size_t numLayers) {
-    if (hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_1_0)) {
-        return sizeof(hwc_display_contents_1_t) + numLayers*sizeof(hwc_layer_1_t);
-    } else {
-        return sizeof(hwc_layer_list_t) + numLayers*sizeof(hwc_layer_t);
-    }
-}
-
-static int hwcEventControl(hwc_composer_device_1_t* hwc, int dpy,
-        int event, int enabled) {
-    if (hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_1_0)) {
-        return hwc->methods->eventControl(hwc, dpy, event, enabled);
-    } else {
-        hwc_composer_device_t* hwc0 = reinterpret_cast<hwc_composer_device_t*>(hwc);
-        return hwc0->methods->eventControl(hwc0, event, enabled);
-    }
-}
-
-static int hwcBlank(hwc_composer_device_1_t* hwc, int dpy, int blank) {
-    if (hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_1_0)) {
-        return hwc->methods->blank(hwc, dpy, blank);
-    } else {
-        if (blank) {
-            hwc_composer_device_t* hwc0 = reinterpret_cast<hwc_composer_device_t*>(hwc);
-            return hwc0->set(hwc0, NULL, NULL, NULL);
-        } else {
-            // HWC 0.x turns the screen on at the next set()
-            return NO_ERROR;
-        }
-    }
-}
-
-static int hwcPrepare(hwc_composer_device_1_t* hwc,
-        size_t numDisplays, hwc_display_contents_1_t** displays) {
-    if (hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_1_0)) {
-        return hwc->prepare(hwc, numDisplays, displays);
-    } else {
-        hwc_composer_device_t* hwc0 = reinterpret_cast<hwc_composer_device_t*>(hwc);
-        hwc_layer_list_t* list0 = reinterpret_cast<hwc_layer_list_t*>(displays[0]);
-        // In the past, SurfaceFlinger would pass a NULL list when doing full
-        // OpenGL ES composition. I don't know what, if any, dependencies there
-        // are on this behavior, so I'm playing it safe and preserving it.
-        if (list0->numHwLayers == 0)
-            return hwc0->prepare(hwc0, NULL);
-        else
-            return hwc0->prepare(hwc0, list0);
-    }
-}
-
-static int hwcSet(hwc_composer_device_1_t* hwc, EGLDisplay dpy, EGLSurface sur,
-        size_t numDisplays, hwc_display_contents_1_t** displays) {
-    int err;
-    if (hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_1_0)) {
-        displays[0]->dpy = dpy;
-        displays[0]->sur = sur;
-        err = hwc->set(hwc, numDisplays, displays);
-    } else {
-        hwc_composer_device_t* hwc0 = reinterpret_cast<hwc_composer_device_t*>(hwc);
-        hwc_layer_list_t* list0 = reinterpret_cast<hwc_layer_list_t*>(displays[0]);
-        err = hwc0->set(hwc0, dpy, sur, list0);
-    }
-    return err;
-}
-
-static uint32_t& hwcFlags(hwc_composer_device_1_t* hwc,
-        hwc_display_contents_1_t* display) {
-    if (hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_1_0)) {
-        return display->flags;
-    } else {
-        hwc_layer_list_t* list0 = reinterpret_cast<hwc_layer_list_t*>(display);
-        return list0->flags;
-    }
-}
-
-static size_t& hwcNumHwLayers(hwc_composer_device_1_t* hwc,
-        hwc_display_contents_1_t* display) {
-    if (hwcHasVersion(hwc, HWC_DEVICE_API_VERSION_1_0)) {
-        return display->numHwLayers;
-    } else {
-        hwc_layer_list_t* list0 = reinterpret_cast<hwc_layer_list_t*>(display);
-        return list0->numHwLayers;
-    }
+    return hwc->common.version >= version;
 }
 
 // ---------------------------------------------------------------------------
@@ -182,14 +70,14 @@
         EventHandler& handler,
         framebuffer_device_t const* fbDev)
     : mFlinger(flinger),
-      mModule(0), mHwc(0), mCapacity(0),
-      mNumOVLayers(0), mNumFBLayers(0),
+      mModule(0), mHwc(0), mNumDisplays(1),
       mCBContext(new cb_context),
-      mEventHandler(handler), mRefreshPeriod(0),
+      mEventHandler(handler),
       mVSyncCount(0), mDebugForceFakeVSync(false)
 {
-    for (size_t i = 0; i < MAX_DISPLAYS; i++)
-        mLists[i] = NULL;
+    for (size_t i =0 ; i<MAX_DISPLAYS ; i++) {
+        mLists[i] = 0;
+    }
 
     char value[PROPERTY_VALUE_MAX];
     property_get("debug.sf.no_hw_vsync", value, "0");
@@ -203,8 +91,7 @@
         ALOGE_IF(err, "%s device failed to initialize (%s)",
                 HWC_HARDWARE_COMPOSER, strerror(-err));
         if (err == 0) {
-            if (HWC_REMOVE_DEPRECATED_VERSIONS &&
-                    mHwc->common.version < HWC_DEVICE_API_VERSION_1_0) {
+            if (mHwc->common.version < HWC_DEVICE_API_VERSION_1_0) {
                 ALOGE("%s device version %#x too old, will not be used",
                         HWC_HARDWARE_COMPOSER, mHwc->common.version);
                 hwc_close_1(mHwc);
@@ -213,45 +100,54 @@
         }
 
         if (mHwc) {
-            // always turn vsync off when we start
-            needVSyncThread = false;
-            if (hwcHasVsyncEvent(mHwc)) {
-                hwcEventControl(mHwc, 0, HWC_EVENT_VSYNC, 0);
-
-                int period;
-                if (mHwc->query(mHwc, HWC_VSYNC_PERIOD, &period) == NO_ERROR) {
-                    mRefreshPeriod = nsecs_t(period);
-                }
-            } else {
-                needVSyncThread = true;
-            }
-
             if (mHwc->registerProcs) {
                 mCBContext->hwc = this;
                 mCBContext->procs.invalidate = &hook_invalidate;
                 mCBContext->procs.vsync = &hook_vsync;
-                mHwc->registerProcs(mHwc, &mCBContext->procs);
                 memset(mCBContext->procs.zero, 0, sizeof(mCBContext->procs.zero));
+                mHwc->registerProcs(mHwc, &mCBContext->procs);
             }
 
-            // create initial empty display contents for display 0
-            createWorkList(MAIN, 0);
+            // always turn vsync off when we start
+            needVSyncThread = false;
+            mHwc->eventControl(mHwc, 0, HWC_EVENT_VSYNC, 0);
+
+            int period;
+            if (mHwc->query(mHwc, HWC_VSYNC_PERIOD, &period) == NO_ERROR) {
+                mDisplayData[HWC_DISPLAY_PRIMARY].refresh = nsecs_t(period);
+            }
+
+            // these IDs are always reserved
+            for (size_t i=0 ; i<HWC_NUM_DISPLAY_TYPES ; i++) {
+                mAllocatedDisplayIDs.markBit(i);
+                // TODO: we query xdpi / ydpi / refresh
+            }
+
+            // the number of displays we actually have depends on the
+            // hw composer version
+            if (mHwc->common.version == HWC_DEVICE_API_VERSION_1_1) {
+                // 1.1 adds support for multiple displays
+                mNumDisplays = HWC_NUM_DISPLAY_TYPES;
+            } else if (mHwc->common.version > HWC_DEVICE_API_VERSION_1_1) {
+                // 1.2 adds support for virtual displays
+                mNumDisplays = MAX_DISPLAYS;
+            }
         }
     }
 
-
     if (fbDev) {
-        if (mRefreshPeriod == 0) {
-            mRefreshPeriod = nsecs_t(1e9 / fbDev->fps);
-            ALOGW("getting VSYNC period from fb HAL: %lld", mRefreshPeriod);
+        // if we're here it means we are on version 1.0
+        DisplayData& disp(mDisplayData[HWC_DISPLAY_PRIMARY]);
+        disp.xdpi = fbDev->xdpi;
+        disp.ydpi = fbDev->ydpi;
+        if (disp.refresh == 0) {
+            disp.refresh = nsecs_t(1e9 / fbDev->fps);
+            ALOGW("getting VSYNC period from fb HAL: %lld", disp.refresh);
         }
-        mDpiX = fbDev->xdpi;
-        mDpiY = fbDev->ydpi;
-    }
-
-    if (mRefreshPeriod == 0) {
-        mRefreshPeriod = nsecs_t(1e9 / 60.0);
-        ALOGW("getting VSYNC period thin air: %lld", mRefreshPeriod);
+        if (disp.refresh == 0) {
+            disp.refresh = nsecs_t(1e9 / 60.0);
+            ALOGW("getting VSYNC period thin air: %lld", mDisplayData[HWC_DISPLAY_PRIMARY].refresh);
+        }
     }
 
     if (needVSyncThread) {
@@ -261,9 +157,7 @@
 }
 
 HWComposer::~HWComposer() {
-    hwcEventControl(mHwc, 0, EVENT_VSYNC, 0);
-    for (size_t i = 0; i < MAX_DISPLAYS; i++)
-        free(mLists[i]);
+    mHwc->eventControl(mHwc, 0, EVENT_VSYNC, 0);
     if (mVSyncThread != NULL) {
         mVSyncThread->requestExitAndWait();
     }
@@ -277,12 +171,17 @@
     return mHwc ? NO_ERROR : NO_INIT;
 }
 
-void HWComposer::hook_invalidate(struct hwc_procs* procs) {
-    reinterpret_cast<cb_context *>(procs)->hwc->invalidate();
+void HWComposer::hook_invalidate(const struct hwc_procs* procs) {
+    cb_context* ctx = reinterpret_cast<cb_context*>(
+            const_cast<hwc_procs_t*>(procs));
+    ctx->hwc->invalidate();
 }
 
-void HWComposer::hook_vsync(struct hwc_procs* procs, int dpy, int64_t timestamp) {
-    reinterpret_cast<cb_context *>(procs)->hwc->vsync(dpy, timestamp);
+void HWComposer::hook_vsync(const struct hwc_procs* procs, int dpy,
+        int64_t timestamp) {
+    cb_context* ctx = reinterpret_cast<cb_context*>(
+            const_cast<hwc_procs_t*>(procs));
+    ctx->hwc->vsync(dpy, timestamp);
 }
 
 void HWComposer::invalidate() {
@@ -296,8 +195,29 @@
     mLastHwVSync = timestamp;
 }
 
+int32_t HWComposer::allocateDisplayId() {
+    if (mAllocatedDisplayIDs.count() >= mNumDisplays) {
+        return NO_MEMORY;
+    }
+    int32_t id = mAllocatedDisplayIDs.firstUnmarkedBit();
+    mAllocatedDisplayIDs.markBit(id);
+    return id;
+}
+
+status_t HWComposer::freeDisplayId(int32_t id) {
+    if (id < HWC_NUM_DISPLAY_TYPES) {
+        // cannot free the reserved IDs
+        return BAD_VALUE;
+    }
+    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
+        return BAD_INDEX;
+    }
+    mAllocatedDisplayIDs.clearBit(id);
+    return NO_ERROR;
+}
+
 nsecs_t HWComposer::getRefreshPeriod() const {
-    return mRefreshPeriod;
+    return mDisplayData[HWC_DISPLAY_PRIMARY].refresh;
 }
 
 nsecs_t HWComposer::getRefreshTimestamp() const {
@@ -306,22 +226,22 @@
     // the refresh period and whatever closest timestamp we have.
     Mutex::Autolock _l(mLock);
     nsecs_t now = systemTime(CLOCK_MONOTONIC);
-    return now - ((now - mLastHwVSync) %  mRefreshPeriod);
+    return now - ((now - mLastHwVSync) %  mDisplayData[HWC_DISPLAY_PRIMARY].refresh);
 }
 
 float HWComposer::getDpiX() const {
-    return mDpiX;
+    return mDisplayData[HWC_DISPLAY_PRIMARY].xdpi;
 }
 
 float HWComposer::getDpiY() const {
-    return mDpiY;
+    return mDisplayData[HWC_DISPLAY_PRIMARY].ydpi;
 }
 
 void HWComposer::eventControl(int event, int enabled) {
     status_t err = NO_ERROR;
-    if (mHwc && mHwc->common.version >= HWC_DEVICE_API_VERSION_0_3) {
+    if (mHwc) {
         if (!mDebugForceFakeVSync) {
-            err = hwcEventControl(mHwc, 0, event, enabled);
+            err = mHwc->eventControl(mHwc, 0, event, enabled);
             // error here should not happen -- not sure what we should
             // do if it does.
             ALOGE_IF(err, "eventControl(%d, %d) failed %s",
@@ -335,140 +255,122 @@
 }
 
 status_t HWComposer::createWorkList(int32_t id, size_t numLayers) {
-    // FIXME: handle multiple displays
-    if (uint32_t(id) >= MAX_DISPLAYS)
+    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
         return BAD_INDEX;
+    }
 
     if (mHwc) {
-        // TODO: must handle multiple displays here
-        // mLists[0] is NULL only when this is called from the constructor
-        if (!mLists[0] || mCapacity < numLayers) {
-            free(mLists[0]);
-            size_t size = sizeofHwcLayerList(mHwc, numLayers);
-            mLists[0] = (hwc_display_contents_1_t*)malloc(size);
-            mCapacity = numLayers;
+        DisplayData& disp(mDisplayData[id]);
+        if (disp.capacity < numLayers) {
+            const 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;
         }
-        hwcFlags(mHwc, mLists[0]) = HWC_GEOMETRY_CHANGED;
-        hwcNumHwLayers(mHwc, mLists[0]) = numLayers;
-        if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
-            mLists[0]->flipFenceFd = -1;
-        }
+        disp.list->flags = HWC_GEOMETRY_CHANGED;
+        disp.list->numHwLayers = numLayers;
+        disp.list->flipFenceFd = -1;
     }
     return NO_ERROR;
 }
 
-status_t HWComposer::prepare() const {
-    int err = hwcPrepare(mHwc, 1,
-            const_cast<hwc_display_contents_1_t**>(mLists));
+status_t HWComposer::prepare() {
+    for (size_t i=0 ; i<mNumDisplays ; i++) {
+        mLists[i] = mDisplayData[i].list;
+        if (mLists[i]) {
+            mLists[i]->dpy = EGL_NO_DISPLAY;
+            mLists[i]->sur = EGL_NO_SURFACE;
+        }
+    }
+    int err = mHwc->prepare(mHwc, mNumDisplays, mLists);
     if (err == NO_ERROR) {
-
         // here we're just making sure that "skip" layers are set
         // to HWC_FRAMEBUFFER and we're also counting how many layers
         // we have of each type.
-        // It would be nice if we could get rid of this entirely, which I
-        // think is almost possible.
-
-        // TODO: must handle multiple displays here
-
-        size_t numOVLayers = 0;
-        size_t numFBLayers = 0;
-        size_t count = getNumLayers(0);
-
-        for (size_t i=0 ; i<count ; i++) {
-            int compositionType;
-            if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
-                hwc_layer_1_t* l = &mLists[0]->hwLayers[i];
-                if (l->flags & HWC_SKIP_LAYER) {
-                    l->compositionType = HWC_FRAMEBUFFER;
+        for (size_t i=0 ; i<mNumDisplays ; i++) {
+            DisplayData& disp(mDisplayData[i]);
+            disp.hasFbComp = false;
+            disp.hasOvComp = false;
+            if (disp.list) {
+                for (size_t i=0 ; i<disp.list->numHwLayers ; i++) {
+                    hwc_layer_1_t& l = disp.list->hwLayers[i];
+                    if (l.flags & HWC_SKIP_LAYER) {
+                        l.compositionType = HWC_FRAMEBUFFER;
+                    }
+                    if (l.compositionType == HWC_FRAMEBUFFER) {
+                        disp.hasFbComp = true;
+                    }
+                    if (l.compositionType == HWC_OVERLAY) {
+                        disp.hasOvComp = true;
+                    }
                 }
-                compositionType = l->compositionType;
-            } else {
-                // mList really has hwc_layer_list_t memory layout
-                hwc_layer_list_t* list0 = reinterpret_cast<hwc_layer_list_t*>(mLists[0]);
-                hwc_layer_t* l = &list0->hwLayers[i];
-                if (l->flags & HWC_SKIP_LAYER) {
-                    l->compositionType = HWC_FRAMEBUFFER;
-                }
-                compositionType = l->compositionType;
-            }
-
-            switch (compositionType) {
-                case HWC_OVERLAY:
-                    numOVLayers++;
-                    break;
-                case HWC_FRAMEBUFFER:
-                    numFBLayers++;
-                    break;
             }
         }
-        mNumOVLayers = numOVLayers;
-        mNumFBLayers = numFBLayers;
     }
     return (status_t)err;
 }
 
-size_t HWComposer::getLayerCount(int32_t id, int type) const {
-    // FIXME: handle multiple displays
-    if (uint32_t(id) >= MAX_DISPLAYS) {
-        // FIXME: in practice this is only use to know
-        // if we have at least one layer of type.
-        return (type == HWC_FRAMEBUFFER) ? 1 : 0;
-    }
-
-
-    switch (type) {
-        case HWC_OVERLAY:
-            return mNumOVLayers;
-        case HWC_FRAMEBUFFER:
-            return mNumFBLayers;
-    }
-    return 0;
+bool HWComposer::hasHwcComposition(int32_t id) const {
+    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
+        return false;
+    return mDisplayData[id].hasOvComp;
 }
 
-status_t HWComposer::commit(void* fbDisplay, void* fbSurface) const {
+bool HWComposer::hasGlesComposition(int32_t id) const {
+    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id))
+        return false;
+    return mDisplayData[id].hasFbComp;
+}
+
+status_t HWComposer::commit() {
     int err = NO_ERROR;
     if (mHwc) {
-        err = hwcSet(mHwc, fbDisplay, fbSurface, 1,
-                const_cast<hwc_display_contents_1_t**>(mLists));
-        if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
-            if (mLists[0]->flipFenceFd != -1) {
-                close(mLists[0]->flipFenceFd);
-                mLists[0]->flipFenceFd = -1;
+        if (mHwc->common.version == HWC_DEVICE_API_VERSION_1_0) {
+            // On version 1.0, the OpenGL ES target surface is communicated
+            // by the (dpy, sur) fields and we are guaranteed to have only
+            // a single display.
+            mLists[0]->dpy = eglGetCurrentDisplay();
+            mLists[0]->sur = eglGetCurrentSurface(EGL_DRAW);
+        }
+
+        err = mHwc->set(mHwc, mNumDisplays, mLists);
+
+        for (size_t i=0 ; i<mNumDisplays ; i++) {
+            DisplayData& disp(mDisplayData[i]);
+            if (disp.list) {
+                if (disp.list->flipFenceFd != -1) {
+                    close(disp.list->flipFenceFd);
+                    disp.list->flipFenceFd = -1;
+                }
+                disp.list->flags &= ~HWC_GEOMETRY_CHANGED;
             }
         }
-        hwcFlags(mHwc, mLists[0]) &= ~HWC_GEOMETRY_CHANGED;
     }
     return (status_t)err;
 }
 
 status_t HWComposer::release() const {
     if (mHwc) {
-        if (hwcHasVsyncEvent(mHwc)) {
-            hwcEventControl(mHwc, 0, HWC_EVENT_VSYNC, 0);
-        }
-        return (status_t)hwcBlank(mHwc, 0, 1);
+        mHwc->eventControl(mHwc, 0, HWC_EVENT_VSYNC, 0);
+        return (status_t)mHwc->blank(mHwc, 0, 1);
     }
     return NO_ERROR;
 }
 
 status_t HWComposer::acquire() const {
     if (mHwc) {
-        return (status_t)hwcBlank(mHwc, 0, 0);
+        return (status_t)mHwc->blank(mHwc, 0, 0);
     }
     return NO_ERROR;
 }
 
-status_t HWComposer::disable() {
-    if (mHwc) {
-        hwcNumHwLayers(mHwc, mLists[0]) = 0;
-        int err = hwcPrepare(mHwc, 1, mLists);
-        return (status_t)err;
+size_t HWComposer::getNumLayers(int32_t id) const {
+    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
+        return 0;
     }
-    return NO_ERROR;
-}
-
-size_t HWComposer::getNumLayers(int32_t id) const { // FIXME: handle multiple displays
-    return mHwc ? hwcNumHwLayers(mHwc, mLists[0]) : 0;
+    return (mHwc && mDisplayData[id].list) ?
+            mDisplayData[id].list->numHwLayers : 0;
 }
 
 /*
@@ -496,78 +398,6 @@
     }
 };
 
-// #if !HWC_REMOVE_DEPRECATED_VERSIONS
-/*
- * Concrete implementation of HWCLayer for HWC_DEVICE_API_VERSION_0_3
- * This implements the HWCLayer side of HWCIterableLayer.
- */
-class HWCLayerVersion0 : public Iterable<HWCLayerVersion0, hwc_layer_t> {
-public:
-    HWCLayerVersion0(hwc_layer_t* layer)
-        : Iterable<HWCLayerVersion0, hwc_layer_t>(layer) { }
-
-    virtual int32_t getCompositionType() const {
-        return getLayer()->compositionType;
-    }
-    virtual uint32_t getHints() const {
-        return getLayer()->hints;
-    }
-    virtual int getAndResetReleaseFenceFd() {
-        // not supported on VERSION_03
-        return -1;
-    }
-    virtual void setAcquireFenceFd(int fenceFd) {
-        if (fenceFd != -1) {
-            ALOGE("HWC 0.x can't handle acquire fences");
-            close(fenceFd);
-        }
-    }
-
-    virtual void setDefaultState() {
-        getLayer()->compositionType = HWC_FRAMEBUFFER;
-        getLayer()->hints = 0;
-        getLayer()->flags = HWC_SKIP_LAYER;
-        getLayer()->transform = 0;
-        getLayer()->blending = HWC_BLENDING_NONE;
-        getLayer()->visibleRegionScreen.numRects = 0;
-        getLayer()->visibleRegionScreen.rects = NULL;
-    }
-    virtual void setSkip(bool skip) {
-        if (skip) {
-            getLayer()->flags |= HWC_SKIP_LAYER;
-        } else {
-            getLayer()->flags &= ~HWC_SKIP_LAYER;
-        }
-    }
-    virtual void setBlending(uint32_t blending) {
-        getLayer()->blending = blending;
-    }
-    virtual void setTransform(uint32_t transform) {
-        getLayer()->transform = transform;
-    }
-    virtual void setFrame(const Rect& frame) {
-        reinterpret_cast<Rect&>(getLayer()->displayFrame) = frame;
-    }
-    virtual void setCrop(const Rect& crop) {
-        reinterpret_cast<Rect&>(getLayer()->sourceCrop) = crop;
-    }
-    virtual void setVisibleRegionScreen(const Region& reg) {
-        getLayer()->visibleRegionScreen.rects =
-                reinterpret_cast<hwc_rect_t const *>(
-                        reg.getArray(&getLayer()->visibleRegionScreen.numRects));
-    }
-    virtual void setBuffer(const sp<GraphicBuffer>& buffer) {
-        if (buffer == 0 || buffer->handle == 0) {
-            getLayer()->compositionType = HWC_FRAMEBUFFER;
-            getLayer()->flags |= HWC_SKIP_LAYER;
-            getLayer()->handle = 0;
-        } else {
-            getLayer()->handle = buffer->handle;
-        }
-    }
-};
-// #endif // !HWC_REMOVE_DEPRECATED_VERSIONS
-
 /*
  * Concrete implementation of HWCLayer for HWC_DEVICE_API_VERSION_1_0.
  * This implements the HWCLayer side of HWCIterableLayer.
@@ -642,19 +472,14 @@
  * returns an iterator initialized at a given index in the layer list
  */
 HWComposer::LayerListIterator HWComposer::getLayerIterator(int32_t id, size_t index) {
-    // FIXME: handle multiple displays
-    if (uint32_t(id) >= MAX_DISPLAYS)
+    if (uint32_t(id)>31 || !mAllocatedDisplayIDs.hasBit(id)) {
         return LayerListIterator();
-
-    if (!mHwc || index > hwcNumHwLayers(mHwc, mLists[0]))
-        return LayerListIterator();
-    if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
-        return LayerListIterator(new HWCLayerVersion1(mLists[0]->hwLayers),
-                index);
-    } else {
-        hwc_layer_list_t* list0 = reinterpret_cast<hwc_layer_list_t*>(mLists[0]);
-        return LayerListIterator(new HWCLayerVersion0(list0->hwLayers), index);
     }
+    const DisplayData& disp(mDisplayData[id]);
+    if (!mHwc || !disp.list || index > disp.list->numHwLayers) {
+        return LayerListIterator();
+    }
+    return LayerListIterator(new HWCLayerVersion1(disp.list->hwLayers), index);
 }
 
 /*
@@ -674,44 +499,41 @@
 void HWComposer::dump(String8& result, char* buffer, size_t SIZE,
         const Vector< sp<LayerBase> >& visibleLayersSortedByZ) const {
     if (mHwc) {
-        hwc_layer_list_t* list0 = reinterpret_cast<hwc_layer_list_t*>(mLists[0]);
-
         result.append("Hardware Composer state:\n");
-        result.appendFormat("  mDebugForceFakeVSync=%d\n",
-                mDebugForceFakeVSync);
-        result.appendFormat("  numHwLayers=%u, flags=%08x\n",
-                hwcNumHwLayers(mHwc, mLists[0]), hwcFlags(mHwc, mLists[0]));
-        result.append(
-                "   type   |  handle  |   hints  |   flags  | tr | blend |  format  |       source crop         |           frame           name \n"
-                "----------+----------+----------+----------+----+-------+----------+---------------------------+--------------------------------\n");
-        //      " ________ | ________ | ________ | ________ | __ | _____ | ________ | [_____,_____,_____,_____] | [_____,_____,_____,_____]
-        for (size_t i=0 ; i<hwcNumHwLayers(mHwc, mLists[0]) ; i++) {
-            hwc_layer_1_t const* lp;
-            if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
-                lp = &mLists[0]->hwLayers[i];
-            } else {
-                // FIXME: here we rely on hwc_layer_1_t and hwc_layer_t having the same layout
-                lp = reinterpret_cast<hwc_layer_1_t const*>(&list0->hwLayers[i]);
-            }
-            const sp<LayerBase> layer(visibleLayersSortedByZ[i]);
-            int32_t format = -1;
-            if (layer->getLayer() != NULL) {
-                const sp<GraphicBuffer>& buffer(layer->getLayer()->getActiveBuffer());
-                if (buffer != NULL) {
-                    format = buffer->getPixelFormat();
+        result.appendFormat("  mDebugForceFakeVSync=%d\n", mDebugForceFakeVSync);
+        for (size_t i=0 ; i<mNumDisplays ; i++) {
+            const DisplayData& disp(mDisplayData[i]);
+            if (disp.list) {
+                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");
+                //      " ________ | ________ | ________ | ________ | __ | _____ | ________ | [_____,_____,_____,_____] | [_____,_____,_____,_____]
+                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(
+                                layer->getLayer()->getActiveBuffer());
+                        if (buffer != NULL) {
+                            format = buffer->getPixelFormat();
+                        }
+                    }
+                    result.appendFormat(
+                            " %8s | %08x | %08x | %08x | %02x | %05x | %08x | [%5d,%5d,%5d,%5d] | [%5d,%5d,%5d,%5d] %s\n",
+                            l.compositionType ? "OVERLAY" : "FB",
+                                    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());
                 }
             }
-            const hwc_layer_1_t& l(*lp);
-            result.appendFormat(
-                    " %8s | %08x | %08x | %08x | %02x | %05x | %08x | [%5d,%5d,%5d,%5d] | [%5d,%5d,%5d,%5d] %s\n",
-                    l.compositionType ? "OVERLAY" : "FB",
-                    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());
         }
     }
-    if (mHwc && hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_0_1) && mHwc->dump) {
+
+    if (mHwc && mHwc->dump) {
         mHwc->dump(mHwc, buffer, SIZE);
         result.append(buffer);
     }
@@ -722,7 +544,7 @@
 HWComposer::VSyncThread::VSyncThread(HWComposer& hwc)
     : mHwc(hwc), mEnabled(false),
       mNextFakeVSync(0),
-      mRefreshPeriod(hwc.mRefreshPeriod)
+      mRefreshPeriod(hwc.getRefreshPeriod())
 {
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index ac2257e..7b92d2e 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -28,6 +28,7 @@
 #include <utils/Thread.h>
 #include <utils/Timers.h>
 #include <utils/Vector.h>
+#include <utils/BitSet.h>
 
 extern "C" int clock_nanosleep(clockid_t clock_id, int flags,
                            const struct timespec *request,
@@ -58,9 +59,7 @@
     };
 
     enum {
-        MAIN = 0,
-        HDMI = 1,
-        MAX_DISPLAYS
+        MAX_DISPLAYS = HWC_NUM_DISPLAY_TYPES + 1
     };
 
     HWComposer(
@@ -72,14 +71,23 @@
 
     status_t initCheck() const;
 
-    // Asks the HAL what it can do
-    status_t prepare() const;
+    // returns a display ID starting at MAX_DISPLAYS, this ID
+    // is to be used with createWorkList (and all other
+    // methods requiring an ID below).
+    // IDs below MAX_DISPLAY are pre-defined and therefore are always valid.
+    // returns a negative error code if an ID cannot be allocated
+    int32_t allocateDisplayId();
 
-    // disable hwc until next createWorkList
-    status_t disable();
+    // recycles the given ID and frees the associated worklist.
+    // IDs below MAX_DISPLAYS are not recycled
+    status_t freeDisplayId(int32_t id);
+
+
+    // Asks the HAL what it can do
+    status_t prepare();
 
     // commits the list
-    status_t commit(void* fbDisplay, void* fbSurface) const;
+    status_t commit();
 
     // release hardware resources and blank screen
     status_t release() const;
@@ -90,9 +98,11 @@
     // create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED.
     status_t createWorkList(int32_t id, size_t numLayers);
 
-    // get number of layers of the given type as updated in prepare().
-    // type is HWC_OVERLAY or HWC_FRAMEBUFFER
-    size_t getLayerCount(int32_t id, int type) 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;
 
     // needed forward declarations
     class LayerListIterator;
@@ -231,32 +241,45 @@
 
     struct cb_context;
 
-    static void hook_invalidate(struct hwc_procs* procs);
-    static void hook_vsync(struct hwc_procs* procs, int dpy, int64_t timestamp);
+    static void hook_invalidate(const struct hwc_procs* procs);
+    static void hook_vsync(const struct hwc_procs* procs, int dpy,
+            int64_t timestamp);
 
     inline void invalidate();
     inline void vsync(int dpy, int64_t timestamp);
 
 
+    struct DisplayData {
+        DisplayData() : xdpi(0), ydpi(0), refresh(0),
+            hasFbComp(false), hasOvComp(false),
+            capacity(0), list(NULL) { }
+        ~DisplayData() {
+            free(list);
+        }
+        float xdpi;
+        float ydpi;
+        nsecs_t refresh;
+        bool hasFbComp;
+        bool hasOvComp;
+        size_t capacity;
+        hwc_display_contents_1* list;
+    };
+
     sp<SurfaceFlinger>              mFlinger;
     hw_module_t const*              mModule;
     struct hwc_composer_device_1*   mHwc;
     // invariant: mLists[0] != NULL iff mHwc != NULL
-    // TODO: decide whether mLists[i>0] should be non-NULL when display i is
-    //       not attached/enabled.
+    // mLists[i>0] can be NULL. that display is to be ignored
     struct hwc_display_contents_1*  mLists[MAX_DISPLAYS];
+    DisplayData                     mDisplayData[MAX_DISPLAYS];
+    size_t                          mNumDisplays;
 
-    size_t                          mCapacity;
-    mutable size_t                  mNumOVLayers;
-    mutable size_t                  mNumFBLayers;
     cb_context*                     mCBContext;
     EventHandler&                   mEventHandler;
-    nsecs_t                         mRefreshPeriod;
-    float                           mDpiX;
-    float                           mDpiY;
     size_t                          mVSyncCount;
     sp<VSyncThread>                 mVSyncThread;
     bool                            mDebugForceFakeVSync;
+    BitSet32                        mAllocatedDisplayIDs;
 
     // protected by mLock
     mutable Mutex mLock;
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index 3833f48..a39b7d8 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -19,6 +19,8 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include <cutils/compiler.h>
+
 #include <gui/BitTube.h>
 #include <gui/IDisplayEventConnection.h>
 #include <gui/DisplayEventReceiver.h>
@@ -58,14 +60,6 @@
     return NO_ERROR;
 }
 
-status_t EventThread::unregisterDisplayEventConnection(
-        const wp<EventThread::Connection>& connection) {
-    Mutex::Autolock _l(mLock);
-    mDisplayEventConnections.remove(connection);
-    mCondition.broadcast();
-    return NO_ERROR;
-}
-
 void EventThread::removeDisplayEventConnection(
         const wp<EventThread::Connection>& connection) {
     Mutex::Autolock _l(mLock);
@@ -120,118 +114,115 @@
 }
 
 bool EventThread::threadLoop() {
-
-    nsecs_t timestamp;
-    size_t vsyncCount;
-    size_t activeEvents;
     DisplayEventReceiver::Event vsync;
-    Vector< sp<EventThread::Connection> > activeConnections;
+    Vector< sp<EventThread::Connection> > signalConnections;
+    signalConnections = waitForEvent(&vsync);
+
+    // dispatch vsync events to listeners...
+    const size_t count = signalConnections.size();
+    for (size_t i=0 ; i<count ; i++) {
+        const sp<Connection>& conn(signalConnections[i]);
+        // now see if we still need to report this VSYNC event
+        status_t err = conn->postEvent(vsync);
+        if (err == -EAGAIN || err == -EWOULDBLOCK) {
+            // The destination doesn't accept events anymore, it's probably
+            // full. For now, we just drop the events on the floor.
+            // Note that some events cannot be dropped and would have to be
+            // re-sent later. Right-now we don't have the ability to do
+            // this, but it doesn't matter for VSYNC.
+        } else if (err < 0) {
+            // handle any other error on the pipe as fatal. the only
+            // reasonable thing to do is to clean-up this connection.
+            // The most common error we'll get here is -EPIPE.
+            removeDisplayEventConnection(signalConnections[i]);
+        }
+    }
+    return true;
+}
+
+Vector< sp<EventThread::Connection> > EventThread::waitForEvent(
+        DisplayEventReceiver::Event* event)
+{
+    Mutex::Autolock _l(mLock);
+
+    size_t vsyncCount;
+    nsecs_t timestamp;
+    Vector< sp<EventThread::Connection> > signalConnections;
 
     do {
-        Mutex::Autolock _l(mLock);
         // latch VSYNC event if any
+        bool waitForVSync = false;
+        vsyncCount = mVSyncCount;
         timestamp = mVSyncTimestamp;
         mVSyncTimestamp = 0;
 
-        // check if we should be waiting for VSYNC events
-        activeEvents = 0;
-        bool waitForNextVsync = false;
+        // find out connections waiting for events
         size_t count = mDisplayEventConnections.size();
         for (size_t i=0 ; i<count ; i++) {
             sp<Connection> connection(mDisplayEventConnections[i].promote());
             if (connection != NULL) {
-                activeConnections.add(connection);
                 if (connection->count >= 0) {
-                    // at least one continuous mode or active one-shot event
-                    waitForNextVsync = true;
-                    activeEvents++;
-                    break;
+                    // we need vsync events because at least
+                    // one connection is waiting for it
+                    waitForVSync = true;
+                    if (timestamp) {
+                        // we consume the event only if it's time
+                        // (ie: we received a vsync event)
+                        if (connection->count == 0) {
+                            // fired this time around
+                            connection->count = -1;
+                            signalConnections.add(connection);
+                        } else if (connection->count == 1 ||
+                                (vsyncCount % connection->count) == 0) {
+                            // continuous event, and time to report it
+                            signalConnections.add(connection);
+                        }
+                    }
                 }
-            }
-        }
-
-        if (timestamp) {
-            if (!waitForNextVsync) {
-                // we received a VSYNC but we have no clients
-                // don't report it, and disable VSYNC events
-                disableVSyncLocked();
             } else {
-                // report VSYNC event
-                break;
-            }
-        } else {
-            // never disable VSYNC events immediately, instead
-            // we'll wait to receive the event and we'll
-            // reevaluate whether we need to dispatch it and/or
-            // disable VSYNC events then.
-            if (waitForNextVsync) {
-                // enable
-                enableVSyncLocked();
+                // we couldn't promote this reference, the connection has
+                // died, so clean-up!
+                mDisplayEventConnections.removeAt(i);
+                --i; --count;
             }
         }
 
-        // wait for something to happen
-        if (mUseSoftwareVSync && waitForNextVsync) {
-            // h/w vsync cannot be used (screen is off), so we use
-            // a  timeout instead. it doesn't matter how imprecise this
-            // is, we just need to make sure to serve the clients
-            if (mCondition.waitRelative(mLock, ms2ns(16)) == TIMED_OUT) {
-                mVSyncTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
-                mVSyncCount++;
-            }
-        } else {
-            mCondition.wait(mLock);
+        // Here we figure out if we need to enable or disable vsyncs
+        if (timestamp && !waitForVSync) {
+            // we received a VSYNC but we have no clients
+            // don't report it, and disable VSYNC events
+            disableVSyncLocked();
+        } else if (!timestamp && waitForVSync) {
+            enableVSyncLocked();
         }
-        vsyncCount = mVSyncCount;
-    } while (!activeConnections.size());
 
-    if (!activeEvents) {
-        // no events to return. start over.
-        // (here we make sure to exit the scope of this function
-        //  so that we release our Connection references)
-        return true;
-    }
+        // note: !timestamp implies signalConnections.isEmpty()
+        if (!timestamp) {
+            // wait for something to happen
+            if (CC_UNLIKELY(mUseSoftwareVSync && waitForVSync)) {
+                // h/w vsync cannot be used (screen is off), so we use
+                // a  timeout instead. it doesn't matter how imprecise this
+                // is, we just need to make sure to serve the clients
+                if (mCondition.waitRelative(mLock, ms2ns(16)) == TIMED_OUT) {
+                    mVSyncTimestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+                    mVSyncCount++;
+                }
+            } else {
+                // This is where we spend most of our time, waiting
+                // for a vsync events and registered clients
+                mCondition.wait(mLock);
+            }
+        }
+    } while (signalConnections.isEmpty());
+
+    // here we're guaranteed to have a timestamp and some connections to signal
 
     // dispatch vsync events to listeners...
-    vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
-    vsync.header.timestamp = timestamp;
-    vsync.vsync.count = vsyncCount;
+    event->header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
+    event->header.timestamp = timestamp;
+    event->vsync.count = vsyncCount;
 
-    const size_t count = activeConnections.size();
-    for (size_t i=0 ; i<count ; i++) {
-        const sp<Connection>& conn(activeConnections[i]);
-        // now see if we still need to report this VSYNC event
-        const int32_t vcount = conn->count;
-        if (vcount >= 0) {
-            bool reportVsync = false;
-            if (vcount == 0) {
-                // fired this time around
-                conn->count = -1;
-                reportVsync = true;
-            } else if (vcount == 1 || (vsyncCount % vcount) == 0) {
-                // continuous event, and time to report it
-                reportVsync = true;
-            }
-
-            if (reportVsync) {
-                status_t err = conn->postEvent(vsync);
-                if (err == -EAGAIN || err == -EWOULDBLOCK) {
-                    // The destination doesn't accept events anymore, it's probably
-                    // full. For now, we just drop the events on the floor.
-                    // Note that some events cannot be dropped and would have to be
-                    // re-sent later. Right-now we don't have the ability to do
-                    // this, but it doesn't matter for VSYNC.
-                } else if (err < 0) {
-                    // handle any other error on the pipe as fatal. the only
-                    // reasonable thing to do is to clean-up this connection.
-                    // The most common error we'll get here is -EPIPE.
-                    removeDisplayEventConnection(activeConnections[i]);
-                }
-            }
-        }
-    }
-
-    return true;
+    return signalConnections;
 }
 
 void EventThread::enableVSyncLocked() {
@@ -279,7 +270,8 @@
 }
 
 EventThread::Connection::~Connection() {
-    mEventThread->unregisterDisplayEventConnection(this);
+    // do nothing here -- clean-up will happen automatically
+    // when the main thread wakes up
 }
 
 void EventThread::Connection::onFirstRef() {
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index d23b9fa..20ea34d 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -47,7 +47,6 @@
         // count >= 1 : continuous event. count is the vsync rate
         // count == 0 : one-shot event that has not fired
         // count ==-1 : one-shot event that fired this round / disabled
-        // count ==-2 : one-shot event that fired the round before
         int32_t count;
 
     private:
@@ -66,7 +65,6 @@
 
     sp<Connection> createEventConnection() const;
     status_t registerDisplayEventConnection(const sp<Connection>& connection);
-    status_t unregisterDisplayEventConnection(const wp<Connection>& connection);
 
     void setVsyncRate(uint32_t count, const sp<Connection>& connection);
     void requestNextVsync(const sp<Connection>& connection);
@@ -80,6 +78,9 @@
     // called when receiving a vsync event
     void onVSyncReceived(int display, nsecs_t timestamp);
 
+    Vector< sp<EventThread::Connection> > waitForEvent(
+            DisplayEventReceiver::Event* event);
+
     void dump(String8& result, char* buffer, size_t SIZE) const;
 
 private:
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index c63d0cf..e6e258f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -409,7 +409,8 @@
         mCurrentState.displays.add(mDefaultDisplays[i], DisplayDeviceState(i));
     }
     sp<DisplayDevice> hw = new DisplayDevice(this,
-            DisplayDevice::DISPLAY_ID_MAIN, anw, fbs, mEGLConfig);
+            DisplayDevice::DISPLAY_ID_MAIN, HWC_DISPLAY_PRIMARY,
+            anw, fbs, mEGLConfig);
     mDisplays.add(hw->getDisplayId(), hw);
 
     //  initialize OpenGL ES
@@ -779,29 +780,30 @@
         mHwWorkListDirty = false;
         for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
             sp<const DisplayDevice> hw(mDisplays[dpy]);
-            const Vector< sp<LayerBase> >& currentLayers(
+            const int32_t id = hw->getHwcDisplayId();
+            if (id >= 0) {
+                const Vector< sp<LayerBase> >& currentLayers(
                     hw->getVisibleLayersSortedByZ());
-            const size_t count = currentLayers.size();
+                const size_t count = currentLayers.size();
+                if (hwc.createWorkList(id, count) >= 0) {
+                    HWComposer::LayerListIterator cur = hwc.begin(id);
+                    const HWComposer::LayerListIterator end = hwc.end(id);
+                    for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
+                        const sp<LayerBase>& layer(currentLayers[i]);
 
-            const int32_t id = hw->getDisplayId();
-            if (hwc.createWorkList(id, count) >= 0) {
-                HWComposer::LayerListIterator cur = hwc.begin(id);
-                const HWComposer::LayerListIterator end = hwc.end(id);
-                for (size_t i=0 ; cur!=end && i<count ; ++i, ++cur) {
-                    const sp<LayerBase>& layer(currentLayers[i]);
-
-                    if (CC_UNLIKELY(workListsDirty)) {
-                        layer->setGeometry(hw, *cur);
-                        if (mDebugDisableHWC || mDebugRegion) {
-                            cur->setSkip(true);
+                        if (CC_UNLIKELY(workListsDirty)) {
+                            layer->setGeometry(hw, *cur);
+                            if (mDebugDisableHWC || mDebugRegion) {
+                                cur->setSkip(true);
+                            }
                         }
-                    }
 
-                    /*
-                     * update the per-frame h/w composer data for each layer
-                     * and build the transparent region of the FB
-                     */
-                    layer->setPerFrameData(hw, *cur);
+                        /*
+                         * update the per-frame h/w composer data for each layer
+                         * and build the transparent region of the FB
+                         */
+                        layer->setPerFrameData(hw, *cur);
+                    }
                 }
             }
         }
@@ -841,21 +843,20 @@
 
     HWComposer& hwc(getHwComposer());
     if (hwc.initCheck() == NO_ERROR) {
-        // FIXME: eventually commit() won't take arguments
         // FIXME: EGL spec says:
         //   "surface must be bound to the calling thread's current context,
         //    for the current rendering API."
         DisplayDevice::makeCurrent(
                 getDisplayDevice(DisplayDevice::DISPLAY_ID_MAIN), mEGLContext);
-        hwc.commit(mEGLDisplay, getDefaultDisplayDevice()->getEGLSurface());
+        hwc.commit();
     }
 
     for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
         sp<const DisplayDevice> hw(mDisplays[dpy]);
         const Vector< sp<LayerBase> >& currentLayers(hw->getVisibleLayersSortedByZ());
         const size_t count = currentLayers.size();
-        if (hwc.initCheck() == NO_ERROR) {
-            int32_t id = hw->getDisplayId();
+        int32_t id = hw->getHwcDisplayId();
+        if (id >=0 && hwc.initCheck() == NO_ERROR) {
             HWComposer::LayerListIterator cur = hwc.begin(id);
             const HWComposer::LayerListIterator end = hwc.end(id);
             for (size_t i = 0; cur != end && i < count; ++i, ++cur) {
@@ -951,12 +952,15 @@
                     if (state.surface->asBinder() != draw[i].surface->asBinder()) {
                         // changing the surface is like destroying and
                         // recreating the DisplayDevice
+                        const int32_t hwcDisplayId =
+                            (uint32_t(state.id) < DisplayDevice::DISPLAY_ID_COUNT) ?
+                                state.id : getHwComposer().allocateDisplayId();
 
                         sp<SurfaceTextureClient> stc(
                                 new SurfaceTextureClient(state.surface));
 
                         sp<DisplayDevice> disp = new DisplayDevice(this,
-                                state.id, stc, 0, mEGLConfig);
+                            state.id, hwcDisplayId, stc, 0, mEGLConfig);
 
                         disp->setLayerStack(state.layerStack);
                         disp->setOrientation(state.orientation);
@@ -982,10 +986,14 @@
             for (size_t i=0 ; i<cc ; i++) {
                 if (draw.indexOfKey(curr.keyAt(i)) < 0) {
                     const DisplayDeviceState& state(curr[i]);
+                    const int32_t hwcDisplayId =
+                        (uint32_t(state.id) < DisplayDevice::DISPLAY_ID_COUNT) ?
+                            state.id : getHwComposer().allocateDisplayId();
+
                     sp<SurfaceTextureClient> stc(
                             new SurfaceTextureClient(state.surface));
-                    sp<DisplayDevice> disp = new DisplayDevice(this, state.id,
-                            stc, 0, mEGLConfig);
+                    sp<DisplayDevice> disp = new DisplayDevice(this,
+                        state.id, hwcDisplayId, stc, 0, mEGLConfig);
                     mDisplays.add(state.id, disp);
                 }
             }
@@ -1251,12 +1259,13 @@
 void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty)
 {
     HWComposer& hwc(getHwComposer());
-    int32_t id = hw->getDisplayId();
+    int32_t id = hw->getHwcDisplayId();
     HWComposer::LayerListIterator cur = hwc.begin(id);
     const HWComposer::LayerListIterator end = hwc.end(id);
 
-    const size_t fbLayerCount = hwc.getLayerCount(id, HWC_FRAMEBUFFER);
-    if (cur==end || fbLayerCount) {
+    const bool hasGlesComposition = hwc.hasGlesComposition(id);
+    const bool hasHwcComposition = hwc.hasHwcComposition(id);
+    if (cur==end || hasGlesComposition) {
 
         DisplayDevice::makeCurrent(hw, mEGLContext);
 
@@ -1265,7 +1274,7 @@
         glLoadIdentity();
 
         // Never touch the framebuffer if we don't have any framebuffer layers
-        if (hwc.getLayerCount(id, HWC_OVERLAY)) {
+        if (hasHwcComposition) {
             // when using overlays, we assume a fully transparent framebuffer
             // NOTE: we could reduce how much we need to clear, for instance
             // remove where there are opaque FB layers. however, on some