refactor compositing code to avoid multiple eglMakeCurrent() calls

when multiple displays are connected, we ended-up having to
call eglMakeCurrent() twice per display due to a limitation
in EGL. this fixes that.

Change-Id: I11e4584df50f8c24bbecee74e37b28b3ee031d2f
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index a379111..2289444 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -218,6 +218,18 @@
     return mSecureLayerVisible;
 }
 
+Region DisplayDevice::getDirtyRegion(bool repaintEverything) const {
+    Region dirty;
+    const Transform& planeTransform(mGlobalTransform);
+    if (repaintEverything) {
+        dirty.set(getBounds());
+    } else {
+        dirty = planeTransform.transform(this->dirtyRegion);
+        dirty.andSelf(getBounds());
+    }
+    return dirty;
+}
+
 // ----------------------------------------------------------------------------
 
 bool DisplayDevice::canDraw() const {
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index e9ba5ff..9790699 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -87,6 +87,7 @@
     void                    setVisibleLayersSortedByZ(const Vector< sp<LayerBase> >& layers);
     Vector< sp<LayerBase> > getVisibleLayersSortedByZ() const;
     bool                    getSecureLayerVisible() const;
+    Region                  getDirtyRegion(bool repaintEverything) const;
 
     status_t                setOrientation(int orientation);
     void                    setLayerStack(uint32_t stack);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 63f3d91..c63d0cf 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -649,20 +649,101 @@
 }
 
 void SurfaceFlinger::handleMessageInvalidate() {
+    ATRACE_CALL();
     handlePageFlip();
 }
 
 void SurfaceFlinger::handleMessageRefresh() {
-    handleRefresh();
+    ATRACE_CALL();
+    preComposition();
+    rebuildLayerStacks();
+    setUpHWComposer();
+    doDebugFlashRegions();
+    doComposition();
+    postComposition();
+}
 
+void SurfaceFlinger::doDebugFlashRegions()
+{
+    // is debugging enabled
+    if (CC_LIKELY(!mDebugRegion))
+        return;
+
+    const bool repaintEverything = mRepaintEverything;
+    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+        const sp<DisplayDevice>& hw(mDisplays[dpy]);
+        if (hw->canDraw()) {
+            // transform the dirty region into this screen's coordinate space
+            const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
+            if (!dirtyRegion.isEmpty()) {
+                // redraw the whole screen
+                doComposeSurfaces(hw, Region(hw->bounds()));
+
+                // and draw the dirty region
+                glDisable(GL_TEXTURE_EXTERNAL_OES);
+                glDisable(GL_TEXTURE_2D);
+                glDisable(GL_BLEND);
+                glColor4f(1, 0, 1, 1);
+                const int32_t height = hw->getHeight();
+                Region::const_iterator it = dirtyRegion.begin();
+                Region::const_iterator const end = dirtyRegion.end();
+                while (it != end) {
+                    const Rect& r = *it++;
+                    GLfloat vertices[][2] = {
+                            { r.left,  height - r.top },
+                            { r.left,  height - r.bottom },
+                            { r.right, height - r.bottom },
+                            { r.right, height - r.top }
+                    };
+                    glVertexPointer(2, GL_FLOAT, 0, vertices);
+                    glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+                }
+                hw->compositionComplete();
+                // FIXME
+                if (hw->getDisplayId() >= DisplayDevice::DISPLAY_ID_COUNT) {
+                    eglSwapBuffers(mEGLDisplay, hw->getEGLSurface());
+                }
+            }
+        }
+    }
+
+    postFramebuffer();
+
+    if (mDebugRegion > 1) {
+        usleep(mDebugRegion * 1000);
+    }
+}
+
+void SurfaceFlinger::preComposition()
+{
+    bool needExtraInvalidate = false;
+    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
+    const size_t count = currentLayers.size();
+    for (size_t i=0 ; i<count ; i++) {
+        if (currentLayers[i]->onPreComposition()) {
+            needExtraInvalidate = true;
+        }
+    }
+    if (needExtraInvalidate) {
+        signalLayerUpdate();
+    }
+}
+
+void SurfaceFlinger::postComposition()
+{
+    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
+    const size_t count = currentLayers.size();
+    for (size_t i=0 ; i<count ; i++) {
+        currentLayers[i]->onPostComposition();
+    }
+}
+
+void SurfaceFlinger::rebuildLayerStacks() {
+    // rebuild the visible layer list per screen
     if (CC_UNLIKELY(mVisibleRegionsDirty)) {
+        ATRACE_CALL();
         mVisibleRegionsDirty = false;
         invalidateHwcGeometry();
-
-        /*
-         *  rebuild the visible layer list per screen
-         */
-
         const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
         for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
             const sp<DisplayDevice>& hw(mDisplays[dpy]);
@@ -684,10 +765,13 @@
             }
             hw->setVisibleLayersSortedByZ(layersSortedByZ);
             hw->undefinedRegion.set(hw->getBounds());
-            hw->undefinedRegion.subtractSelf(hw->getTransform().transform(opaqueRegion));
+            hw->undefinedRegion.subtractSelf(
+                    hw->getTransform().transform(opaqueRegion));
         }
     }
