diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h index e4e8aa797..4f32146cc 100644 --- a/include/gui/ISurfaceComposer.h +++ b/include/gui/ISurfaceComposer.h @@ -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 display) = 0; }; // ---------------------------------------------------------------------------- @@ -168,6 +171,7 @@ public: CREATE_DISPLAY_EVENT_CONNECTION, BLANK, UNBLANK, + CONNECT_DISPLAY, }; virtual status_t onTransact( uint32_t code, diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp index 8177e4dd5..bc550bf10 100644 --- a/libs/gui/ISurfaceComposer.cpp +++ b/libs/gui/ISurfaceComposer.cpp @@ -207,6 +207,13 @@ public: data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); remote()->transact(BnSurfaceComposer::UNBLANK, data, &reply); } + + virtual void connectDisplay(const sp 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 surfaceTexture = + interface_cast(data.readStrongBinder()); + connectDisplay(surfaceTexture); + } break; default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp index e1c4f62fa..bb537c935 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp +++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp @@ -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; diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h index f029a0a13..31662dd04 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h +++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h @@ -96,6 +96,7 @@ public: uint32_t getPageFlipCount() const; EGLDisplay getEGLDisplay() const { return mDisplay; } + EGLConfig getEGLConfig() const { return mConfig; } void dump(String8& res) const; diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 981d69424..07ea3a060 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -64,6 +64,7 @@ #include #include #include +#include #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 SurfaceFlinger::createDisplayEventConnection() { return mEventThread->createEventConnection(); } +void SurfaceFlinger::connectDisplay(const sp display) { + const DisplayHardware& hw(graphicPlane(0).displayHardware()); + EGLSurface result = EGL_NO_SURFACE; + EGLSurface old_surface = EGL_NO_SURFACE; + sp 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 >& layers(mVisibleLayersSortedByZ); + const size_t count = layers.size(); + for (size_t i=0 ; i& 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; } } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index c3efdbc02..8256fef37 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -153,6 +153,8 @@ public: // called when screen is turning back on virtual void unblank(); + virtual void connectDisplay(const sp 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 mExternalDisplayNativeWindow; + EGLSurface mExternalDisplaySurface; }; // ---------------------------------------------------------------------------