We now have a real list of displays.

displays can be dynamically added or removed, and the
list is part of the SF's transaction.

Change-Id: I4186ea39f1317c0e7c044f869004017738968fab
diff --git a/include/utils/KeyedVector.h b/include/utils/KeyedVector.h
index 20575ee..47c2c56 100644
--- a/include/utils/KeyedVector.h
+++ b/include/utils/KeyedVector.h
@@ -56,7 +56,10 @@
     inline  size_t          capacity() const            { return mVector.capacity(); }
     //! setst the capacity. capacity can never be reduced less than size()
     inline ssize_t          setCapacity(size_t size)    { return mVector.setCapacity(size); }
-    
+
+    // returns true if the arguments is known to be identical to this vector
+    inline bool isIdenticalTo(const KeyedVector& rhs) const;
+
     /*! 
      * accessors
      */
@@ -64,6 +67,7 @@
             const VALUE&    valueAt(size_t index) const;
             const KEY&      keyAt(size_t index) const;
             ssize_t         indexOfKey(const KEY& key) const;
+            const VALUE&    operator[] (size_t index) const;
 
     /*!
      * modifying the array
@@ -123,6 +127,11 @@
 }
 
 template<typename KEY, typename VALUE> inline
+bool KeyedVector<KEY,VALUE>::isIdenticalTo(const KeyedVector<KEY,VALUE>& rhs) const {
+    return mVector.array() == rhs.mVector.array();
+}
+
+template<typename KEY, typename VALUE> inline
 ssize_t KeyedVector<KEY,VALUE>::indexOfKey(const KEY& key) const {
     return mVector.indexOf( key_value_pair_t<KEY,VALUE>(key) );
 }
@@ -140,6 +149,11 @@
 }
 
 template<typename KEY, typename VALUE> inline
+const VALUE& KeyedVector<KEY,VALUE>::operator[] (size_t index) const {
+    return valueAt(index);
+}
+
+template<typename KEY, typename VALUE> inline
 const KEY& KeyedVector<KEY,VALUE>::keyAt(size_t index) const {
     return mVector.itemAt(index).key;
 }
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index b09b77c..a33b94b 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -97,33 +97,55 @@
  *
  */
 
+DisplayDevice::DisplayDevice()
+    : mId(0),
+      mDisplay(EGL_NO_DISPLAY),
+      mSurface(EGL_NO_SURFACE),
+      mContext(EGL_NO_CONTEXT)
+{
+}
+
 DisplayDevice::DisplayDevice(
         const sp<SurfaceFlinger>& flinger,
         int display,
         const sp<SurfaceTextureClient>& surface,
         EGLConfig config)
-    :   mFlinger(flinger),
-        mDisplayId(display),
-        mNativeWindow(surface),
-        mDisplay(EGL_NO_DISPLAY),
-        mSurface(EGL_NO_SURFACE),
-        mContext(EGL_NO_CONTEXT),
-        mDpiX(), mDpiY(),
-        mRefreshRate(),
-        mDensity(),
-        mDisplayWidth(), mDisplayHeight(), mFormat(),
-        mFlags(),
-        mPageFlipCount(),
-        mRefreshPeriod(),
-        mSecureLayerVisible(false),
-        mScreenAcquired(false),
-        mOrientation(),
-        mLayerStack(0)
+    : mFlinger(flinger),
+      mId(display),
+      mNativeWindow(surface),
+      mDisplay(EGL_NO_DISPLAY),
+      mSurface(EGL_NO_SURFACE),
+      mContext(EGL_NO_CONTEXT),
+      mDpiX(), mDpiY(),
+      mRefreshRate(),
+      mDensity(),
+      mDisplayWidth(), mDisplayHeight(), mFormat(),
+      mFlags(),
+      mPageFlipCount(),
+      mRefreshPeriod(),
+      mSecureLayerVisible(false),
+      mScreenAcquired(false),
+      mOrientation(),
+      mLayerStack(0)
 {
     init(config);
 }
 
 DisplayDevice::~DisplayDevice() {
+    // DO NOT call terminate() from here, because we create
+    // temporaries of this class (on the stack typically), and we don't
+    // want to destroy the EGLSurface in that case
+}
+
+void DisplayDevice::terminate() {
+    if (mSurface != EGL_NO_SURFACE) {
+        eglDestroySurface(mDisplay, mSurface);
+        mSurface = EGL_NO_SURFACE;
+    }
+}
+
+bool DisplayDevice::isValid() const {
+    return mFlinger != NULL;
 }
 
 float DisplayDevice::getDpiX() const {
@@ -389,5 +411,6 @@
         h = tmp;
     }
     mOrientation = orientation;
