refactor things a bit

- decouple GL and main display initialization
- ensure that each "supported" display has its own FramebufferSurface
- onScreenAcquired/Released now takes a display

Change-Id: If34a05f3dea40f6c79db77f4dde283a2580daac4
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 1b55792..81640af 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -561,22 +561,34 @@
             mDisplayData[id].list->numHwLayers : 0;
 }
 
-int HWComposer::fbPost(buffer_handle_t buffer)
-{
-    return mFbDev->post(mFbDev, buffer);
-}
-
-int HWComposer::fbCompositionComplete()
-{
-    if (mFbDev->compositionComplete) {
-        return mFbDev->compositionComplete(mFbDev);
+int HWComposer::getVisualID() const {
+    if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
+        return HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
     } else {
-        return INVALID_OPERATION;
+        return mFbDev->format;
     }
 }
 
+int HWComposer::fbPost(buffer_handle_t buffer) {
+    if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
+        return mFbDev->post(mFbDev, buffer);
+    }
+    return NO_ERROR;
+}
+
+int HWComposer::fbCompositionComplete() {
+    if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_0)) {
+        if (mFbDev->compositionComplete) {
+            return mFbDev->compositionComplete(mFbDev);
+        } else {
+            return INVALID_OPERATION;
+        }
+    }
+    return NO_ERROR;
+}
+
 void HWComposer::fbDump(String8& result) {
-    if (mFbDev->common.version >= 1 && mFbDev->dump) {
+    if (mFbDev && mFbDev->common.version >= 1 && mFbDev->dump) {
         const size_t SIZE = 4096;
         char buffer[SIZE];
         mFbDev->dump(mFbDev, buffer, SIZE);
@@ -727,7 +739,7 @@
 void HWComposer::dump(String8& result, char* buffer, size_t SIZE,
         const Vector< sp<LayerBase> >& visibleLayersSortedByZ) const {
     if (mHwc) {
-        result.append("Hardware Composer state:\n");
+        result.appendFormat("Hardware Composer state (version %8x):\n", hwcApiVersion(mHwc));
         result.appendFormat("  mDebugForceFakeVSync=%d\n", mDebugForceFakeVSync);
         for (size_t i=0 ; i<mNumDisplays ; i++) {
             const DisplayData& disp(mDisplayData[i]);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index 552d42f..fe928c5 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -106,6 +106,10 @@
     // needed forward declarations
     class LayerListIterator;
 
+    // return the visual id to be used to find a suitable EGLConfig for
+    // *ALL* displays.
+    int getVisualID() const;
+
     // Forwarding to FB HAL for pre-HWC-1.1 code (see FramebufferSurface).
     int fbPost(buffer_handle_t buffer);
     int fbCompositionComplete();
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f1d790d..f62f075 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -43,6 +43,7 @@
 #include <ui/GraphicBufferAllocator.h>
 #include <ui/PixelFormat.h>
 
+#include <utils/misc.h>
 #include <utils/String8.h>
 #include <utils/String16.h>
 #include <utils/StopWatch.h>
@@ -243,6 +244,16 @@
     eglGetConfigs(dpy, NULL, 0, &numConfigs);
     EGLConfig* const configs = new EGLConfig[numConfigs];
     eglChooseConfig(dpy, attrs, configs, numConfigs, &n);
+
+    if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+        // FIXME: temporary hack until HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED
+        // is supported by the implementation. we can only be in this case
+        // if we have HWC 1.1
+        *outConfig = configs[0];
+        delete [] configs;
+        return NO_ERROR;
+    }
+
     for (int i=0 ; i<n ; i++) {
         EGLint nativeVisualId = 0;
         eglGetConfigAttrib(dpy, configs[i], EGL_NATIVE_VISUAL_ID, &nativeVisualId);
@@ -264,6 +275,11 @@
     status_t err;
     EGLint attribs[] = {
             EGL_SURFACE_TYPE,           EGL_WINDOW_BIT,
+            EGL_RED_SIZE,               8,
+            EGL_GREEN_SIZE,             8,
+            EGL_BLUE_SIZE,              8,
+            // EGL_RECORDABLE_ANDROID must be last so that we can retry
+            // without it easily (see below)
             EGL_RECORDABLE_ANDROID,     EGL_TRUE,
             EGL_NONE
     };
@@ -271,7 +287,7 @@
     if (err) {
         // maybe we failed because of EGL_RECORDABLE_ANDROID
         ALOGW("couldn't find an EGLConfig with EGL_RECORDABLE_ANDROID");
-        attribs[2] = EGL_NONE;
+        attribs[NELEM(attribs) - 3] = EGL_NONE;
         err = selectConfigForPixelFormat(display, attribs, nativeVisualId, &config);
     }
     ALOGE_IF(err, "couldn't find an EGLConfig matching the screen format");
@@ -297,13 +313,7 @@
     return ctxt;
 }
 
-void SurfaceFlinger::initializeGL(EGLDisplay display, const sp<DisplayDevice>& hw) {
-    EGLBoolean result = DisplayDevice::makeCurrent(display, hw, mEGLContext);
-    if (!result) {
-        ALOGE("Couldn't create a working GLES context. check logs. exiting...");
-        exit(0);
-    }
-
+void SurfaceFlinger::initializeGL(EGLDisplay display) {
     GLExtensions& extensions(GLExtensions::getInstance());
     extensions.initWithGLStrings(
             glGetString(GL_VENDOR),
@@ -375,39 +385,45 @@
     mHwc = new HWComposer(this,
             *static_cast<HWComposer::EventHandler *>(this));
 
-    // Initialize the main display
-    // create native window to main display
-    sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc);
-    if (fbs == NULL) {
-        ALOGE("Display subsystem failed to initialize. check logs. exiting...");
-        exit(0);
-    }
-
-    sp<SurfaceTextureClient> stc(new SurfaceTextureClient(
-            static_cast<sp<ISurfaceTexture> >(fbs->getBufferQueue())));
-
     // initialize the config and context
-    int format;
-    ANativeWindow* const anw = stc.get();
-    anw->query(anw, NATIVE_WINDOW_FORMAT, &format);
+    EGLint format = mHwc->getVisualID();
     mEGLConfig  = selectEGLConfig(mEGLDisplay, format);
     mEGLContext = createGLContext(mEGLDisplay, mEGLConfig);
 
-    // initialize our main display hardware
-
+    // initialize our non-virtual displays
     for (size_t i=0 ; i<DisplayDevice::NUM_DISPLAY_TYPES ; i++) {
         mDefaultDisplays[i] = new BBinder();
         mCurrentState.displays.add(mDefaultDisplays[i],
-                DisplayDeviceState((DisplayDevice::DisplayType)i));
+                DisplayDeviceState(DisplayDevice::DisplayType(i)));
     }
+
+    // The main display is a bit special and always exists
+    //
+    // if we didn't add it here, it would be added automatically during the
+    // first transaction, however this would also create some difficulties:
+    //
+    // - there would be a race where a client could call getDisplayInfo(),
+    //   for instance before the DisplayDevice is created.
+    //
+    // - we need a GL context current in a few places, when initializing
+    //   OpenGL ES (see below), or creating a layer,
+    //   or when a texture is (asynchronously) destroyed, and for that
+    //   we need a valid surface, so it's conveniant to use the main display
+    //   for that.
+
+    sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc);
+    sp<SurfaceTextureClient> stc = new SurfaceTextureClient(
+                static_cast< sp<ISurfaceTexture> >(fbs->getBufferQueue()));
     sp<DisplayDevice> hw = new DisplayDevice(this,
             DisplayDevice::DISPLAY_PRIMARY,
             mDefaultDisplays[DisplayDevice::DISPLAY_PRIMARY],
-            anw, fbs, mEGLConfig);
+            stc, fbs, mEGLConfig);
     mDisplays.add(mDefaultDisplays[DisplayDevice::DISPLAY_PRIMARY], hw);
 
+
     //  initialize OpenGL ES
-    initializeGL(mEGLDisplay, hw);
+    DisplayDevice::makeCurrent(mEGLDisplay, hw, mEGLContext);
+    initializeGL(mEGLDisplay);
 
     // start the EventThread
     mEventThread = new EventThread(this);
@@ -416,6 +432,7 @@
     // initialize our drawing state
     mDrawingState = mCurrentState;
 
+
     // We're now ready to accept clients...
     mReadyToRunBarrier.open();
 
@@ -1009,16 +1026,41 @@
             for (size_t i=0 ; i<cc ; i++) {
                 if (draw.indexOfKey(curr.keyAt(i)) < 0) {
                     const DisplayDeviceState& state(curr[i]);
-                    if (state.surface != NULL) {
-                        sp<SurfaceTextureClient> stc(
-                                new SurfaceTextureClient(state.surface));
-                        const wp<IBinder>& display(curr.keyAt(i));
-                        sp<DisplayDevice> disp = new DisplayDevice(this,
-                                state.type, display, stc, 0, mEGLConfig);
-                        disp->setLayerStack(state.layerStack);
-                        disp->setProjection(state.orientation,
+
+                    sp<FramebufferSurface> fbs;
+                    sp<SurfaceTextureClient> stc;
+                    if (!state.isVirtualDisplay()) {
+
+                        ALOGE_IF(state.surface!=NULL,
+                                "adding a supported display, but rendering "
+                                "surface is provided (%p), ignoring it",
+                                state.surface.get());
+
+                        // for supported (by hwc) displays we provide our
+                        // own rendering surface
+                        fbs = new FramebufferSurface(*mHwc);
+                        stc = new SurfaceTextureClient(
+                                static_cast< sp<ISurfaceTexture> >(fbs->getBufferQueue()));
+                    } else {
+                        if (state.surface != NULL) {
+                            stc = new SurfaceTextureClient(state.surface);
+                        }
+                    }
+
+                    const wp<IBinder>& display(curr.keyAt(i));
+                    if (stc != NULL) {
+                        sp<DisplayDevice> hw = new DisplayDevice(this,
+                                state.type, display, stc, fbs, mEGLConfig);
+                        hw->setLayerStack(state.layerStack);
+                        hw->setProjection(state.orientation,
                                 state.viewport, state.frame);
-                        mDisplays.add(display, disp);
+                        mDisplays.add(display, hw);
+                        if (hw->getDisplayType() < DisplayDevice::NUM_DISPLAY_TYPES) {
+                            // notify the system that this display is now up
+                            // (note onScreenAcquired() is safe to call from
+                            // here because we're in the main thread)
+                            onScreenAcquired(hw);
+                        }
                     }
                 }
             }
@@ -1753,9 +1795,7 @@
     d.viewport.makeInvalid();
     displays.add(d);
     setTransactionState(state, displays, 0);
-
-    // XXX: this should init default device to "unblank" and all other devices to "blank"
-    onScreenAcquired();
+    onScreenAcquired(getDefaultDisplayDevice());
 }
 
 void SurfaceFlinger::initializeDisplays() {
@@ -1773,21 +1813,25 @@
 }
 
 
-void SurfaceFlinger::onScreenAcquired() {
+void SurfaceFlinger::onScreenAcquired(const sp<const DisplayDevice>& hw) {
     ALOGD("Screen about to return, flinger = %p", this);
-    sp<const DisplayDevice> hw(getDefaultDisplayDevice()); // XXX: this should be per DisplayDevice
     getHwComposer().acquire();
     hw->acquireScreen();
-    mEventThread->onScreenAcquired();
+    if (hw->getDisplayType() == DisplayDevice::DISPLAY_PRIMARY) {
+        // FIXME: eventthread only knows about the main display right now
+        mEventThread->onScreenAcquired();
+    }
     mVisibleRegionsDirty = true;
     repaintEverything();
 }
 
-void SurfaceFlinger::onScreenReleased() {
+void SurfaceFlinger::onScreenReleased(const sp<const DisplayDevice>& hw) {
     ALOGD("About to give-up screen, flinger = %p", this);
-    sp<const DisplayDevice> hw(getDefaultDisplayDevice()); // XXX: this should be per DisplayDevice
     if (hw->isScreenAcquired()) {
-        mEventThread->onScreenReleased();
+        if (hw->getDisplayType() == DisplayDevice::DISPLAY_PRIMARY) {
+            // FIXME: eventthread only knows about the main display right now
+            mEventThread->onScreenReleased();
+        }
         hw->releaseScreen();
         getHwComposer().release();
         mVisibleRegionsDirty = true;
@@ -1801,7 +1845,8 @@
     public:
         MessageScreenAcquired(SurfaceFlinger* flinger) : flinger(flinger) { }
         virtual bool handler() {
-            flinger->onScreenAcquired();
+            // FIXME: should this be per-display?
+            flinger->onScreenAcquired(flinger->getDefaultDisplayDevice());
             return true;
         }
     };
@@ -1815,7 +1860,8 @@
     public:
         MessageScreenReleased(SurfaceFlinger* flinger) : flinger(flinger) { }
         virtual bool handler() {
-            flinger->onScreenReleased();
+            // FIXME: should this be per-display?
+            flinger->onScreenReleased(flinger->getDefaultDisplayDevice());
             return true;
         }
     };
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ffe68c6..a648621 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -166,6 +166,7 @@
         DisplayDeviceState(DisplayDevice::DisplayType type);
         bool isValid() const { return type >= 0; }
         bool isMainDisplay() const { return type == DisplayDevice::DISPLAY_PRIMARY; }
+        bool isVirtualDisplay() const { return type >= DisplayDevice::DISPLAY_VIRTUAL; }
         DisplayDevice::DisplayType type;
         sp<ISurfaceTexture> surface;
         uint32_t layerStack;
@@ -238,9 +239,9 @@
     // called on the main thread in response to initializeDisplays()
     void onInitializeDisplays();
     // called on the main thread in response to blank()
-    void onScreenReleased();
+    void onScreenReleased(const sp<const DisplayDevice>& hw);
     // called on the main thread in response to unblank()
-    void onScreenAcquired();
+    void onScreenAcquired(const sp<const DisplayDevice>& hw);
 
     void handleMessageTransaction();
     void handleMessageInvalidate();
@@ -320,7 +321,7 @@
         EGLint const* attrs, PixelFormat format, EGLConfig* outConfig);
     static EGLConfig selectEGLConfig(EGLDisplay disp, EGLint visualId);
     static EGLContext createGLContext(EGLDisplay disp, EGLConfig config);
-    void initializeGL(EGLDisplay display, const sp<DisplayDevice>& hw);
+    void initializeGL(EGLDisplay display);
     uint32_t getMaxTextureSize() const;
     uint32_t getMaxViewportDims() const;