am 306f18c5
: Merge "rework screenshot API and implementation" into jb-mr2-dev
* commit '306f18c5fb15ac05db09ece7241af02b9713a23d': rework screenshot API and implementation
This commit is contained in:
commit
675427910b
@ -103,7 +103,6 @@ public:
|
||||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ) = 0;
|
||||
|
||||
|
||||
/* triggers screen off and waits for it to complete */
|
||||
virtual void blank(const sp<IBinder>& display) = 0;
|
||||
|
||||
@ -113,6 +112,11 @@ public:
|
||||
/* returns information about a display
|
||||
* intended to be used to get information about built-in displays */
|
||||
virtual status_t getDisplayInfo(const sp<IBinder>& display, DisplayInfo* info) = 0;
|
||||
|
||||
virtual status_t captureScreen(const sp<IBinder>& display,
|
||||
const sp<IGraphicBufferProducer>& producer,
|
||||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ) = 0;
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@ -130,11 +134,12 @@ public:
|
||||
GET_BUILT_IN_DISPLAY,
|
||||
SET_TRANSACTION_STATE,
|
||||
AUTHENTICATE_SURFACE,
|
||||
CAPTURE_SCREEN,
|
||||
CAPTURE_SCREEN_DEPRECATED,
|
||||
BLANK,
|
||||
UNBLANK,
|
||||
GET_DISPLAY_INFO,
|
||||
CONNECT_DISPLAY,
|
||||
CAPTURE_SCREEN,
|
||||
};
|
||||
|
||||
virtual status_t onTransact(uint32_t code, const Parcel& data,
|
||||
|
@ -156,10 +156,19 @@ private:
|
||||
|
||||
class ScreenshotClient
|
||||
{
|
||||
public:
|
||||
static status_t capture(
|
||||
const sp<IBinder>& display,
|
||||
const sp<IGraphicBufferProducer>& producer,
|
||||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ);
|
||||
|
||||
private:
|
||||
sp<IMemoryHeap> mHeap;
|
||||
uint32_t mWidth;
|
||||
uint32_t mHeight;
|
||||
PixelFormat mFormat;
|
||||
|
||||
public:
|
||||
ScreenshotClient();
|
||||
|
||||
|
@ -115,7 +115,7 @@ public:
|
||||
data.writeInt32(reqHeight);
|
||||
data.writeInt32(minLayerZ);
|
||||
data.writeInt32(maxLayerZ);
|
||||
remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
|
||||
remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN_DEPRECATED, data, &reply);
|
||||
*heap = interface_cast<IMemoryHeap>(reply.readStrongBinder());
|
||||
*width = reply.readInt32();
|
||||
*height = reply.readInt32();
|
||||
@ -123,6 +123,23 @@ public:
|
||||
return reply.readInt32();
|
||||
}
|
||||
|
||||
virtual status_t captureScreen(const sp<IBinder>& display,
|
||||
const sp<IGraphicBufferProducer>& producer,
|
||||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ)
|
||||
{
|
||||
Parcel data, reply;
|
||||
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
|
||||
data.writeStrongBinder(display);
|
||||
data.writeStrongBinder(producer->asBinder());
|
||||
data.writeInt32(reqWidth);
|
||||
data.writeInt32(reqHeight);
|
||||
data.writeInt32(minLayerZ);
|
||||
data.writeInt32(maxLayerZ);
|
||||
remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
|
||||
return reply.readInt32();
|
||||
}
|
||||
|
||||
virtual bool authenticateSurfaceTexture(
|
||||
const sp<IGraphicBufferProducer>& bufferProducer) const
|
||||
{
|
||||
@ -268,7 +285,7 @@ status_t BnSurfaceComposer::onTransact(
|
||||
CHECK_INTERFACE(ISurfaceComposer, data, reply);
|
||||
bootFinished();
|
||||
} break;
|
||||
case CAPTURE_SCREEN: {
|
||||
case CAPTURE_SCREEN_DEPRECATED: {
|
||||
CHECK_INTERFACE(ISurfaceComposer, data, reply);
|
||||
sp<IBinder> display = data.readStrongBinder();
|
||||
uint32_t reqWidth = data.readInt32();
|
||||
@ -286,6 +303,19 @@ status_t BnSurfaceComposer::onTransact(
|
||||
reply->writeInt32(f);
|
||||
reply->writeInt32(res);
|
||||
} break;
|
||||
case CAPTURE_SCREEN: {
|
||||
CHECK_INTERFACE(ISurfaceComposer, data, reply);
|
||||
sp<IBinder> display = data.readStrongBinder();
|
||||
sp<IGraphicBufferProducer> producer =
|
||||
interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
|
||||
uint32_t reqWidth = data.readInt32();
|
||||
uint32_t reqHeight = data.readInt32();
|
||||
uint32_t minLayerZ = data.readInt32();
|
||||
uint32_t maxLayerZ = data.readInt32();
|
||||
status_t res = captureScreen(display, producer,
|
||||
reqWidth, reqHeight, minLayerZ, maxLayerZ);
|
||||
reply->writeInt32(res);
|
||||
} break;
|
||||
case AUTHENTICATE_SURFACE: {
|
||||
CHECK_INTERFACE(ISurfaceComposer, data, reply);
|
||||
sp<IGraphicBufferProducer> bufferProducer =
|
||||
|
@ -606,6 +606,17 @@ void SurfaceComposerClient::unblankDisplay(const sp<IBinder>& token) {
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
status_t ScreenshotClient::capture(
|
||||
const sp<IBinder>& display,
|
||||
const sp<IGraphicBufferProducer>& producer,
|
||||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ) {
|
||||
sp<ISurfaceComposer> s(ComposerService::getComposerService());
|
||||
if (s == NULL) return NO_INIT;
|
||||
return s->captureScreen(display, producer,
|
||||
reqWidth, reqHeight, minLayerZ, maxLayerZ);
|
||||
}
|
||||
|
||||
ScreenshotClient::ScreenshotClient()
|
||||
: mWidth(0), mHeight(0), mFormat(PIXEL_FORMAT_NONE) {
|
||||
}
|
||||
|
@ -112,6 +112,10 @@ protected:
|
||||
virtual void dumpStats(String8& result, char* buffer, size_t SIZE) const;
|
||||
virtual void clearStats();
|
||||
|
||||
sp<SurfaceFlingerConsumer> getConsumer() const {
|
||||
return mSurfaceFlingerConsumer;
|
||||
}
|
||||
|
||||
private:
|
||||
// Creates an instance of ISurface for this Layer.
|
||||
virtual sp<ISurface> createSurface();
|
||||
|
@ -18,152 +18,28 @@
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <GLES/gl.h>
|
||||
#include <GLES/glext.h>
|
||||
|
||||
#include <utils/Errors.h>
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <ui/GraphicBuffer.h>
|
||||
|
||||
#include "LayerScreenshot.h"
|
||||
#include "SurfaceFlinger.h"
|
||||
#include "DisplayDevice.h"
|
||||
|
||||
|
||||
namespace android {
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
LayerScreenshot::LayerScreenshot(SurfaceFlinger* flinger,
|
||||
const sp<Client>& client)
|
||||
: LayerBaseClient(flinger, client),
|
||||
mTextureName(0), mFlinger(flinger), mIsSecure(false)
|
||||
: Layer(flinger, client)
|
||||
{
|
||||
}
|
||||
|
||||
LayerScreenshot::~LayerScreenshot()
|
||||
void LayerScreenshot::onFirstRef()
|
||||
{
|
||||
if (mTextureName) {
|
||||
mFlinger->deleteTextureAsync(mTextureName);
|
||||
}
|
||||
}
|
||||
Layer::onFirstRef();
|
||||
|
||||
status_t LayerScreenshot::captureLocked(int32_t layerStack) {
|
||||
GLfloat u, v;
|
||||
status_t result = mFlinger->renderScreenToTextureLocked(layerStack,
|
||||
&mTextureName, &u, &v);
|
||||
if (result != NO_ERROR) {
|
||||
return result;
|
||||
}
|
||||
initTexture(u, v);
|
||||
|
||||
// Currently screenshot always comes from the default display
|
||||
mIsSecure = mFlinger->getDefaultDisplayDevice()->getSecureLayerVisible();
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
status_t LayerScreenshot::capture() {
|
||||
GLfloat u, v;
|
||||
status_t result = mFlinger->renderScreenToTexture(0, &mTextureName, &u, &v);
|
||||
if (result != NO_ERROR) {
|
||||
return result;
|
||||
}
|
||||
initTexture(u, v);
|
||||
|
||||
// Currently screenshot always comes from the default display
|
||||
mIsSecure = mFlinger->getDefaultDisplayDevice()->getSecureLayerVisible();
|
||||
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
void LayerScreenshot::initTexture(GLfloat u, GLfloat v) {
|
||||
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;
|
||||
}
|
||||
|
||||
void LayerScreenshot::initStates(uint32_t w, uint32_t h, uint32_t flags) {
|
||||
LayerBaseClient::initStates(w, h, flags);
|
||||
if (!(flags & ISurfaceComposerClient::eHidden)) {
|
||||
capture();
|
||||
}
|
||||
if (flags & ISurfaceComposerClient::eSecure) {
|
||||
ALOGW("ignoring surface flag eSecure - LayerScreenshot is considered "
|
||||
"secure iff it captures the contents of a secure surface.");
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t LayerScreenshot::doTransaction(uint32_t flags)
|
||||
{
|
||||
const LayerBase::State& draw(drawingState());
|
||||
const LayerBase::State& curr(currentState());
|
||||
|
||||
if (draw.flags & layer_state_t::eLayerHidden) {
|
||||
if (!(curr.flags & layer_state_t::eLayerHidden)) {
|
||||
// we're going from hidden to visible
|
||||
status_t err = captureLocked(curr.layerStack);
|
||||
if (err != NO_ERROR) {
|
||||
ALOGW("createScreenshotSurface failed (%s)", strerror(-err));
|
||||
}
|
||||
}
|
||||
} else if (curr.flags & layer_state_t::eLayerHidden) {
|
||||
// we're going from visible to hidden
|
||||
if (mTextureName) {
|
||||
glDeleteTextures(1, &mTextureName);
|
||||
mTextureName = 0;
|
||||
}
|
||||
}
|
||||
return LayerBaseClient::doTransaction(flags);
|
||||
}
|
||||
|
||||
void LayerScreenshot::onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const
|
||||
{
|
||||
const State& s(drawingState());
|
||||
if (s.alpha>0) {
|
||||
const GLfloat alpha = s.alpha/255.0f;
|
||||
const uint32_t fbHeight = hw->getHeight();
|
||||
|
||||
if (s.alpha == 0xFF) {
|
||||
glDisable(GL_BLEND);
|
||||
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
} else {
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
|
||||
}
|
||||
|
||||
GLuint texName = mTextureName;
|
||||
if (isSecure() && !hw->isSecure()) {
|
||||
texName = mFlinger->getProtectedTexName();
|
||||
}
|
||||
|
||||
LayerMesh mesh;
|
||||
computeGeometry(hw, &mesh);
|
||||
|
||||
glColor4f(alpha, alpha, alpha, alpha);
|
||||
|
||||
glDisable(GL_TEXTURE_EXTERNAL_OES);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texName);
|
||||
glMatrixMode(GL_TEXTURE);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
glTexCoordPointer(2, GL_FLOAT, 0, mTexCoords);
|
||||
glVertexPointer(2, GL_FLOAT, 0, mesh.getVertices());
|
||||
glDrawArrays(GL_TRIANGLE_FAN, 0, mesh.getVertexCount());
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||
}
|
||||
// FIXME: we currently hardcode the default display
|
||||
// it's unclear what should we do instead.
|
||||
sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
|
||||
mFlinger->captureScreenImplLocked(hw, getConsumer()->getBufferQueue(),
|
||||
0, 0, 0, 0x7FFFFFFF);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -20,39 +20,18 @@
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
#include "LayerBase.h"
|
||||
#include "Layer.h"
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
namespace android {
|
||||
|
||||
class LayerScreenshot : public LayerBaseClient
|
||||
class LayerScreenshot : public Layer
|
||||
{
|
||||
GLuint mTextureName;
|
||||
GLfloat mTexCoords[8];
|
||||
sp<SurfaceFlinger> mFlinger;
|
||||
bool mIsSecure;
|
||||
public:
|
||||
LayerScreenshot(SurfaceFlinger* flinger, const sp<Client>& client);
|
||||
virtual ~LayerScreenshot();
|
||||
|
||||
status_t capture();
|
||||
|
||||
virtual void initStates(uint32_t w, uint32_t h, uint32_t flags);
|
||||
virtual uint32_t doTransaction(uint32_t flags);
|
||||
virtual void onDraw(const sp<const DisplayDevice>& hw, const Region& clip) const;
|
||||
virtual bool isOpaque() const { return false; }
|
||||
virtual bool isSecure() const { return mIsSecure; }
|
||||
virtual bool isProtectedByApp() const { return false; }
|
||||
virtual bool isProtectedByDRM() const { return false; }
|
||||
virtual const char* getTypeId() const { return "LayerScreenshot"; }
|
||||
|
||||
private:
|
||||
status_t captureLocked(int32_t layerStack);
|
||||
void initTexture(GLfloat u, GLfloat v);
|
||||
LayerScreenshot(SurfaceFlinger* flinger, const sp<Client>& client);
|
||||
protected:
|
||||
virtual void onFirstRef();
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
@ -2020,6 +2020,7 @@ sp<LayerScreenshot> SurfaceFlinger::createScreenshotLayer(
|
||||
uint32_t w, uint32_t h, uint32_t flags)
|
||||
{
|
||||
sp<LayerScreenshot> layer = new LayerScreenshot(this, client);
|
||||
layer->setBuffers(w, h, PIXEL_FORMAT_RGBA_8888, flags);
|
||||
return layer;
|
||||
}
|
||||
|
||||
@ -2605,101 +2606,69 @@ void SurfaceFlinger::repaintEverything() {
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
status_t SurfaceFlinger::renderScreenToTexture(uint32_t layerStack,
|
||||
GLuint* textureName, GLfloat* uOut, GLfloat* vOut)
|
||||
{
|
||||
Mutex::Autolock _l(mStateLock);
|
||||
return renderScreenToTextureLocked(layerStack, textureName, uOut, vOut);
|
||||
}
|
||||
|
||||
status_t SurfaceFlinger::renderScreenToTextureLocked(uint32_t layerStack,
|
||||
GLuint* textureName, GLfloat* uOut, GLfloat* vOut)
|
||||
{
|
||||
ATRACE_CALL();
|
||||
|
||||
if (!GLExtensions::getInstance().haveFramebufferObject())
|
||||
return INVALID_OPERATION;
|
||||
|
||||
// get screen geometry
|
||||
// FIXME: figure out what it means to have a screenshot texture w/ multi-display
|
||||
sp<const DisplayDevice> hw(getDefaultDisplayDevice());
|
||||
const uint32_t hw_w = hw->getWidth();
|
||||
const uint32_t hw_h = hw->getHeight();
|
||||
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_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
|
||||
hw_w, hw_h, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
|
||||
if (glGetError() != GL_NO_ERROR) {
|
||||
while ( 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);
|
||||
|
||||
DisplayDevice::setViewportAndProjection(hw);
|
||||
|
||||
// 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<LayerBase> >& layers(hw->getVisibleLayersSortedByZ());
|
||||
const size_t count = layers.size();
|
||||
for (size_t i=0 ; i<count ; ++i) {
|
||||
const sp<LayerBase>& layer(layers[i]);
|
||||
layer->draw(hw);
|
||||
}
|
||||
|
||||
hw->compositionComplete();
|
||||
|
||||
// back to main framebuffer
|
||||
glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
|
||||
glDeleteFramebuffersOES(1, &name);
|
||||
|
||||
*textureName = tname;
|
||||
*uOut = u;
|
||||
*vOut = v;
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
// Capture screen into an IGraphiBufferProducer
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
status_t SurfaceFlinger::captureScreenImplLocked(const sp<IBinder>& display,
|
||||
sp<IMemoryHeap>* heap,
|
||||
uint32_t* w, uint32_t* h, PixelFormat* f,
|
||||
uint32_t sw, uint32_t sh,
|
||||
status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
|
||||
const sp<IGraphicBufferProducer>& producer,
|
||||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ) {
|
||||
|
||||
if (CC_UNLIKELY(display == 0))
|
||||
return BAD_VALUE;
|
||||
|
||||
if (CC_UNLIKELY(producer == 0))
|
||||
return BAD_VALUE;
|
||||
|
||||
class MessageCaptureScreen : public MessageBase {
|
||||
SurfaceFlinger* flinger;
|
||||
sp<IBinder> display;
|
||||
sp<IGraphicBufferProducer> producer;
|
||||
uint32_t reqWidth, reqHeight;
|
||||
uint32_t minLayerZ,maxLayerZ;
|
||||
status_t result;
|
||||
public:
|
||||
MessageCaptureScreen(SurfaceFlinger* flinger,
|
||||
const sp<IBinder>& display,
|
||||
const sp<IGraphicBufferProducer>& producer,
|
||||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ)
|
||||
: flinger(flinger), display(display), producer(producer),
|
||||
reqWidth(reqWidth), reqHeight(reqHeight),
|
||||
minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
|
||||
result(PERMISSION_DENIED)
|
||||
{
|
||||
}
|
||||
status_t getResult() const {
|
||||
return result;
|
||||
}
|
||||
virtual bool handler() {
|
||||
Mutex::Autolock _l(flinger->mStateLock);
|
||||
sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
|
||||
result = flinger->captureScreenImplLocked(hw, producer,
|
||||
reqWidth, reqHeight, minLayerZ, maxLayerZ);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
sp<MessageBase> msg = new MessageCaptureScreen(this,
|
||||
display, producer, reqWidth, reqHeight, minLayerZ, maxLayerZ);
|
||||
status_t res = postMessageSync(msg);
|
||||
if (res == NO_ERROR) {
|
||||
res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult();
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
status_t SurfaceFlinger::captureScreenImplLocked(
|
||||
const sp<const DisplayDevice>& hw,
|
||||
const sp<IGraphicBufferProducer>& producer,
|
||||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ)
|
||||
{
|
||||
ATRACE_CALL();
|
||||
|
||||
status_t result = PERMISSION_DENIED;
|
||||
|
||||
if (!GLExtensions::getInstance().haveFramebufferObject()) {
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
|
||||
// get screen geometry
|
||||
sp<const DisplayDevice> hw(getDisplayDevice(display));
|
||||
const uint32_t hw_w = hw->getWidth();
|
||||
const uint32_t hw_h = hw->getHeight();
|
||||
|
||||
@ -2709,68 +2678,128 @@ status_t SurfaceFlinger::captureScreenImplLocked(const sp<IBinder>& display,
|
||||
return PERMISSION_DENIED;
|
||||
}
|
||||
|
||||
if ((sw > hw_w) || (sh > hw_h)) {
|
||||
ALOGE("size mismatch (%d, %d) > (%d, %d)", sw, sh, hw_w, hw_h);
|
||||
if ((reqWidth > hw_w) || (reqHeight > hw_h)) {
|
||||
ALOGE("size mismatch (%d, %d) > (%d, %d)",
|
||||
reqWidth, reqHeight, hw_w, hw_h);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
sw = (!sw) ? hw_w : sw;
|
||||
sh = (!sh) ? hw_h : sh;
|
||||
const size_t size = sw * sh * 4;
|
||||
const bool filtering = sw != hw_w || sh != hw_h;
|
||||
reqWidth = (!reqWidth) ? hw_w : reqWidth;
|
||||
reqHeight = (!reqHeight) ? hw_h : reqHeight;
|
||||
const bool filtering = reqWidth != hw_w || reqWidth != hw_h;
|
||||
|
||||
// ALOGD("screenshot: sw=%d, sh=%d, minZ=%d, maxZ=%d",
|
||||
// sw, sh, minLayerZ, maxLayerZ);
|
||||
// Create a surface to render into
|
||||
sp<Surface> surface = new Surface(producer);
|
||||
ANativeWindow* const window = surface.get();
|
||||
|
||||
// set the buffer size to what the user requested
|
||||
native_window_set_buffers_user_dimensions(window, reqWidth, reqHeight);
|
||||
|
||||
// and create the corresponding EGLSurface
|
||||
EGLSurface eglSurface = eglCreateWindowSurface(
|
||||
mEGLDisplay, mEGLConfig, window, NULL);
|
||||
if (eglSurface == EGL_NO_SURFACE) {
|
||||
ALOGE("captureScreenImplLocked: eglCreateWindowSurface() failed 0x%4x",
|
||||
eglGetError());
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
if (!eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext)) {
|
||||
ALOGE("captureScreenImplLocked: eglMakeCurrent() failed 0x%4x",
|
||||
eglGetError());
|
||||
eglDestroySurface(mEGLDisplay, eglSurface);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
// make sure to clear all GL error flags
|
||||
while ( glGetError() != GL_NO_ERROR ) ;
|
||||
|
||||
// create a FBO
|
||||
GLuint name, tname;
|
||||
glGenRenderbuffersOES(1, &tname);
|
||||
glBindRenderbufferOES(GL_RENDERBUFFER_OES, tname);
|
||||
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_RGBA8_OES, sw, sh);
|
||||
// set-up our viewport
|
||||
glViewport(0, 0, reqWidth, reqHeight);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrthof(0, hw_w, 0, hw_h, 0, 1);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
glGenFramebuffersOES(1, &name);
|
||||
glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
|
||||
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES,
|
||||
GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname);
|
||||
// redraw the screen entirely...
|
||||
glDisable(GL_TEXTURE_EXTERNAL_OES);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glClearColor(0,0,0,1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
|
||||
|
||||
if (status == GL_FRAMEBUFFER_COMPLETE_OES) {
|
||||
|
||||
// invert everything, b/c glReadPixel() below will invert the FB
|
||||
GLint viewport[4];
|
||||
glGetIntegerv(GL_VIEWPORT, viewport);
|
||||
glViewport(0, 0, sw, sh);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix();
|
||||
glLoadIdentity();
|
||||
glOrthof(0, hw_w, hw_h, 0, 0, 1);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
// redraw the screen entirely...
|
||||
glClearColor(0,0,0,1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
const Vector< sp<LayerBase> >& layers(hw->getVisibleLayersSortedByZ());
|
||||
const size_t count = layers.size();
|
||||
for (size_t i=0 ; i<count ; ++i) {
|
||||
const sp<LayerBase>& layer(layers[i]);
|
||||
const uint32_t z = layer->drawingState().z;
|
||||
if (z >= minLayerZ && z <= maxLayerZ) {
|
||||
if (filtering) layer->setFiltering(true);
|
||||
layer->draw(hw);
|
||||
if (filtering) layer->setFiltering(false);
|
||||
}
|
||||
const Vector< sp<LayerBase> >& layers(hw->getVisibleLayersSortedByZ());
|
||||
const size_t count = layers.size();
|
||||
for (size_t i=0 ; i<count ; ++i) {
|
||||
const sp<LayerBase>& layer(layers[i]);
|
||||
const uint32_t z = layer->drawingState().z;
|
||||
if (z >= minLayerZ && z <= maxLayerZ) {
|
||||
if (filtering) layer->setFiltering(true);
|
||||
layer->draw(hw);
|
||||
if (filtering) layer->setFiltering(false);
|
||||
}
|
||||
}
|
||||
|
||||
// and finishing things up...
|
||||
if (eglSwapBuffers(mEGLDisplay, eglSurface) != EGL_TRUE) {
|
||||
ALOGE("captureScreenImplLocked: eglSwapBuffers() failed 0x%4x",
|
||||
eglGetError());
|
||||
eglDestroySurface(mEGLDisplay, eglSurface);
|
||||
return BAD_VALUE;
|
||||
}
|
||||
|
||||
eglDestroySurface(mEGLDisplay, eglSurface);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Capture screen into an IMemoryHeap (legacy)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
status_t SurfaceFlinger::captureScreenImplLocked(
|
||||
const sp<const DisplayDevice>& hw,
|
||||
sp<IMemoryHeap>* heap,
|
||||
uint32_t* w, uint32_t* h, PixelFormat* f,
|
||||
uint32_t sw, uint32_t sh,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ)
|
||||
{
|
||||
ATRACE_CALL();
|
||||
|
||||
if (!GLExtensions::getInstance().haveFramebufferObject()) {
|
||||
return INVALID_OPERATION;
|
||||
}
|
||||
|
||||
// create the texture that will receive the screenshot, later we'll
|
||||
// attach a FBO to it so we can call glReadPixels().
|
||||
GLuint tname;
|
||||
glGenTextures(1, &tname);
|
||||
glBindTexture(GL_TEXTURE_2D, tname);
|
||||
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
// the GLConsumer will provide the BufferQueue
|
||||
sp<GLConsumer> consumer = new GLConsumer(tname, true, GL_TEXTURE_2D);
|
||||
consumer->getBufferQueue()->setDefaultBufferFormat(HAL_PIXEL_FORMAT_RGBA_8888);
|
||||
|
||||
// call the new screenshot taking code, passing a BufferQueue to it
|
||||
status_t result = captureScreenImplLocked(hw,
|
||||
consumer->getBufferQueue(), sw, sh, minLayerZ, maxLayerZ);
|
||||
|
||||
if (result == NO_ERROR) {
|
||||
result = consumer->updateTexImage();
|
||||
if (result == NO_ERROR) {
|
||||
// create a FBO
|
||||
GLuint name;
|
||||
glGenFramebuffersOES(1, &name);
|
||||
glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
|
||||
glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES,
|
||||
GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, tname, 0);
|
||||
|
||||
sp<GraphicBuffer> buf(consumer->getCurrentBuffer());
|
||||
sw = buf->getWidth();
|
||||
sh = buf->getHeight();
|
||||
size_t size = buf->getStride() * sh * 4;
|
||||
|
||||
// check for errors and return screen capture
|
||||
if (glGetError() != GL_NO_ERROR) {
|
||||
// error while rendering
|
||||
result = INVALID_OPERATION;
|
||||
} else {
|
||||
// allocate shared memory large enough to hold the
|
||||
// screen capture
|
||||
sp<MemoryHeapBase> base(
|
||||
@ -2790,59 +2819,48 @@ status_t SurfaceFlinger::captureScreenImplLocked(const sp<IBinder>& display,
|
||||
} else {
|
||||
result = NO_MEMORY;
|
||||
}
|
||||
|
||||
// back to main framebuffer
|
||||
glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
|
||||
glDeleteFramebuffersOES(1, &name);
|
||||
}
|
||||
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPopMatrix();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
} else {
|
||||
result = BAD_VALUE;
|
||||
}
|
||||
|
||||
// release FBO resources
|
||||
glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
|
||||
glDeleteRenderbuffersOES(1, &tname);
|
||||
glDeleteFramebuffersOES(1, &name);
|
||||
|
||||
hw->compositionComplete();
|
||||
|
||||
// ALOGD("screenshot: result = %s", result<0 ? strerror(result) : "OK");
|
||||
glDeleteTextures(1, &tname);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
|
||||
sp<IMemoryHeap>* heap,
|
||||
uint32_t* width, uint32_t* height, PixelFormat* format,
|
||||
uint32_t sw, uint32_t sh,
|
||||
uint32_t* outWidth, uint32_t* outHeight, PixelFormat* outFormat,
|
||||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ)
|
||||
{
|
||||
if (CC_UNLIKELY(display == 0))
|
||||
return BAD_VALUE;
|
||||
|
||||
if (!GLExtensions::getInstance().haveFramebufferObject())
|
||||
return INVALID_OPERATION;
|
||||
|
||||
class MessageCaptureScreen : public MessageBase {
|
||||
SurfaceFlinger* flinger;
|
||||
sp<IBinder> display;
|
||||
sp<IMemoryHeap>* heap;
|
||||
uint32_t* w;
|
||||
uint32_t* h;
|
||||
PixelFormat* f;
|
||||
uint32_t sw;
|
||||
uint32_t sh;
|
||||
uint32_t* outWidth;
|
||||
uint32_t* outHeight;
|
||||
PixelFormat* outFormat;
|
||||
uint32_t reqWidth;
|
||||
uint32_t reqHeight;
|
||||
uint32_t minLayerZ;
|
||||
uint32_t maxLayerZ;
|
||||
status_t result;
|
||||
public:
|
||||
MessageCaptureScreen(SurfaceFlinger* flinger, const sp<IBinder>& display,
|
||||
sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f,
|
||||
uint32_t sw, uint32_t sh,
|
||||
MessageCaptureScreen(SurfaceFlinger* flinger,
|
||||
const sp<IBinder>& display, sp<IMemoryHeap>* heap,
|
||||
uint32_t* outWidth, uint32_t* outHeight, PixelFormat* outFormat,
|
||||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ)
|
||||
: flinger(flinger), display(display),
|
||||
heap(heap), w(w), h(h), f(f), sw(sw), sh(sh),
|
||||
: flinger(flinger), display(display), heap(heap),
|
||||
outWidth(outWidth), outHeight(outHeight), outFormat(outFormat),
|
||||
reqWidth(reqWidth), reqHeight(reqHeight),
|
||||
minLayerZ(minLayerZ), maxLayerZ(maxLayerZ),
|
||||
result(PERMISSION_DENIED)
|
||||
{
|
||||
@ -2852,14 +2870,17 @@ status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display,
|
||||
}
|
||||
virtual bool handler() {
|
||||
Mutex::Autolock _l(flinger->mStateLock);
|
||||
result = flinger->captureScreenImplLocked(display,
|
||||
heap, w, h, f, sw, sh, minLayerZ, maxLayerZ);
|
||||
sp<const DisplayDevice> hw(flinger->getDisplayDevice(display));
|
||||
result = flinger->captureScreenImplLocked(hw, heap,
|
||||
outWidth, outHeight, outFormat,
|
||||
reqWidth, reqHeight, minLayerZ, maxLayerZ);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
sp<MessageBase> msg = new MessageCaptureScreen(this,
|
||||
display, heap, width, height, format, sw, sh, minLayerZ, maxLayerZ);
|
||||
sp<MessageBase> msg = new MessageCaptureScreen(this, display, heap,
|
||||
outWidth, outHeight, outFormat,
|
||||
reqWidth, reqHeight, minLayerZ, maxLayerZ);
|
||||
status_t res = postMessageSync(msg);
|
||||
if (res == NO_ERROR) {
|
||||
res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult();
|
||||
|
@ -103,14 +103,6 @@ public:
|
||||
// force full composition on all displays
|
||||
void repaintEverything();
|
||||
|
||||
// renders content on given display to a texture. thread-safe version.
|
||||
status_t renderScreenToTexture(uint32_t layerStack, GLuint* textureName,
|
||||
GLfloat* uOut, GLfloat* vOut);
|
||||
|
||||
// renders content on given display to a texture, w/o acquiring main lock
|
||||
status_t renderScreenToTextureLocked(uint32_t layerStack, GLuint* textureName,
|
||||
GLfloat* uOut, GLfloat* vOut);
|
||||
|
||||
// returns the default Display
|
||||
sp<const DisplayDevice> getDefaultDisplayDevice() const {
|
||||
return getDisplayDevice(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]);
|
||||
@ -202,6 +194,10 @@ private:
|
||||
uint32_t* width, uint32_t* height, PixelFormat* format,
|
||||
uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ,
|
||||
uint32_t maxLayerZ);
|
||||
virtual status_t captureScreen(const sp<IBinder>& display,
|
||||
const sp<IGraphicBufferProducer>& producer,
|
||||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ);
|
||||
// called when screen needs to turn off
|
||||
virtual void blank(const sp<IBinder>& display);
|
||||
// called when screen is turning back on
|
||||
@ -306,10 +302,18 @@ private:
|
||||
|
||||
void startBootAnim();
|
||||
|
||||
status_t captureScreenImplLocked(const sp<IBinder>& display, sp<IMemoryHeap>* heap,
|
||||
uint32_t* width, uint32_t* height, PixelFormat* format,
|
||||
uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ,
|
||||
uint32_t maxLayerZ);
|
||||
status_t captureScreenImplLocked(
|
||||
const sp<const DisplayDevice>& hw,
|
||||
sp<IMemoryHeap>* heap,
|
||||
uint32_t* width, uint32_t* height, PixelFormat* format,
|
||||
uint32_t reqWidth, uint32_t reqHeight, uint32_t minLayerZ,
|
||||
uint32_t maxLayerZ);
|
||||
|
||||
status_t captureScreenImplLocked(
|
||||
const sp<const DisplayDevice>& hw,
|
||||
const sp<IGraphicBufferProducer>& producer,
|
||||
uint32_t reqWidth, uint32_t reqHeight,
|
||||
uint32_t minLayerZ, uint32_t maxLayerZ);
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* EGL
|
||||
|
Loading…
Reference in New Issue
Block a user