+}
 
+void SurfaceFlinger::setUpHWComposer() {
     HWComposer& hwc(getHwComposer());
     if (hwc.initCheck() == NO_ERROR) {
         // build the h/w work list
@@ -695,7 +779,8 @@
         mHwWorkListDirty = false;
         for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
             sp<const DisplayDevice> hw(mDisplays[dpy]);
-            const Vector< sp<LayerBase> >& currentLayers(hw->getVisibleLayersSortedByZ());
+            const Vector< sp<LayerBase> >& currentLayers(
+                    hw->getVisibleLayersSortedByZ());
             const size_t count = currentLayers.size();
 
             const int32_t id = hw->getDisplayId();
@@ -723,32 +808,27 @@
         status_t err = hwc.prepare();
         ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
     }
+}
 
+void SurfaceFlinger::doComposition() {
+    ATRACE_CALL();
     const bool repaintEverything = android_atomic_and(0, &mRepaintEverything);
     for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
         const sp<DisplayDevice>& hw(mDisplays[dpy]);
-
-        // transform the dirty region into this screen's coordinate space
-        const Transform& planeTransform(hw->getTransform());
-        Region dirtyRegion;
-        if (repaintEverything) {
-            dirtyRegion.set(hw->bounds());
-        } else {
-            dirtyRegion = planeTransform.transform(hw->dirtyRegion);
-            dirtyRegion.andSelf(hw->bounds());
-        }
-        hw->dirtyRegion.clear();
-
-        if (!dirtyRegion.isEmpty()) {
-            if (hw->canDraw()) {
+        if (hw->canDraw()) {
+            // transform the dirty region into this screen's coordinate space
+            const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
+            if (!dirtyRegion.isEmpty()) {
                 // repaint the framebuffer (if needed)
-                handleRepaint(hw, dirtyRegion);
+                doDisplayComposition(hw, dirtyRegion);
             }
+            hw->dirtyRegion.clear();
+            hw->flip(hw->swapRegion);
+            hw->swapRegion.clear();
         }
         // inform the h/w that we're done compositing
         hw->compositionComplete();
     }
-
     postFramebuffer();
 }
 
@@ -760,30 +840,13 @@
     mDebugInSwapBuffers = now;
 
     HWComposer& hwc(getHwComposer());
-
-    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
-        const sp<DisplayDevice>& hw(mDisplays[dpy]);
-        if (hwc.initCheck() == NO_ERROR) {
-            const Vector< sp<LayerBase> >& currentLayers(hw->getVisibleLayersSortedByZ());
-            const size_t count = currentLayers.size();
-            const int32_t id = hw->getDisplayId();
-            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]);
-                layer->setAcquireFence(hw, *cur);
-            }
-        }
-        hw->flip(hw->swapRegion);
-        hw->swapRegion.clear();
-    }
-
     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);
+        DisplayDevice::makeCurrent(
+                getDisplayDevice(DisplayDevice::DISPLAY_ID_MAIN), mEGLContext);
         hwc.commit(mEGLDisplay, getDefaultDisplayDevice()->getEGLSurface());
     }
 
@@ -798,18 +861,7 @@
             for (size_t i = 0; cur != end && i < count; ++i, ++cur) {
                 currentLayers[i]->onLayerDisplayed(hw, &*cur);
             }