+    dirtyRegion.set(bounds());
     return NO_ERROR;
 }
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index e1c2d11..96590a0 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -49,10 +49,17 @@
     Region undefinedRegion;
 
     enum {
+        DISPLAY_ID_MAIN = 0,
+        DISPLAY_ID_HDMI = 1
+    };
+
+    enum {
         PARTIAL_UPDATES = 0x00020000, // video driver feature
         SWAP_RECTANGLE  = 0x00080000,
     };
 
+    DisplayDevice();
+
     DisplayDevice(
             const sp<SurfaceFlinger>& flinger,
             int dpy,
@@ -61,6 +68,14 @@
 
     ~DisplayDevice();
 
+    // must be called when this object is no longer needed. this will
+    // render the associated EGLSurface invalid.
+    void terminate();
+
+    // whether this is a valid object. An invalid DisplayDevice is returned
+    // when an non existing id is requested
+    bool isValid() const;
+
     // Flip the front and back buffers if the back buffer is "dirty".  Might
     // be instantaneous, might involve copying the frame buffer around.
     void flip(const Region& dirty) const;
@@ -110,6 +125,9 @@
     uint32_t getPageFlipCount() const;
     void dump(String8& res) const;
 
+    inline bool operator < (const DisplayDevice& rhs) const {
+        return mId < rhs.mId;
+    }
 
 private:
     void init(EGLConfig config);
@@ -118,7 +136,7 @@
      *  Constants, set during initialization
      */
     sp<SurfaceFlinger> mFlinger;
-    int mDisplayId;
+    int32_t mId;
 
     // ANativeWindow this display is rendering into
     sp<SurfaceTextureClient> mNativeWindow;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7fb825a..f25eb5f 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -370,11 +370,12 @@
     mEGLContext = createGLContext(mEGLDisplay, mEGLConfig);
 
     // initialize our main display hardware
-    DisplayDevice* const hw = new DisplayDevice(this, 0, anw, mEGLConfig);
-    mDisplayDevices[0] = hw;
+    mCurrentState.displays.add(DisplayDevice::DISPLAY_ID_MAIN, DisplayDeviceState());
+    DisplayDevice hw(this, DisplayDevice::DISPLAY_ID_MAIN, anw, mEGLConfig);
+    mDisplays.add(DisplayDevice::DISPLAY_ID_MAIN, hw);
 
     //  initialize OpenGL ES
-    EGLSurface surface = hw->getEGLSurface();
+    EGLSurface surface = hw.getEGLSurface();
     initializeGL(mEGLDisplay, surface);
 
     // start the EventThread
@@ -384,7 +385,10 @@
     // initialize the H/W composer
     mHwc = new HWComposer(this,
             *static_cast<HWComposer::EventHandler *>(this),
-            hw->getRefreshPeriod());
+            hw.getRefreshPeriod());
+
+    // initialize our drawing state
+    mDrawingState = mCurrentState;
 
     // We're now ready to accept clients...
     mReadyToRunBarrier.open();
@@ -585,9 +589,8 @@
          */
 
         const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
