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/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;
         }
     };