-        }
-
-        // 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 and never for the other ones
-        if (hw->getDisplayId() >= DisplayDevice::DISPLAY_ID_COUNT) {
-            // FIXME: EGL spec says:
-            //   "surface must be bound to the calling thread's current context,
-            //    for the current rendering API."
-            DisplayDevice::makeCurrent(hw, mEGLContext);
-            eglSwapBuffers(mEGLDisplay, hw->getEGLSurface());
+        } else {
             for (size_t i = 0; i < count; i++) {
                 currentLayers[i]->onLayerDisplayed(hw, NULL);
             }
@@ -944,7 +996,8 @@
      * Perform our own transaction if needed
      */
 
-    if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {
+    const LayerVector& previousLayers(mDrawingState.layersSortedByZ);
+    if (currentLayers.size() > previousLayers.size()) {
         // layers have been added
         mVisibleRegionsDirty = true;
     }
@@ -954,7 +1007,6 @@
     if (mLayersRemoved) {
         mLayersRemoved = false;
         mVisibleRegionsDirty = true;
-        const LayerVector& previousLayers(mDrawingState.layersSortedByZ);
         const size_t count = previousLayers.size();
         for (size_t i=0 ; i<count ; i++) {
             const sp<LayerBase>& layer(previousLayers[i]);
@@ -1130,16 +1182,13 @@
 
 void SurfaceFlinger::handlePageFlip()
 {
-    ATRACE_CALL();
     Region dirtyRegion;
 
-    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
-
     bool visibleRegions = false;
+    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
     const size_t count = currentLayers.size();
-    sp<LayerBase> const* layers = currentLayers.array();
     for (size_t i=0 ; i<count ; i++) {
-        const sp<LayerBase>& layer(layers[i]);
+        const sp<LayerBase>& layer(currentLayers[i]);
         const Region dirty(layer->latchBuffer(visibleRegions));
         Layer::State s(layer->drawingState());
         invalidateLayerStack(s.layerStack, dirty);
@@ -1153,36 +1202,15 @@
     mHwWorkListDirty = true;
 }
 
-void SurfaceFlinger::handleRefresh()
-{
-    bool needInvalidate = false;
-    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
-    const size_t count = currentLayers.size();
-    for (size_t i=0 ; i<count ; i++) {
-        const sp<LayerBase>& layer(currentLayers[i]);
-        if (layer->onPreComposition()) {
-            needInvalidate = true;
-        }
-    }
-    if (needInvalidate) {
-        signalLayerUpdate();
-    }
-}
 
-void SurfaceFlinger::handleRepaint(const sp<const DisplayDevice>& hw,
+void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& hw,
         const Region& inDirtyRegion)
 {
-    ATRACE_CALL();
-
     Region dirtyRegion(inDirtyRegion);
 
     // compute the invalid region
     hw->swapRegion.orSelf(dirtyRegion);
 
-    if (CC_UNLIKELY(mDebugRegion)) {
-        debugFlashRegions(hw, dirtyRegion);
-    }
-
     uint32_t flags = hw->getFlags();
     if (flags & DisplayDevice::SWAP_RECTANGLE) {
         // we can redraw only what's dirty, but since SWAP_RECTANGLE only
@@ -1203,19 +1231,24 @@
         }
     }
 
-    composeSurfaces(hw, dirtyRegion);
+    doComposeSurfaces(hw, dirtyRegion);
 
-    const LayerVector& currentLayers(mDrawingState.layersSortedByZ);
-    const size_t count = currentLayers.size();
-    for (size_t i=0 ; i<count ; i++) {
-        currentLayers[i]->onPostComposition();
+    // 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 and never for the other ones
+    if (hw->getDisplayId() >= DisplayDevice::DISPLAY_ID_COUNT) {
+        // 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);
 }
 
-void SurfaceFlinger::composeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty)
+void SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty)
 {
     HWComposer& hwc(getHwComposer());
     int32_t id = hw->getDisplayId();
@@ -1259,74 +1292,32 @@
         for (size_t i=0 ; i<count ; ++i) {
             const sp<LayerBase>& layer(layers[i]);
             const Region clip(dirty.intersect(tr.transform(layer->visibleRegion)));
-            if (!clip.isEmpty()) {
-                if (cur != end && cur->getCompositionType() == HWC_OVERLAY) {
-                    if (i && (cur->getHints() & HWC_HINT_CLEAR_FB)
-                            && layer->isOpaque()) {
-                        // never clear the very first layer since we're
-                        // guaranteed the FB is already cleared
-                        layer->clearWithOpenGL(hw, clip);
-                    }
-                    ++cur;
-                    continue;
-                }
-                // render the layer
-                layer->draw(hw, clip);
-            }
             if (cur != end) {
+                // we're using h/w composer
+                if (!clip.isEmpty()) {
+                    if (cur->getCompositionType() == HWC_OVERLAY) {
+                        if (i && (cur->getHints() & HWC_HINT_CLEAR_FB)
+                                && layer->isOpaque()) {
+                            // never clear the very first layer since we're
+                            // guaranteed the FB is already cleared
+                            layer->clearWithOpenGL(hw, clip);
+                        }
+                    } else {
+                        layer->draw(hw, clip);
+                    }
+                    layer->setAcquireFence(hw, *cur);
+                }
                 ++cur;
+            } else {
+                // we're not using h/w composer
+                if (!clip.isEmpty()) {
+                    layer->draw(hw, clip);
+                }
             }
         }
     }
 }
 
-void SurfaceFlinger::debugFlashRegions(const sp<const DisplayDevice>& hw,
-        const Region& dirtyRegion)
-{
-    const uint32_t flags = hw->getFlags();
-    const int32_t height = hw->getHeight();
-    if (hw->swapRegion.isEmpty()) {
-        return;
-    }
-
-    if (!(flags & DisplayDevice::SWAP_RECTANGLE)) {
-        const Region repaint((flags & DisplayDevice::PARTIAL_UPDATES) ?
-                dirtyRegion.bounds() : hw->bounds());
-        composeSurfaces(hw, repaint);
-    }
-
-    glDisable(GL_TEXTURE_EXTERNAL_OES);
-    glDisable(GL_TEXTURE_2D);
-    glDisable(GL_BLEND);
-
-    static int toggle = 0;
-    toggle = 1 - toggle;
-    if (toggle) {
-        glColor4f(1, 0, 1, 1);
-    } else {
-        glColor4f(1, 1, 0, 1);
-    }
-
-    Region::const_iterator it = dirtyRegion.begin();
-    Region::const_iterator const end = dirtyRegion.end();
-    while (it != end) {
-        const Rect& r = *it++;
-        GLfloat vertices[][2] = {
-                { r.left,  height - r.top },
-                { r.left,  height - r.bottom },
-                { r.right, height - r.bottom },
-                { r.right, height - r.top }
-        };
-        glVertexPointer(2, GL_FLOAT, 0, vertices);
-        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-    }
-
-    hw->flip(hw->swapRegion);
-
-    if (mDebugRegion > 1)
-        usleep(mDebugRegion * 1000);
-}
-
 void SurfaceFlinger::drawWormhole(const Region& region) const
 {
     glDisable(GL_TEXTURE_EXTERNAL_OES);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 4831d9d..1f79906 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -248,9 +248,6 @@
      */
     void handlePageFlip();
 
-    void handleRefresh();
-    void handleRepaint(const sp<const DisplayDevice>& hw, const Region& dirtyRegion);
-
     /* ------------------------------------------------------------------------
      * Transactions
      */
@@ -348,8 +345,19 @@
     void computeVisibleRegions(const LayerVector& currentLayers,
             uint32_t layerStack,
             Region& dirtyRegion, Region& opaqueRegion);
+
+    void preComposition();
+    void postComposition();
+    void rebuildLayerStacks();
+    void setUpHWComposer();
+    void doComposition();
+    void doDebugFlashRegions();
+    void doDisplayComposition(const sp<const DisplayDevice>& hw,
+            const Region& dirtyRegion);
+    void doComposeSurfaces(const sp<const DisplayDevice>& hw,
+            const Region& dirty);
+
     void postFramebuffer();
-    void composeSurfaces(const sp<const DisplayDevice>& hw, const Region& dirty);
     void drawWormhole(const Region& region) const;
     GLuint getProtectedTexName() const {
         return mProtectedTexName;
@@ -358,7 +366,6 @@
     /* ------------------------------------------------------------------------
      * Debugging & dumpsys
      */
-    void debugFlashRegions(const sp<const DisplayDevice>& hw, const Region& dirtyReg);
     void listLayersLocked(const Vector<String16>& args, size_t& index,
         String8& result, char* buffer, size_t SIZE) const;
     void dumpStatsLocked(const Vector<String16>& args, size_t& index,