summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/gui/ISurfaceComposer.h9
-rw-r--r--include/gui/SurfaceComposerClient.h9
-rw-r--r--libs/gui/ISurfaceComposer.cpp34
-rw-r--r--libs/gui/SurfaceComposerClient.cpp11
-rw-r--r--services/surfaceflinger/Layer.h4
-rw-r--r--services/surfaceflinger/LayerScreenshot.cpp140
-rw-r--r--services/surfaceflinger/LayerScreenshot.h31
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp333
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h28
9 files changed, 269 insertions, 330 deletions
diff --git a/include/gui/ISurfaceComposer.h b/include/gui/ISurfaceComposer.h
index 4862949..08eddcb 100644
--- a/include/gui/ISurfaceComposer.h
+++ b/include/gui/ISurfaceComposer.h
@@ -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,
diff --git a/include/gui/SurfaceComposerClient.h b/include/gui/SurfaceComposerClient.h
index 9e4d6fc..38c931d 100644
--- a/include/gui/SurfaceComposerClient.h
+++ b/include/gui/SurfaceComposerClient.h
@@ -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();
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 72b6277..0a79ff7 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -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 =
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index e8e208f..edfa78a 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -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) {
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 242493d..e57fb59 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -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();
diff --git a/services/surfaceflinger/LayerScreenshot.cpp b/services/surfaceflinger/LayerScreenshot.cpp
index f8009b3..3470d67 100644
--- a/services/surfaceflinger/LayerScreenshot.cpp
+++ b/services/surfaceflinger/LayerScreenshot.cpp
@@ -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);
- }
-}
-
-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());
+ Layer::onFirstRef();
- 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);
}
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/LayerScreenshot.h b/services/surfaceflinger/LayerScreenshot.h
index 38cbd88..a2ae03f 100644
--- a/services/surfaceflinger/LayerScreenshot.h
+++ b/services/surfaceflinger/LayerScreenshot.h
@@ -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();
};
// ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 5cc74a7..8fa0800 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -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,86 +2606,158 @@ void SurfaceFlinger::repaintEverything() {
}
// ---------------------------------------------------------------------------
+// Capture screen into an IGraphiBufferProducer
+// ---------------------------------------------------------------------------
-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::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::renderScreenToTextureLocked(uint32_t layerStack,
- GLuint* textureName, GLfloat* uOut, GLfloat* vOut)
+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();
- 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;
+
+ // if we have secure windows on this display, never allow the screen capture
+ if (hw->getSecureLayerVisible()) {
+ ALOGW("FB is protected: PERMISSION_DENIED");
+ return PERMISSION_DENIED;
+ }
+
+ if ((reqWidth > hw_w) || (reqHeight > hw_h)) {
+ ALOGE("size mismatch (%d, %d) > (%d, %d)",
+ reqWidth, reqHeight, hw_w, hw_h);
+ return BAD_VALUE;
+ }
+
+ reqWidth = (!reqWidth) ? hw_w : reqWidth;
+ reqHeight = (!reqHeight) ? hw_h : reqHeight;
+ const bool filtering = reqWidth != hw_w || reqWidth != hw_h;
+
+ // 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;
- 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);
+ // 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();
// 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);
+ 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);
+ }
}
- hw->compositionComplete();
-
- // back to main framebuffer
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
- glDeleteFramebuffersOES(1, &name);
+ // and finishing things up...
+ if (eglSwapBuffers(mEGLDisplay, eglSurface) != EGL_TRUE) {
+ ALOGE("captureScreenImplLocked: eglSwapBuffers() failed 0x%4x",
+ eglGetError());
+ eglDestroySurface(mEGLDisplay, eglSurface);
+ return BAD_VALUE;
+ }
- *textureName = tname;
- *uOut = u;
- *vOut = v;
+ eglDestroySurface(mEGLDisplay, eglSurface);
return NO_ERROR;
}
// ---------------------------------------------------------------------------
+// Capture screen into an IMemoryHeap (legacy)
+// ---------------------------------------------------------------------------
-status_t SurfaceFlinger::captureScreenImplLocked(const sp<IBinder>& display,
+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,
@@ -2692,85 +2765,41 @@ status_t SurfaceFlinger::captureScreenImplLocked(const sp<IBinder>& display,
{
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();
-
- // if we have secure windows on this display, never allow the screen capture
- if (hw->getSecureLayerVisible()) {
- ALOGW("FB is protected: PERMISSION_DENIED");
- return PERMISSION_DENIED;
- }
-
- if ((sw > hw_w) || (sh > hw_h)) {
- ALOGE("size mismatch (%d, %d) > (%d, %d)", sw, sh, 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;
-
-// ALOGD("screenshot: sw=%d, sh=%d, minZ=%d, maxZ=%d",
-// sw, sh, minLayerZ, maxLayerZ);
-
- // 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);
-
- glGenFramebuffersOES(1, &name);
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, name);
- glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES,
- GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, tname);
-
- 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);
+ // 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);
- // redraw the screen entirely...
- glClearColor(0,0,0,1);
- glClear(GL_COLOR_BUFFER_BIT);
+ // 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;
- 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);
- }
- }
-
- // 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();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index e67f3f1..d1221dc 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -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