-        for (int dpy=0 ; dpy<1 ; dpy++) {  // TODO: iterate through all displays
-            DisplayDevice& hw(const_cast<DisplayDevice&>(getDisplayDevice(dpy)));
-
+        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+            DisplayDevice& hw(mDisplays.editValueAt(dpy));
             Region opaqueRegion;
             Region dirtyRegion;
             computeVisibleRegions(currentLayers,
@@ -615,8 +618,8 @@
         // build the h/w work list
         const bool workListsDirty = mHwWorkListDirty;
         mHwWorkListDirty = false;
-        for (int dpy=0 ; dpy<1 ; dpy++) {  // TODO: iterate through all displays
-            DisplayDevice& hw(const_cast<DisplayDevice&>(getDisplayDevice(dpy)));
+        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+            const DisplayDevice& hw(mDisplays[dpy]);
             const Vector< sp<LayerBase> >& currentLayers(hw.getVisibleLayersSortedByZ());
             const size_t count = currentLayers.size();
 
@@ -646,8 +649,8 @@
     }
 
     const bool repaintEverything = android_atomic_and(0, &mRepaintEverything);
-    for (int dpy=0 ; dpy<1 ; dpy++) {  // TODO: iterate through all displays
-        DisplayDevice& hw(const_cast<DisplayDevice&>(getDisplayDevice(dpy)));
+    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+        DisplayDevice& hw(mDisplays.editValueAt(dpy));
 
         // transform the dirty region into this screen's coordinate space
         const Transform& planeTransform(hw.getTransform());
@@ -693,7 +696,7 @@
             glMatrixMode(GL_MODELVIEW);
             glLoadIdentity();
 
-            DisplayDevice& hw(const_cast<DisplayDevice&>(getDisplayDevice(0)));
+            DisplayDevice& hw(const_cast<DisplayDevice&>(getDefaultDisplayDevice()));
             const Vector< sp<LayerBase> >& layers( hw.getVisibleLayersSortedByZ() );
             const size_t count = layers.size();
             for (size_t i=0 ; i<count ; ++i) {
@@ -725,8 +728,8 @@
 
     HWComposer& hwc(getHwComposer());
 
-    for (int dpy=0 ; dpy<1 ; dpy++) {  // TODO: iterate through all displays
-        DisplayDevice& hw(const_cast<DisplayDevice&>(getDisplayDevice(dpy)));
+    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+        DisplayDevice& hw(mDisplays.editValueAt(dpy));
         if (hwc.initCheck() == NO_ERROR) {
             const Vector< sp<LayerBase> >& currentLayers(hw.getVisibleLayersSortedByZ());
             const size_t count = currentLayers.size();
@@ -746,8 +749,8 @@
         hwc.commit(mEGLDisplay, getDefaultDisplayDevice().getEGLSurface());
     }
 
-    for (int dpy=0 ; dpy<1 ; dpy++) {  // TODO: iterate through all displays
-        DisplayDevice& hw(const_cast<DisplayDevice&>(getDisplayDevice(dpy)));
+    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+        const DisplayDevice& hw(mDisplays[dpy]);
         const Vector< sp<LayerBase> >& currentLayers(hw.getVisibleLayersSortedByZ());
         const size_t count = currentLayers.size();
         if (hwc.initCheck() == NO_ERROR) {
@@ -822,16 +825,52 @@
      */
 
     if (transactionFlags & eTransactionNeeded) {
-        if (mCurrentState.orientation != mDrawingState.orientation) {
-            // the orientation has changed, recompute all visible regions
-            // and invalidate everything.
-
-            const int dpy = 0; // FIXME: should be a parameter
-            DisplayDevice& hw(const_cast<DisplayDevice&>(getDisplayDevice(dpy)));
-            hw.setOrientation(mCurrentState.orientation);
-            hw.dirtyRegion.set(hw.bounds());
-
+        // here we take advantage of Vector's copy-on-write semantics to
+        // improve performance by skipping the transaction entirely when
+        // know that the lists are identical
+        const KeyedVector<int32_t, DisplayDeviceState>& curr(mCurrentState.displays);
+        const KeyedVector<int32_t, DisplayDeviceState>& draw(mDrawingState.displays);
+        if (!curr.isIdenticalTo(draw)) {
             mVisibleRegionsDirty = true;
+            const size_t cc = curr.size();
+            const size_t dc = draw.size();
+
+            // find the displays that were removed
+            // (ie: in drawing state but not in current state)
+            // also handle displays that changed
+            // (ie: displays that are in both lists)
+            for (size_t i=0 ; i<dc ; i++) {
+                if (curr.indexOfKey(draw[i].id) < 0) {
+                    // in drawing state but not in current state
+                    if (draw[i].id != DisplayDevice::DISPLAY_ID_MAIN) {
+                        mDisplays.editValueFor(draw[i].id).terminate();
+                        mDisplays.removeItem(draw[i].id);
+                    } else {
+                        ALOGW("trying to remove the main display");
+                    }
+                } else {
+                    // this display is in both lists. see if something changed.
+                    const DisplayDeviceState& state(curr[i]);
+                    if (state.layerStack != draw[i].layerStack) {
+                        DisplayDevice& disp(mDisplays.editValueFor(state.id));
+                        //disp.setLayerStack(state.layerStack);
+                    }
+                    if (curr[i].orientation != draw[i].orientation) {
+                        DisplayDevice& disp(mDisplays.editValueFor(state.id));
+                        disp.setOrientation(state.orientation);
+                    }
+                }
+            }
+
+            // find displays that were added
+            // (ie: in current state but not in drawing state)
+            for (size_t i=0 ; i<cc ; i++) {
+                if (mDrawingState.displays.indexOfKey(curr[i].id) < 0) {
+                    // FIXME: we need to pass the surface here
+                    DisplayDevice disp(this, curr[i].id, 0, mEGLConfig);
+                    mDisplays.add(curr[i].id, disp);
+                }
+            }
         }
 
         if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {
@@ -1011,10 +1050,12 @@
 
 void SurfaceFlinger::invalidateLayerStack(uint32_t layerStack,
         const Region& dirty) {
-    // FIXME: update the dirty region of all displays
-    // presenting this layer's layer stack.
-    DisplayDevice& hw(const_cast<DisplayDevice&>(getDisplayDevice(0)));
-    hw.dirtyRegion.orSelf(dirty);
+    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+        DisplayDevice& hw(mDisplays.editValueAt(dpy));
+        if (hw.getLayerStack() == layerStack) {
+            hw.dirtyRegion.orSelf(dirty);
+        }
+    }
 }
 
 void SurfaceFlinger::handlePageFlip()
@@ -1324,9 +1365,10 @@
     }
 
     uint32_t transactionFlags = 0;
-    if (mCurrentState.orientation != orientation) {
+    // FIXME: don't hardcode display id here
+    if (mCurrentState.displays.valueFor(0).orientation != orientation) {
         if (uint32_t(orientation)<=eOrientation270 || orientation==42) {
-            mCurrentState.orientation = orientation;
+            mCurrentState.displays.editValueFor(0).orientation = orientation;
             transactionFlags |= eTransactionNeeded;
         } else if (orientation != eOrientationUnchanged) {
             ALOGW("setTransactionState: ignoring unrecognized orientation: %d",
@@ -1416,7 +1458,7 @@
         PixelFormat& format)
 {
     // initialize the surfaces
-    switch (format) { // TODO: take h/w into account
+    switch (format) {
     case PIXEL_FORMAT_TRANSPARENT:
     case PIXEL_FORMAT_TRANSLUCENT:
         format = PIXEL_FORMAT_RGBA_8888;
@@ -1804,7 +1846,7 @@
     hw.undefinedRegion.dump(result, "undefinedRegion");
     snprintf(buffer, SIZE,
             "  orientation=%d, canDraw=%d\n",
-            mCurrentState.orientation, hw.canDraw());
+            hw.getOrientation(), hw.canDraw());
     result.append(buffer);
     snprintf(buffer, SIZE,
             "  last eglSwapBuffers() time: %f us\n"
@@ -2727,9 +2769,8 @@
 
 // ---------------------------------------------------------------------------
 
-SurfaceFlinger::State::State()
-    : orientation(ISurfaceComposer::eOrientationDefault),
-      orientationFlags(0) {
+SurfaceFlinger::DisplayDeviceState::DisplayDeviceState()
+    : id(DisplayDevice::DISPLAY_ID_MAIN), layerStack(0), orientation(0) {
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6091e33..15d5a37 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -47,6 +47,7 @@
 
 #include "Barrier.h"
 #include "MessageQueue.h"
+#include "DisplayDevice.h"
 
 #include "DisplayHardware/HWComposer.h"
 
@@ -56,7 +57,6 @@
 
 class Client;
 class DisplayEventConnection;
-class DisplayDevice;
 class EventThread;
 class Layer;
 class LayerBase;
@@ -119,7 +119,7 @@
 
     // returns the default Display
     const DisplayDevice& getDefaultDisplayDevice() const {
-        return getDisplayDevice(0);
+        return getDisplayDevice(DisplayDevice::DISPLAY_ID_MAIN);
     }
 
     // utility function to delete a texture on the main thread
@@ -156,11 +156,21 @@
         virtual int do_compare(const void* lhs, const void* rhs) const;
     };
 
-    struct State {
-        State();
-        LayerVector layersSortedByZ;
+    struct DisplayDeviceState {
+        DisplayDeviceState();
+        int32_t id;
+        uint32_t layerStack;
+        Rect viewport;
+        Rect frame;
         uint8_t orientation;
-        uint8_t orientationFlags;
+        inline bool operator < (const DisplayDeviceState& rhs) const {
+            return id < rhs.id;
+        }
+    };
+
+    struct State {
+        LayerVector layersSortedByZ;
+        KeyedVector<int32_t, DisplayDeviceState> displays;
     };
 
     /* ------------------------------------------------------------------------
@@ -175,9 +185,9 @@
      */
     virtual sp<ISurfaceComposerClient> createConnection();
     virtual sp<IGraphicBufferAlloc> createGraphicBufferAlloc();
-    virtual void bootFinished();
     virtual void setTransactionState(const Vector<ComposerState>& state,
             const Vector<DisplayState>& displays, uint32_t flags);
+    virtual void bootFinished();
     virtual bool authenticateSurfaceTexture(
         const sp<ISurfaceTexture>& surface) const;
     virtual sp<IDisplayEventConnection> createDisplayEventConnection();
@@ -317,7 +327,10 @@
      * Display and layer stack management
      */
     const DisplayDevice& getDisplayDevice(DisplayID dpy) const {
-        return *mDisplayDevices[dpy];
+        return mDisplays.valueFor(dpy);
+    }
+    DisplayDevice& getDisplayDevice(DisplayID dpy) {
+        return mDisplays.editValueFor(dpy);
     }
 
     // mark a region of a layer stack dirty. this updates the dirty
@@ -370,7 +383,6 @@
     Vector<sp<LayerBase> > mLayersPendingRemoval;
 
     // protected by mStateLock (but we could use another lock)
-    DisplayDevice* mDisplayDevices[1];
     bool mLayersRemoved;
 
     // access must be protected by mInvalidateLock
@@ -393,6 +405,7 @@
     bool mVisibleRegionsDirty;
     bool mHwWorkListDirty;
     int32_t mElectronBeamAnimationMode;
+    DefaultKeyedVector<int32_t, DisplayDevice> mDisplays;
 
     // don't use a lock for these, we don't care
     int mDebugRegion;