OSDN Git Service

First prototype atttempting to support an external display
authorMathias Agopian <mathias@google.com>
Tue, 19 Jun 2012 01:06:45 +0000 (18:06 -0700)
committerMathias Agopian <mathias@google.com>
Thu, 28 Jun 2012 22:51:08 +0000 (15:51 -0700)
both API and implementation will change, this is just a prototype
intended to show feasability.

SurfaceFlinger is passed an ISurfaceTexture through a new
callback, it is in turn used to create an EGLSurface which
surfaceflinger will draw into in addition to the main screen.

Change-Id: Id0bbb0b854bb7bae44d57246a90b65d4567f9a21

include/gui/ISurfaceComposer.h
libs/gui/ISurfaceComposer.cpp
services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
services/surfaceflinger/DisplayHardware/DisplayHardware.h
services/surfaceflinger/SurfaceFlinger.cpp
services/surfaceflinger/SurfaceFlinger.h

index e4e8aa7..4f32146 100644 (file)
@@ -145,6 +145,9 @@ public:
 
     /* triggers screen on and waits for it to complete */
     virtual void unblank() = 0;
+
+    /* connects to an external display */
+    virtual void connectDisplay(const sp<ISurfaceTexture> display) = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -168,6 +171,7 @@ public:
         CREATE_DISPLAY_EVENT_CONNECTION,
         BLANK,
         UNBLANK,
+        CONNECT_DISPLAY,
     };
 
     virtual status_t    onTransact( uint32_t code,
index 8177e4d..bc550bf 100644 (file)
@@ -207,6 +207,13 @@ public:
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         remote()->transact(BnSurfaceComposer::UNBLANK, data, &reply);
     }
+
+    virtual void connectDisplay(const sp<ISurfaceTexture> display) {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        data.writeStrongBinder(display->asBinder());
+        remote()->transact(BnSurfaceComposer::CONNECT_DISPLAY, data, &reply);
+    }
 };
 
 IMPLEMENT_META_INTERFACE(SurfaceComposer, "android.ui.ISurfaceComposer");
@@ -301,6 +308,12 @@ status_t BnSurfaceComposer::onTransact(
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             unblank();
         } break;
+        case CONNECT_DISPLAY: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            sp<ISurfaceTexture> surfaceTexture =
+                    interface_cast<ISurfaceTexture>(data.readStrongBinder());
+            connectDisplay(surfaceTexture);
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
index e1c4f62..bb537c9 100644 (file)
@@ -224,21 +224,11 @@ void DisplayHardware::init(uint32_t dpy)
 
     // initialize EGL
     EGLint attribs[] = {
-            EGL_SURFACE_TYPE,       EGL_WINDOW_BIT,
-            EGL_NONE,               0,
+            EGL_SURFACE_TYPE,           EGL_WINDOW_BIT,
+            EGL_RECORDABLE_ANDROID,     EGL_TRUE,
             EGL_NONE
     };
 
-    // debug: disable h/w rendering
-    char property[PROPERTY_VALUE_MAX];
-    if (property_get("debug.sf.hw", property, NULL) > 0) {
-        if (atoi(property) == 0) {
-            ALOGW("H/W composition disabled");
-            attribs[2] = EGL_CONFIG_CAVEAT;
-            attribs[3] = EGL_SLOW_CONFIG;
-        }
-    }
-
     // TODO: all the extensions below should be queried through
     // eglGetProcAddress().
 
@@ -248,6 +238,13 @@ void DisplayHardware::init(uint32_t dpy)
 
     EGLConfig config = NULL;
     err = selectConfigForPixelFormat(display, attribs, format, &config);
+    if (err) {
+        // maybe we failed because of EGL_RECORDABLE_ANDROID
+        ALOGW("couldn't find an EGLConfig with EGL_RECORDABLE_ANDROID");
+        attribs[2] = EGL_NONE;
+        err = selectConfigForPixelFormat(display, attribs, format, &config);
+    }
+
     ALOGE_IF(err, "couldn't find an EGLConfig matching the screen format");
     
     EGLint r,g,b,a;
