reimplement wifi display hack with new external display SF framework

fix a few bugs with external displays

- HWComposer doesn't really handle multiple displays yet
  so there is a lot of ugliness there

- We also need to make sure that external displays are not
  blanked by default

- due to some EGL limitations surfaces being swapped need
  to be current

Change-Id: I82bff05b43bcebd8da863c7c76b4edbc3bc223a9
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 4cae692..a379111 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -140,6 +140,9 @@
     mFormat  = format;
     mPageFlipCount = 0;
 
+    // external displays are always considered enabled
+    mScreenAcquired = mId >= DisplayDevice::DISPLAY_ID_COUNT;
+
     // initialize the display orientation transform.
     DisplayDevice::setOrientation(DisplayState::eOrientationDefault);
 }
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index c9df7a4..a3ec352 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -334,7 +334,8 @@
     }
 }
 
-status_t HWComposer::createWorkList(int32_t id, size_t numLayers) { // FIXME: handle multiple displays
+status_t HWComposer::createWorkList(int32_t id, size_t numLayers) {
+    // FIXME: handle multiple displays
     if (uint32_t(id) >= MAX_DISPLAYS)
         return BAD_INDEX;
 
@@ -360,6 +361,15 @@
     int err = hwcPrepare(mHwc, 1,
             const_cast<hwc_display_contents_1_t**>(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);
@@ -397,7 +407,15 @@
     return (status_t)err;
 }
 
-size_t HWComposer::getLayerCount(int32_t id, int type) const { // FIXME: handle multiple displays
+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;
@@ -623,7 +641,11 @@
 /*
  * 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
+HWComposer::LayerListIterator HWComposer::getLayerIterator(int32_t id, size_t index) {
+    // FIXME: handle multiple displays
+    if (uint32_t(id) >= MAX_DISPLAYS)
+        return LayerListIterator();
+
     if (!mHwc || index > hwcNumHwLayers(mHwc, mLists[0]))
         return LayerListIterator();
     if (hwcHasVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
@@ -638,14 +660,14 @@
 /*
  * returns an iterator on the beginning of the layer list
  */
-HWComposer::LayerListIterator HWComposer::begin(int32_t id) { // FIXME: handle multiple displays
+HWComposer::LayerListIterator HWComposer::begin(int32_t id) {
     return getLayerIterator(id, 0);
 }
 
 /*
  * returns an iterator on the end of the layer list
  */
-HWComposer::LayerListIterator HWComposer::end(int32_t id) { // FIXME: handle multiple displays
+HWComposer::LayerListIterator HWComposer::end(int32_t id) {
     return getLayerIterator(id, getNumLayers(id));
 }
 
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index e6189f7..2311e6d 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -426,10 +426,10 @@
 
     snprintf(buffer, SIZE,
             "      "
-            "z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), "
+            "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), "
             "isOpaque=%1d, needsDithering=%1d, invalidate=%1d, "
             "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n",
-            s.z, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h,
+            s.z, s.layerStack, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h,
             s.active.crop.left, s.active.crop.top,
             s.active.crop.right, s.active.crop.bottom,
             isOpaque(), needsDithering(), contentDirty,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 70d6ddb..63f3d91 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -95,8 +95,7 @@
         mLastSwapBufferTime(0),
         mDebugInTransaction(0),
         mLastTransactionTime(0),
-        mBootFinished(false),
-        mExternalDisplaySurface(EGL_NO_SURFACE)
+        mBootFinished(false)
 {
     ALOGI("SurfaceFlinger is starting");
 
@@ -555,40 +554,34 @@
     return mEventThread->createEventConnection();
 }
 
-void SurfaceFlinger::connectDisplay(const sp<ISurfaceTexture> display) {
-    EGLSurface result = EGL_NO_SURFACE;
-    EGLSurface old_surface = EGL_NO_SURFACE;
-    sp<SurfaceTextureClient> stc;
+void SurfaceFlinger::connectDisplay(const sp<ISurfaceTexture> surface) {
 
-    if (display != NULL) {
-        stc = new SurfaceTextureClient(display);
-        result = eglCreateWindowSurface(mEGLDisplay,
-                mEGLConfig, (EGLNativeWindowType)stc.get(), NULL);
-        ALOGE_IF(result == EGL_NO_SURFACE,
-                "eglCreateWindowSurface failed (ISurfaceTexture=%p)",
-                display.get());
+    sp<IBinder> token;
+    { // scope for the lock
+        Mutex::Autolock _l(mStateLock);
+        token = mExtDisplayToken;
+    }
+
+    if (token == 0) {
+        token = createDisplay();
     }
 
     { // scope for the lock
         Mutex::Autolock _l(mStateLock);
-        old_surface = mExternalDisplaySurface;
-        mExternalDisplayNativeWindow = stc;
-        mExternalDisplaySurface = result;
-        ALOGD("mExternalDisplaySurface = %p", result);
-    }
+        if (surface == 0) {
+            // release our current display. we're guarantee to have
+            // a reference to it (token), while we hold the lock
+            mExtDisplayToken = 0;
+        } else {
+            mExtDisplayToken = token;
+        }
 
-    if (old_surface != EGL_NO_SURFACE) {
-        // Note: EGL allows to destroy an object while its current
-        // it will fail to become current next time though.
-        eglDestroySurface(mEGLDisplay, old_surface);
+        DisplayDeviceState& info(mCurrentState.displays.editValueFor(token));
+        info.surface = surface;
+        setTransactionFlags(eDisplayTransactionNeeded);
     }
 }
 
-EGLSurface SurfaceFlinger::getExternalDisplaySurface() const {
-    Mutex::Autolock _l(mStateLock);
-    return mExternalDisplaySurface;
-}
-
 // ----------------------------------------------------------------------------
 
 void SurfaceFlinger::waitForEvent() {
@@ -757,49 +750,6 @@
     }
 
     postFramebuffer();
-
-
-#if 1
-    // render to the external display if we have one
-    EGLSurface externalDisplaySurface = getExternalDisplaySurface();
-    if (externalDisplaySurface != EGL_NO_SURFACE) {
-        EGLSurface cur = eglGetCurrentSurface(EGL_DRAW);
-        EGLBoolean success = eglMakeCurrent(eglGetCurrentDisplay(),
-                externalDisplaySurface, externalDisplaySurface,
-                eglGetCurrentContext());
-
-        ALOGE_IF(!success, "eglMakeCurrent -> external failed");
-
-        if (success) {
-            // redraw the screen entirely...
-            glDisable(GL_TEXTURE_EXTERNAL_OES);
-            glDisable(GL_TEXTURE_2D);
-            glClearColor(0,0,0,1);
-            glClear(GL_COLOR_BUFFER_BIT);
-            glMatrixMode(GL_MODELVIEW);
-            glLoadIdentity();
-
-            const sp<DisplayDevice>& hw(getDisplayDevice(0));
-            const Vector< sp<LayerBase> >& layers( hw->getVisibleLayersSortedByZ() );
-            const size_t count = layers.size();
-            for (size_t i=0 ; i<count ; ++i) {
-                const sp<LayerBase>& layer(layers[i]);
-                layer->draw(hw);
-            }
-
-            success = eglSwapBuffers(eglGetCurrentDisplay(), externalDisplaySurface);
-            ALOGE_IF(!success, "external display eglSwapBuffers failed");
-
-            hw->compositionComplete();
-        }
-
-        success = eglMakeCurrent(eglGetCurrentDisplay(),
-                cur, cur, eglGetCurrentContext());
-
-        ALOGE_IF(!success, "eglMakeCurrent -> internal failed");
-    }
-#endif
-
 }
 
 void SurfaceFlinger::postFramebuffer()
@@ -830,6 +780,10 @@
 
     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());
     }
 
@@ -844,14 +798,22 @@
             for (size_t i = 0; cur != end && i < count; ++i, ++cur) {
                 currentLayers[i]->onLayerDisplayed(hw, &*cur);
             }
-        } else {
+        }
+
+        // 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());
             for (size_t i = 0; i < count; i++) {
                 currentLayers[i]->onLayerDisplayed(hw, NULL);
             }
         }
-
-        // FIXME: we need to call eglSwapBuffers() on displays that have GL composition
     }
 
     mLastSwapBufferTime = systemTime() - now;
@@ -967,7 +929,6 @@
             // (ie: in current state but not in drawing state)
             for (size_t i=0 ; i<cc ; i++) {
                 if (draw.indexOfKey(curr.keyAt(i)) < 0) {
-                    // FIXME: we need to pass the surface here
                     const DisplayDeviceState& state(curr[i]);
                     sp<SurfaceTextureClient> stc(
                             new SurfaceTextureClient(state.surface));
@@ -1955,6 +1916,26 @@
     }
 
     /*
+     * Dump Display state
+     */
+
+    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+        const sp<const DisplayDevice>& hw(mDisplays[dpy]);
+        snprintf(buffer, SIZE,
+                "+ DisplayDevice[%u]\n"
+                "   id=%x, layerStack=%u, (%4dx%4d), orient=%2d, tr=%08x, "
+                "flips=%u, secure=%d, numLayers=%u\n",
+                dpy,
+                hw->getDisplayId(), hw->getLayerStack(),
+                hw->getWidth(), hw->getHeight(),
+                hw->getOrientation(), hw->getTransform().getType(),
+                hw->getPageFlipCount(),
+                hw->getSecureLayerVisible(),
+                hw->getVisibleLayersSortedByZ().size());
+        result.append(buffer);
+    }
+
+    /*
      * Dump SurfaceFlinger global state
      */
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6438bee..4831d9d 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -428,9 +428,7 @@
      * Feature prototyping
      */
 
-    EGLSurface getExternalDisplaySurface() const;
-    sp<SurfaceTextureClient> mExternalDisplayNativeWindow;
-    EGLSurface mExternalDisplaySurface;
+    sp<IBinder> mExtDisplayToken;
 };
 
 // ---------------------------------------------------------------------------