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.

Make sure to call compositionComplete() after rendering into a FBO.

Bug: 5446982, 5467587, 5466259
Change-Id: I5d8a1b4c327f9973d950cd4f4c0bca7f62825cd4
This commit is contained in:
Mathias Agopian 2011-10-13 16:02:48 -07:00
parent 3a3cad30c4
commit 118d0245ee
7 changed files with 227 additions and 28 deletions

View File

@ -53,6 +53,7 @@ public:
eFXSurfaceNormal = 0x00000000, eFXSurfaceNormal = 0x00000000,
eFXSurfaceBlur = 0x00010000, eFXSurfaceBlur = 0x00010000,
eFXSurfaceDim = 0x00020000, eFXSurfaceDim = 0x00020000,
eFXSurfaceScreenshot= 0x00030000,
eFXSurfaceMask = 0x000F0000, eFXSurfaceMask = 0x000F0000,
}; };

View File

@ -5,6 +5,7 @@ LOCAL_SRC_FILES:= \
Layer.cpp \ Layer.cpp \
LayerBase.cpp \ LayerBase.cpp \
LayerDim.cpp \ LayerDim.cpp \
LayerScreenshot.cpp \
DdmConnection.cpp \ DdmConnection.cpp \
DisplayHardware/DisplayHardware.cpp \ DisplayHardware/DisplayHardware.cpp \
DisplayHardware/DisplayHardwareBase.cpp \ DisplayHardware/DisplayHardwareBase.cpp \

View File