index f029a0a..31662dd 100644 (file)
@@ -96,6 +96,7 @@ public:
 
     uint32_t getPageFlipCount() const;
     EGLDisplay getEGLDisplay() const { return mDisplay; }
+    EGLConfig getEGLConfig() const { return mConfig; }
 
     void dump(String8& res) const;
 
index 981d694..07ea3a0 100644 (file)
@@ -64,6 +64,7 @@
 #include <private/android_filesystem_config.h>
 #include <private/gui/SharedBufferStack.h>
 #include <gui/BitTube.h>
+#include <gui/SurfaceTextureClient.h>
 
 #define EGL_VERSION_HW_ANDROID  0x3143
 
@@ -97,7 +98,8 @@ SurfaceFlinger::SurfaceFlinger()
         mDebugInTransaction(0),
         mLastTransactionTime(0),
         mBootFinished(false),
-        mSecureFrameBuffer(0)
+        mSecureFrameBuffer(0),
+        mExternalDisplaySurface(EGL_NO_SURFACE)
 {
     init();
 }
@@ -370,6 +372,41 @@ sp<IDisplayEventConnection> SurfaceFlinger::createDisplayEventConnection() {
     return mEventThread->createEventConnection();
 }
 
+void SurfaceFlinger::connectDisplay(const sp<ISurfaceTexture> display) {
+    const DisplayHardware& hw(graphicPlane(0).displayHardware());
+    EGLSurface result = EGL_NO_SURFACE;
+    EGLSurface old_surface = EGL_NO_SURFACE;
+    sp<SurfaceTextureClient> stc;
+
+    if (display != NULL) {
+        stc = new SurfaceTextureClient(display);
+        result = eglCreateWindowSurface(hw.getEGLDisplay(),
+                hw.getEGLConfig(), (EGLNativeWindowType)stc.get(), NULL);
+        ALOGE_IF(result == EGL_NO_SURFACE,
+                "eglCreateWindowSurface failed (ISurfaceTexture=%p)",
+                display.get());
+    }
+
+    { // scope for the lock
+        Mutex::Autolock _l(mStateLock);
+        old_surface = mExternalDisplaySurface;
+        mExternalDisplayNativeWindow = stc;
+        mExternalDisplaySurface = result;
+        ALOGD("mExternalDisplaySurface = %p", result);
+    }
+
+    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(hw.getEGLDisplay(), old_surface);
+    }
+}
+
+EGLSurface SurfaceFlinger::getExternalDisplaySurface() const {
+    Mutex::Autolock _l(mStateLock);
+    return mExternalDisplaySurface;
+}
+
 // ----------------------------------------------------------------------------
 
 void SurfaceFlinger::waitForEvent() {
@@ -454,6 +491,43 @@ void SurfaceFlinger::onMessageReceived(int32_t what)
                 hw.compositionComplete();
             }
 
+            // 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 Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
+                    const size_t count = layers.size();
+                    for (size_t i=0 ; i<count ; ++i) {
+                        const sp<LayerBase>& layer(layers[i]);
+                        layer->drawForSreenShot();
+                    }
+
+                    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");
+            }
+
         } break;
     }
 }
index c3efdbc..8256fef 100644 (file)
@@ -153,6 +153,8 @@ public:
             // called when screen is turning back on
     virtual void                        unblank();
 
+    virtual void connectDisplay(const sp<ISurfaceTexture> display);
+
             // called on the main thread in response to screenReleased()
             void onScreenReleased();
             // called on the main thread in response to screenAcquired()
@@ -388,6 +390,11 @@ private:
 
    // only written in the main thread, only read in other threads
    volatile     int32_t                     mSecureFrameBuffer;
+
+
+   EGLSurface getExternalDisplaySurface() const;
+   sp<SurfaceTextureClient> mExternalDisplayNativeWindow;
+   EGLSurface mExternalDisplaySurface;
 };
 
 // ---------------------------------------------------------------------------