From f171ab6da9cf9793093e50947aacdab8f2b0c9b2 Mon Sep 17 00:00:00 2001 From: Mathias Agopian Date: Thu, 13 Oct 2011 16:02:48 -0700 Subject: [PATCH] Add a LayerScreenshot A LayerScreenshot is a special type of layer that contains a screenshot of the screen acquired when its created. It works just like LayerDim. Bug: 5446982 Change-Id: I7814aff2380e7e146937f2b641907be2a30c76cc --- include/surfaceflinger/ISurfaceComposer.h | 1 + services/surfaceflinger/Android.mk | 1 + services/surfaceflinger/Layer.cpp | 12 +- services/surfaceflinger/LayerScreenshot.cpp | 116 ++++++++++++++++++++ services/surfaceflinger/LayerScreenshot.h | 56 ++++++++++ services/surfaceflinger/SurfaceFlinger.cpp | 36 ++++-- services/surfaceflinger/SurfaceFlinger.h | 33 ++++-- 7 files changed, 227 insertions(+), 28 deletions(-) create mode 100644 services/surfaceflinger/LayerScreenshot.cpp create mode 100644 services/surfaceflinger/LayerScreenshot.h diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h index ea022a67b..e7a33f1d3 100644 --- a/include/surfaceflinger/ISurfaceComposer.h +++ b/include/surfaceflinger/ISurfaceComposer.h @@ -53,6 +53,7 @@ public: eFXSurfaceNormal = 0x00000000, eFXSurfaceBlur = 0x00010000, eFXSurfaceDim = 0x00020000, + eFXSurfaceScreenshot= 0x00030000, eFXSurfaceMask = 0x000F0000, }; diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk index dab070567..61a835833 100644 --- a/services/surfaceflinger/Android.mk +++ b/services/surfaceflinger/Android.mk @@ -5,6 +5,7 @@ LOCAL_SRC_FILES:= \ Layer.cpp \ LayerBase.cpp \ LayerDim.cpp \ + LayerScreenshot.cpp \ DdmConnection.cpp \ DisplayHardware/DisplayHardware.cpp \ DisplayHardware/DisplayHardwareBase.cpp \ diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp index feb2c5272..76a2caa17 100644 --- a/services/surfaceflinger/Layer.cpp +++ b/services/surfaceflinger/Layer.cpp @@ -88,16 +88,8 @@ void Layer::onFirstRef() Layer::~Layer() { - class MessageDestroyGLState : public MessageBase { - GLuint texture; - public: - MessageDestroyGLState(GLuint texture) : texture(texture) { } - virtual bool handler() { - glDeleteTextures(1, &texture); - return true; - } - }; - mFlinger->postMessageAsync( new MessageDestroyGLState(mTextureName) ); + mFlinger->postMessageAsync( + new SurfaceFlinger::MessageDestroyGLTexture(mTextureName) ); } void Layer::onFrameQueued() { diff --git a/services/surfaceflinger/LayerScreenshot.cpp b/services/surfaceflinger/LayerScreenshot.cpp new file mode 100644 index 000000000..8945e466d --- /dev/null +++ b/services/surfaceflinger/LayerScreenshot.cpp @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include +#include + +#include + +#include "LayerScreenshot.h" +#include "SurfaceFlinger.h" +#include "DisplayHardware/DisplayHardware.h" + +namespace android { +// --------------------------------------------------------------------------- + +LayerScreenshot::LayerScreenshot(SurfaceFlinger* flinger, DisplayID display, + const sp& client) + : LayerBaseClient(flinger, display, client), + mTextureName(0), mFlinger(flinger) +{ +} + +LayerScreenshot::~LayerScreenshot() +{ + if (mTextureName) { + mFlinger->postMessageAsync( + new SurfaceFlinger::MessageDestroyGLTexture(mTextureName) ); + } +} + +status_t LayerScreenshot::capture() { + GLfloat u, v; + status_t result = mFlinger->renderScreenToTexture(0, &mTextureName, &u, &v); + if (result != NO_ERROR) { + return result; + } + + glBindTexture(GL_TEXTURE_2D, mTextureName); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + mTexCoords[0] = 0; mTexCoords[1] = v; + mTexCoords[2] = 0; mTexCoords[3] = 0; + mTexCoords[4] = u; mTexCoords[5] = 0; + mTexCoords[6] = u; mTexCoords[7] = v; + + return NO_ERROR; +} + +void LayerScreenshot::onDraw(const Region& clip) const +{ + const State& s(drawingState()); + Region::const_iterator it = clip.begin(); + Region::const_iterator const end = clip.end(); + if (s.alpha>0 && (it != end)) { + const DisplayHardware& hw(graphicPlane(0).displayHardware()); + const GLfloat alpha = s.alpha/255.0f; + const uint32_t fbHeight = hw.getHeight(); + glDisable(GL_DITHER); + + if (s.alpha == 0xFF) { + glDisable(GL_BLEND); + } else { + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } + + glColor4f(0, 0, 0, alpha); + +#if defined(GL_OES_EGL_image_external) + if (GLExtensions::getInstance().haveTextureExternal()) { + glDisable(GL_TEXTURE_EXTERNAL_OES); + } +#endif + + glBindTexture(GL_TEXTURE_2D, mTextureName); + glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); + glEnable(GL_TEXTURE_2D); + glMatrixMode(GL_TEXTURE); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glTexCoordPointer(2, GL_FLOAT, 0, mTexCoords); + glVertexPointer(2, GL_FLOAT, 0, mVertices); + + while (it != end) { + const Rect& r = *it++; + const GLint sy = fbHeight - (r.top + r.height()); + glScissor(r.left, sy, r.width(), r.height()); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + } + } + glDisableClientState(GL_TEXTURE_COORD_ARRAY); +} + +// --------------------------------------------------------------------------- + +}; // namespace android diff --git a/services/surfaceflinger/LayerScreenshot.h b/services/surfaceflinger/LayerScreenshot.h new file mode 100644 index 000000000..e3a2b1975 --- /dev/null +++ b/services/surfaceflinger/LayerScreenshot.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_LAYER_SCREENSHOT_H +#define ANDROID_LAYER_SCREENSHOT_H + +#include +#include + +#include +#include + +#include "LayerBase.h" + +// --------------------------------------------------------------------------- + +namespace android { + +class LayerScreenshot : public LayerBaseClient +{ + GLuint mTextureName; + GLfloat mTexCoords[8]; + sp mFlinger; +public: + LayerScreenshot(SurfaceFlinger* flinger, DisplayID display, + const sp& client); + virtual ~LayerScreenshot(); + + status_t capture(); + + virtual void onDraw(const Region& clip) const; + virtual bool isOpaque() const { return false; } + virtual bool isSecure() const { return false; } + virtual bool isProtectedByApp() const { return false; } + virtual bool isProtectedByDRM() const { return false; } + virtual const char* getTypeId() const { return "LayerScreenshot"; } +}; + +// --------------------------------------------------------------------------- + +}; // namespace android + +#endif // ANDROID_LAYER_SCREENSHOT_H diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index 1441a5406..3dccc1130 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -50,6 +50,7 @@ #include "DdmConnection.h" #include "Layer.h" #include "LayerDim.h" +#include "LayerScreenshot.h" #include "SurfaceFlinger.h" #include "DisplayHardware/DisplayHardware.h" @@ -1353,6 +1354,9 @@ sp SurfaceFlinger::createSurface( case eFXSurfaceDim: layer = createDimSurface(client, d, w, h, flags); break; + case eFXSurfaceScreenshot: + layer = createScreenshotSurface(client, d, w, h, flags); + break; } if (layer != 0) { @@ -1415,7 +1419,19 @@ sp SurfaceFlinger::createDimSurface( uint32_t w, uint32_t h, uint32_t flags) { sp layer = new LayerDim(this, display, client); - layer->initStates(w, h, flags); + return layer; +} + +sp SurfaceFlinger::createScreenshotSurface( + const sp& client, DisplayID display, + uint32_t w, uint32_t h, uint32_t flags) +{ + sp layer = new LayerScreenshot(this, display, client); + status_t err = layer->capture(); + if (err != NO_ERROR) { + layer.clear(); + LOGW("createScreenshotSurface failed (%s)", strerror(-err)); + } return layer; } @@ -1778,6 +1794,13 @@ void SurfaceFlinger::repaintEverything() { // --------------------------------------------------------------------------- +status_t SurfaceFlinger::renderScreenToTexture(DisplayID dpy, + GLuint* textureName, GLfloat* uOut, GLfloat* vOut) +{ + Mutex::Autolock _l(mStateLock); + return renderScreenToTextureLocked(dpy, textureName, uOut, vOut); +} + status_t SurfaceFlinger::renderScreenToTextureLocked(DisplayID dpy, GLuint* textureName, GLfloat* uOut, GLfloat* vOut) { @@ -1841,11 +1864,6 @@ status_t SurfaceFlinger::renderScreenToTextureLocked(DisplayID dpy, status_t SurfaceFlinger::electronBeamOffAnimationImplLocked() { - status_t result = PERMISSION_DENIED; - - if (!GLExtensions::getInstance().haveFramebufferObject()) - return INVALID_OPERATION; - // get screen geometry const DisplayHardware& hw(graphicPlane(0).displayHardware()); const uint32_t hw_w = hw.getWidth(); @@ -1854,7 +1872,7 @@ status_t SurfaceFlinger::electronBeamOffAnimationImplLocked() GLfloat u, v; GLuint tname; - result = renderScreenToTextureLocked(0, &tname, &u, &v); + status_t result = renderScreenToTextureLocked(0, &tname, &u, &v); if (result != NO_ERROR) { return result; } @@ -2030,10 +2048,6 @@ status_t SurfaceFlinger::electronBeamOnAnimationImplLocked() return result; } - // 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} }; glBindTexture(GL_TEXTURE_2D, tname); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index 0e642c100..3c8f4e5cc 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -49,6 +49,7 @@ class DisplayHardware; class FreezeLock; class Layer; class LayerDim; +class LayerScreenshot; struct surface_flinger_cblk_t; #define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) @@ -186,6 +187,15 @@ public: void screenReleased(DisplayID dpy); void screenAcquired(DisplayID dpy); + status_t renderScreenToTexture(DisplayID dpy, + GLuint* textureName, GLfloat* uOut, GLfloat* vOut); + + status_t postMessageAsync(const sp& msg, + nsecs_t reltime=0, uint32_t flags = 0); + + status_t postMessageSync(const sp& msg, + nsecs_t reltime=0, uint32_t flags = 0); + status_t removeLayer(const sp& layer); status_t addLayer(const sp& layer); status_t invalidateLayerVisibility(const sp& layer); @@ -195,6 +205,18 @@ public: GLuint getProtectedTexName() const { return mProtectedTexName; } + + class MessageDestroyGLTexture : public MessageBase { + GLuint texture; + public: + MessageDestroyGLTexture(GLuint texture) : texture(texture) { } + virtual bool handler() { + glDeleteTextures(1, &texture); + return true; + } + }; + + private: // DeathRecipient interface virtual void binderDied(const wp& who); @@ -204,7 +226,6 @@ private: friend class LayerBase; friend class LayerBaseClient; friend class Layer; - friend class LayerDim; sp createSurface( ISurfaceComposerClient::surface_data_t* params, @@ -222,6 +243,10 @@ private: const sp& client, DisplayID display, uint32_t w, uint32_t h, uint32_t flags); + sp createScreenshotSurface( + const sp& client, DisplayID display, + uint32_t w, uint32_t h, uint32_t flags); + status_t removeSurface(const sp& client, SurfaceID sid); status_t destroySurface(const wp& layer); uint32_t setClientStateLocked(const sp& client, const layer_state_t& s); @@ -329,12 +354,6 @@ private: mutable MessageQueue mEventQueue; - status_t postMessageAsync(const sp& msg, - nsecs_t reltime=0, uint32_t flags = 0); - - status_t postMessageSync(const sp& msg, - nsecs_t reltime=0, uint32_t flags = 0); - // access must be protected by mStateLock mutable Mutex mStateLock; State mCurrentState;