@ -88,16 +88,8 @@ void Layer::onFirstRef()
Layer::~Layer() Layer::~Layer()
{ {
class MessageDestroyGLState : public MessageBase { mFlinger->postMessageAsync(
GLuint texture; new SurfaceFlinger::MessageDestroyGLTexture(mTextureName) );
public:
MessageDestroyGLState(GLuint texture) : texture(texture) { }
virtual bool handler() {
glDeleteTextures(1, &texture);
return true;
}
};
mFlinger->postMessageAsync( new MessageDestroyGLState(mTextureName) );
} }
void Layer::onFrameQueued() { void Layer::onFrameQueued() {

View File

@ -0,0 +1,114 @@
/*
* 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 <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <ui/GraphicBuffer.h>
#include "LayerScreenshot.h"
#include "SurfaceFlinger.h"
#include "DisplayHardware/DisplayHardware.h"
namespace android {
// ---------------------------------------------------------------------------
LayerScreenshot::LayerScreenshot(SurfaceFlinger* flinger, DisplayID display,
const sp<Client>& 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();
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);
glDisable(GL_TEXTURE_EXTERNAL_OES);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, mTextureName);
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
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);
}
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
}
// ---------------------------------------------------------------------------
}; // namespace android

View File

@ -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 <stdint.h>
#include <sys/types.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include "LayerBase.h"
// ---------------------------------------------------------------------------
namespace android {
class LayerScreenshot : public LayerBaseClient
{
GLuint mTextureName;
GLfloat mTexCoords[8];
sp<SurfaceFlinger> mFlinger;
public:
LayerScreenshot(SurfaceFlinger* flinger, DisplayID display,
const sp<Client>& 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

View File

@ -50,6 +50,7 @@
#include "DdmConnection.h" #include "DdmConnection.h"
#include "Layer.h" #include "Layer.h"
#include "LayerDim.h" #include "LayerDim.h"
#include "LayerScreenshot.h"
#include "SurfaceFlinger.h" #include "SurfaceFlinger.h"
#include "DisplayHardware/DisplayHardware.h" #include "DisplayHardware/DisplayHardware.h"
@ -1358,6 +1359,9 @@ sp<ISurface> SurfaceFlinger::createSurface(
case eFXSurfaceDim: case eFXSurfaceDim:
layer = createDimSurface(client, d, w, h, flags); layer = createDimSurface(client, d, w, h, flags);
break; break;
case eFXSurfaceScreenshot:
layer = createScreenshotSurface(client, d, w, h, flags);
break;
} }
if (layer != 0) { if (layer != 0) {
@ -1420,7 +1424,19 @@ sp<LayerDim> SurfaceFlinger::createDimSurface(
uint32_t w, uint32_t h, uint32_t flags) uint32_t w, uint32_t h, uint32_t flags)
{ {
sp<LayerDim> layer = new LayerDim(this, display, client); sp<LayerDim> layer = new LayerDim(this, display, client);
layer->initStates(w, h, flags); return layer;
}
sp<LayerScreenshot> SurfaceFlinger::createScreenshotSurface(
const sp<Client>& client, DisplayID display,
uint32_t w, uint32_t h, uint32_t flags)
{
sp<LayerScreenshot> 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; return layer;
} }
@ -1783,6 +1799,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, status_t SurfaceFlinger::renderScreenToTextureLocked(DisplayID dpy,
GLuint* textureName, GLfloat* uOut, GLfloat* vOut) GLuint* textureName, GLfloat* uOut, GLfloat* vOut)
{ {
@ -1833,6 +1856,8 @@ status_t SurfaceFlinger::renderScreenToTextureLocked(DisplayID dpy,
layer->drawForSreenShot(); layer->drawForSreenShot();
} }
hw.compositionComplete();
// back to main framebuffer // back to main framebuffer
glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0); glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
glDisable(GL_SCISSOR_TEST); glDisable(GL_SCISSOR_TEST);
@ -1848,11 +1873,6 @@ status_t SurfaceFlinger::renderScreenToTextureLocked(DisplayID dpy,
status_t SurfaceFlinger::electronBeamOffAnimationImplLocked() status_t SurfaceFlinger::electronBeamOffAnimationImplLocked()
{ {
status_t result = PERMISSION_DENIED;
if (!GLExtensions::getInstance().haveFramebufferObject())
return INVALID_OPERATION;
// get screen geometry // get screen geometry
const DisplayHardware& hw(graphicPlane(0).displayHardware()); const DisplayHardware& hw(graphicPlane(0).displayHardware());
const uint32_t hw_w = hw.getWidth(); const uint32_t hw_w = hw.getWidth();
@ -1861,7 +1881,7 @@ status_t SurfaceFlinger::electronBeamOffAnimationImplLocked()
GLfloat u, v; GLfloat u, v;
GLuint tname; GLuint tname;
result = renderScreenToTextureLocked(0, &tname, &u, &v); status_t result = renderScreenToTextureLocked(0, &tname, &u, &v);
if (result != NO_ERROR) { if (result != NO_ERROR) {
return result; return result;
} }
@ -2038,10 +2058,6 @@ status_t SurfaceFlinger::electronBeamOnAnimationImplLocked()
return result; return result;
} }
// back to main framebuffer
glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
glDisable(GL_SCISSOR_TEST);
GLfloat vtx[8]; GLfloat vtx[8];
const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} }; const GLfloat texCoords[4][2] = { {0,v}, {0,0}, {u,0}, {u,v} };
glBindTexture(GL_TEXTURE_2D, tname); glBindTexture(GL_TEXTURE_2D, tname);

View File

@ -49,6 +49,7 @@ class DisplayHardware;
class FreezeLock; class FreezeLock;
class Layer; class Layer;
class LayerDim; class LayerDim;
class LayerScreenshot;
struct surface_flinger_cblk_t; struct surface_flinger_cblk_t;
#define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) #define LIKELY( exp ) (__builtin_expect( (exp) != 0, true ))
@ -186,6 +187,15 @@ public:
void screenReleased(DisplayID dpy); void screenReleased(DisplayID dpy);
void screenAcquired(DisplayID dpy); void screenAcquired(DisplayID dpy);
status_t renderScreenToTexture(DisplayID dpy,
GLuint* textureName, GLfloat* uOut, GLfloat* vOut);
status_t postMessageAsync(const sp<MessageBase>& msg,
nsecs_t reltime=0, uint32_t flags = 0);
status_t postMessageSync(const sp<MessageBase>& msg,
nsecs_t reltime=0, uint32_t flags = 0);
status_t removeLayer(const sp<LayerBase>& layer); status_t removeLayer(const sp<LayerBase>& layer);
status_t addLayer(const sp<LayerBase>& layer); status_t addLayer(const sp<LayerBase>& layer);
status_t invalidateLayerVisibility(const sp<LayerBase>& layer); status_t invalidateLayerVisibility(const sp<LayerBase>& layer);
@ -195,6 +205,18 @@ public:
GLuint getProtectedTexName() const { return mProtectedTexName; } 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: private:
// DeathRecipient interface // DeathRecipient interface
virtual void binderDied(const wp<IBinder>& who); virtual void binderDied(const wp<IBinder>& who);
@ -204,7 +226,6 @@ private:
friend class LayerBase; friend class LayerBase;
friend class LayerBaseClient; friend class LayerBaseClient;
friend class Layer; friend class Layer;
friend class LayerDim;
sp<ISurface> createSurface( sp<ISurface> createSurface(
ISurfaceComposerClient::surface_data_t* params, ISurfaceComposerClient::surface_data_t* params,
@ -222,6 +243,10 @@ private:
const sp<Client>& client, DisplayID display, const sp<Client>& client, DisplayID display,
uint32_t w, uint32_t h, uint32_t flags); uint32_t w, uint32_t h, uint32_t flags);
sp<LayerScreenshot> createScreenshotSurface(
const sp<Client>& client, DisplayID display,
uint32_t w, uint32_t h, uint32_t flags);
status_t removeSurface(const sp<Client>& client, SurfaceID sid); status_t removeSurface(const sp<Client>& client, SurfaceID sid);
status_t destroySurface(const wp<LayerBaseClient>& layer); status_t destroySurface(const wp<LayerBaseClient>& layer);
uint32_t setClientStateLocked(const sp<Client>& client, const layer_state_t& s); uint32_t setClientStateLocked(const sp<Client>& client, const layer_state_t& s);
@ -329,12 +354,6 @@ private:
mutable MessageQueue mEventQueue; mutable MessageQueue mEventQueue;
status_t postMessageAsync(const sp<MessageBase>& msg,
nsecs_t reltime=0, uint32_t flags = 0);
status_t postMessageSync(const sp<MessageBase>& msg,
nsecs_t reltime=0, uint32_t flags = 0);
// access must be protected by mStateLock // access must be protected by mStateLock
mutable Mutex mStateLock; mutable Mutex mStateLock;
State mCurrentState; State mCurrentState;