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:
parent
3a3cad30c4
commit
118d0245ee
@ -53,6 +53,7 @@ public:
|
|||||||
eFXSurfaceNormal = 0x00000000,
|
eFXSurfaceNormal = 0x00000000,
|
||||||
eFXSurfaceBlur = 0x00010000,
|
eFXSurfaceBlur = 0x00010000,
|
||||||
eFXSurfaceDim = 0x00020000,
|
eFXSurfaceDim = 0x00020000,
|
||||||
|
eFXSurfaceScreenshot= 0x00030000,
|
||||||
eFXSurfaceMask = 0x000F0000,
|
eFXSurfaceMask = 0x000F0000,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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 \
|
||||||
|
@ -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() {
|
||||||
|
114
services/surfaceflinger/LayerScreenshot.cpp
Normal file
114
services/surfaceflinger/LayerScreenshot.cpp
Normal 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
|
56
services/surfaceflinger/LayerScreenshot.h
Normal file
56
services/surfaceflinger/LayerScreenshot.h
Normal 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
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user