diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h index 653360023..1a1821c14 100644 --- a/include/surfaceflinger/ISurfaceComposer.h +++ b/include/surfaceflinger/ISurfaceComposer.h @@ -118,6 +118,8 @@ public: uint32_t* width, uint32_t* height, PixelFormat* format, uint32_t reqWidth, uint32_t reqHeight) = 0; + virtual status_t turnElectronBeamOff(int32_t mode) = 0; + /* Signal surfaceflinger that there might be some work to do * This is an ASYNCHRONOUS call. */ @@ -142,7 +144,8 @@ public: FREEZE_DISPLAY, UNFREEZE_DISPLAY, SIGNAL, - CAPTURE_SCREEN + CAPTURE_SCREEN, + TURN_ELECTRON_BEAM_OFF }; virtual status_t onTransact( uint32_t code, diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/surfaceflinger_client/ISurfaceComposer.cpp index d676f5e90..d72561fd7 100644 --- a/libs/surfaceflinger_client/ISurfaceComposer.cpp +++ b/libs/surfaceflinger_client/ISurfaceComposer.cpp @@ -142,6 +142,15 @@ public: return reply.readInt32(); } + virtual status_t turnElectronBeamOff(int32_t mode) + { + Parcel data, reply; + data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor()); + data.writeInt32(mode); + remote()->transact(BnSurfaceComposer::TURN_ELECTRON_BEAM_OFF, data, &reply); + return reply.readInt32(); + } + virtual void signal() const { Parcel data, reply; @@ -224,6 +233,12 @@ status_t BnSurfaceComposer::onTransact( reply->writeInt32(f); reply->writeInt32(res); } break; + case TURN_ELECTRON_BEAM_OFF: { + CHECK_INTERFACE(ISurfaceComposer, data, reply); + int32_t mode = data.readInt32(); + status_t res = turnElectronBeamOff(mode); + reply->writeInt32(res); + } default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp index 1d09f84dc..fe9a5ab33 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp +++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.cpp @@ -359,7 +359,7 @@ status_t DisplayHardwareBase::ConsoleManagerThread::initCheck() const DisplayHardwareBase::DisplayHardwareBase(const sp& flinger, uint32_t displayIndex) - : mCanDraw(true) + : mCanDraw(true), mScreenAcquired(true) { mDisplayEventThread = new DisplayEventThread(flinger); if (mDisplayEventThread->initCheck() != NO_ERROR) { @@ -374,18 +374,21 @@ DisplayHardwareBase::~DisplayHardwareBase() mDisplayEventThread->requestExitAndWait(); } +void DisplayHardwareBase::setCanDraw(bool canDraw) +{ + mCanDraw = canDraw; +} bool DisplayHardwareBase::canDraw() const { - return mCanDraw; + return mCanDraw && mScreenAcquired; } void DisplayHardwareBase::releaseScreen() const { status_t err = mDisplayEventThread->releaseScreen(); if (err >= 0) { - //LOGD("screen given-up"); - mCanDraw = false; + mScreenAcquired = false; } } @@ -393,9 +396,14 @@ void DisplayHardwareBase::acquireScreen() const { status_t err = mDisplayEventThread->acquireScreen(); if (err >= 0) { - //LOGD("screen returned"); mCanDraw = true; + mScreenAcquired = true; } } +bool DisplayHardwareBase::isScreenAcquired() const +{ + return mScreenAcquired; +} + }; // namespace android diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h index 8369bb886..fa6a0c4bc 100644 --- a/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h +++ b/services/surfaceflinger/DisplayHardware/DisplayHardwareBase.h @@ -40,7 +40,11 @@ public: // console managment void releaseScreen() const; void acquireScreen() const; + bool isScreenAcquired() const; + bool canDraw() const; + void setCanDraw(bool canDraw); + private: class DisplayEventThreadBase : public Thread { @@ -89,6 +93,7 @@ private: sp mDisplayEventThread; mutable int mCanDraw; + mutable int mScreenAcquired; }; }; // namespace android diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index e5e87c60e..a919ddf8d 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -423,14 +423,14 @@ void SurfaceFlinger::handleConsoleEvents() hw.acquireScreen(); } - if (mDeferReleaseConsole && hw.canDraw()) { + if (mDeferReleaseConsole && hw.isScreenAcquired()) { // We got the release signal before the acquire signal mDeferReleaseConsole = false; hw.releaseScreen(); } if (what & eConsoleReleased) { - if (hw.canDraw()) { + if (hw.isScreenAcquired()) { hw.releaseScreen(); } else { mDeferReleaseConsole = true; @@ -1456,6 +1456,7 @@ status_t SurfaceFlinger::onTransact( case FREEZE_DISPLAY: case UNFREEZE_DISPLAY: case BOOT_FINISHED: + case TURN_ELECTRON_BEAM_OFF: { // codes that require permission check IPCThreadState* ipc = IPCThreadState::self(); @@ -1544,6 +1545,231 @@ status_t SurfaceFlinger::onTransact( return err; } + +// --------------------------------------------------------------------------- + +status_t SurfaceFlinger::turnElectronBeamOffImplLocked() +{ + status_t result = PERMISSION_DENIED; + + if (!GLExtensions::getInstance().haveFramebufferObject()) + return INVALID_OPERATION; + + // get screen geometry + const int dpy = 0; + const DisplayHardware& hw(graphicPlane(dpy).displayHardware()); + if (!hw.canDraw()) { + // we're already off + return NO_ERROR; + } + + const uint32_t hw_w = hw.getWidth(); + const uint32_t hw_h = hw.getHeight(); + const Region screenBounds(hw.bounds()); + GLfloat u = 1; + GLfloat v = 1; + + // make sure to clear all GL error flags + while ( glGetError() != GL_NO_ERROR ) ; + + // create a FBO + GLuint name, tname; + glGenTextures(1, &tname); + glBindTexture(GL_TEXTURE_2D, tname); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, hw_w, hw_h, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + if (glGetError() != GL_NO_ERROR) { + GLint tw = (2 << (31 - clz(hw_w))); + GLint th = (2 << (31 - clz(hw_h))); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tw, th, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + u = GLfloat(hw_w) / tw; + v = GLfloat(hw_h) / th; + } + glGenFramebuffersOES(1, &name); + glBindFramebufferOES(GL_FRAMEBUFFER_OES, name); + glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0); + + GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); + if (status == GL_FRAMEBUFFER_COMPLETE_OES) { + // redraw the screen entirely... + glClearColor(0,0,0,1); + glClear(GL_COLOR_BUFFER_BIT); + const Vector< sp >& layers(mVisibleLayersSortedByZ); + const size_t count = layers.size(); + for (size_t i=0 ; i& layer(layers[i]); + layer->drawForSreenShot(); + } + // back to main framebuffer + glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); + glDisable(GL_SCISSOR_TEST); + + GLfloat vtx[8]; + const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} }; + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, tname); + glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glTexCoordPointer(2, GL_FLOAT, 0, texCoords); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glVertexPointer(2, GL_FLOAT, 0, vtx); + + class s_curve_interpolator { + const float nbFrames, s, v; + public: + s_curve_interpolator(int nbFrames, float s) + : nbFrames(1.0f / (nbFrames-1)), s(s), + v(1.0f + expf(-s + 0.5f*s)) { + } + float operator()(int f) { + const float x = f * nbFrames; + return ((1.0f/(1.0f + expf(-x*s + 0.5f*s))) - 0.5f) * v + 0.5f; + } + }; + + class v_stretch { + const GLfloat hw_w, hw_h; + public: + v_stretch(uint32_t hw_w, uint32_t hw_h) + : hw_w(hw_w), hw_h(hw_h) { + } + void operator()(GLfloat* vtx, float v) { + const GLfloat w = hw_w + (hw_w * v); + const GLfloat h = hw_h - (hw_h * v); + const GLfloat x = (hw_w - w) * 0.5f; + const GLfloat y = (hw_h - h) * 0.5f; + vtx[0] = x; vtx[1] = y; + vtx[2] = x; vtx[3] = y + h; + vtx[4] = x + w; vtx[5] = y + h; + vtx[6] = x + w; vtx[7] = y; + } + }; + + class h_stretch { + const GLfloat hw_w, hw_h; + public: + h_stretch(uint32_t hw_w, uint32_t hw_h) + : hw_w(hw_w), hw_h(hw_h) { + } + void operator()(GLfloat* vtx, float v) { + const GLfloat w = hw_w - (hw_w * v); + const GLfloat h = 1.0f; + const GLfloat x = (hw_w - w) * 0.5f; + const GLfloat y = (hw_h - h) * 0.5f; + vtx[0] = x; vtx[1] = y; + vtx[2] = x; vtx[3] = y + h; + vtx[4] = x + w; vtx[5] = y + h; + vtx[6] = x + w; vtx[7] = y; + } + }; + + // the full animation is 24 frames + const int nbFrames = 12; + + v_stretch vverts(hw_w, hw_h); + s_curve_interpolator itr(nbFrames, 7.5f); + s_curve_interpolator itg(nbFrames, 8.0f); + s_curve_interpolator itb(nbFrames, 8.5f); + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE); + for (int i=0 ; imStateLock); + result = flinger->turnElectronBeamOffImplLocked(); + return true; + } + }; + + sp msg = new MessageTurnElectronBeamOff(this); + status_t res = postMessageSync(msg); + if (res == NO_ERROR) { + res = static_cast( msg.get() )->getResult(); + } + return res; +} + // --------------------------------------------------------------------------- status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy, @@ -2005,6 +2231,10 @@ const DisplayHardware& GraphicPlane::displayHardware() const { return *mHw; } +DisplayHardware& GraphicPlane::editDisplayHardware() { + return *mHw; +} + const Transform& GraphicPlane::transform() const { return mGlobalTransform; } diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index f0a167b96..f85a22bed 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -141,6 +141,7 @@ public: int getHeight() const; const DisplayHardware& displayHardware() const; + DisplayHardware& editDisplayHardware(); const Transform& transform() const; EGLDisplay getEGLDisplay() const; @@ -200,6 +201,7 @@ public: PixelFormat* format, uint32_t reqWidth, uint32_t reqHeight); + virtual status_t turnElectronBeamOff(int32_t mode); void screenReleased(DisplayID dpy); void screenAcquired(DisplayID dpy); @@ -325,6 +327,8 @@ private: uint32_t* width, uint32_t* height, PixelFormat* format, uint32_t reqWidth = 0, uint32_t reqHeight = 0); + status_t turnElectronBeamOffImplLocked(); + friend class FreezeLock; sp getFreezeLock() const; inline void incFreezeCount() {