summaryrefslogtreecommitdiffstats
path: root/services/surfaceflinger/SurfaceFlinger.cpp
diff options
context:
space:
mode:
authorMathias Agopian <mathias@google.com>2010-09-29 13:02:36 -0700
committerMathias Agopian <mathias@google.com>2010-10-04 17:36:17 -0700
commit597c7f67b5f2491c6098a1de241a3f0fd274688a (patch)
tree841774d2e67bfced0608d2344868c64ac566004e /services/surfaceflinger/SurfaceFlinger.cpp
parent541d942000c338a15dc4b361b15b72864640d2bf (diff)
downloadframeworks_base-597c7f67b5f2491c6098a1de241a3f0fd274688a.zip
frameworks_base-597c7f67b5f2491c6098a1de241a3f0fd274688a.tar.gz
frameworks_base-597c7f67b5f2491c6098a1de241a3f0fd274688a.tar.bz2
refactored screenshot code
the core screenshot function now can capture the screen at any lower resolution performing bilinear filtering. we also now have some client code to interface with the screenshot service. it's now possible to request a screenshot at a lower resolution. Change-Id: I33689bba98507ab928d0898b21596d0d2fe4b953
Diffstat (limited to 'services/surfaceflinger/SurfaceFlinger.cpp')
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp202
1 files changed, 117 insertions, 85 deletions
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 2b06f6f..e5e87c6 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1546,9 +1546,117 @@ status_t SurfaceFlinger::onTransact(
// ---------------------------------------------------------------------------
+status_t SurfaceFlinger::captureScreenImplLocked(DisplayID dpy,
+ sp<IMemoryHeap>* heap,
+ uint32_t* w, uint32_t* h, PixelFormat* f,
+ uint32_t sw, uint32_t sh)
+{
+ status_t result = PERMISSION_DENIED;
+
+ // only one display supported for now
+ if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
+ return BAD_VALUE;
+
+ if (!GLExtensions::getInstance().haveFramebufferObject())
+ return INVALID_OPERATION;
+
+ // get screen geometry
+ const DisplayHardware& hw(graphicPlane(dpy).displayHardware());
+ const uint32_t hw_w = hw.getWidth();
+ const uint32_t hw_h = hw.getHeight();
+
+ if ((sw > hw_w) || (sh > hw_h))
+ return BAD_VALUE;
+
+ sw = (!sw) ? hw_w : sw;
+ sh = (!sh) ? hw_h : sh;
+ const size_t size = sw * sh * 4;
+
+ // 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
+ glViewport(0, 0, sw, sh);
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glOrthof(0, hw_w, 0, hw_h, 0, 1);
+ glMatrixMode(GL_MODELVIEW);
+
+ // redraw the screen entirely...
+ glClearColor(0,0,0,1);
+ glClear(GL_COLOR_BUFFER_BIT);
+ const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
+ const size_t count = layers.size();
+ for (size_t i=0 ; i<count ; ++i) {
+ const sp<LayerBase>& layer(layers[i]);
+ layer->drawForSreenShot();
+ }
+
+ // XXX: this is needed on tegra
+ glScissor(0, 0, sw, sh);
+
+ // 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(
+ new MemoryHeapBase(size, 0, "screen-capture") );
+ void* const ptr = base->getBase();
+ if (ptr) {
+ // capture the screen with glReadPixels()
+ glReadPixels(0, 0, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, ptr);
+ if (glGetError() == GL_NO_ERROR) {
+ *heap = base;
+ *w = sw;
+ *h = sh;
+ *f = PIXEL_FORMAT_RGBA_8888;
+ result = NO_ERROR;
+ }
+ } else {
+ result = NO_MEMORY;
+ }
+ }
+
+ glEnable(GL_SCISSOR_TEST);
+ glViewport(0, 0, hw_w, hw_h);
+ 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);
+ return result;
+}
+
+
status_t SurfaceFlinger::captureScreen(DisplayID dpy,
sp<IMemoryHeap>* heap,
- uint32_t* width, uint32_t* height, PixelFormat* format)
+ uint32_t* width, uint32_t* height, PixelFormat* format,
+ uint32_t sw, uint32_t sh)
{
// only one display supported for now
if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
@@ -1564,12 +1672,15 @@ status_t SurfaceFlinger::captureScreen(DisplayID dpy,
uint32_t* w;
uint32_t* h;
PixelFormat* f;
+ uint32_t sw;
+ uint32_t sh;
status_t result;
public:
MessageCaptureScreen(SurfaceFlinger* flinger, DisplayID dpy,
- sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f)
+ sp<IMemoryHeap>* heap, uint32_t* w, uint32_t* h, PixelFormat* f,
+ uint32_t sw, uint32_t sh)
: flinger(flinger), dpy(dpy),
- heap(heap), w(w), h(h), f(f), result(PERMISSION_DENIED)
+ heap(heap), w(w), h(h), f(f), sw(sw), sh(sh), result(PERMISSION_DENIED)
{
}
status_t getResult() const {
@@ -1582,94 +1693,15 @@ status_t SurfaceFlinger::captureScreen(DisplayID dpy,
if (flinger->mSecureFrameBuffer)
return true;
- // make sure to clear all GL error flags
- while ( glGetError() != GL_NO_ERROR ) ;
-
- // get screen geometry
- const DisplayHardware& hw(flinger->graphicPlane(dpy).displayHardware());
- const uint32_t sw = hw.getWidth();
- const uint32_t sh = hw.getHeight();
- const Region screenBounds(hw.bounds());
- const size_t size = sw * sh * 4;
-
- // 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
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glOrthof(0, sw, 0, sh, 0, 1);
- glMatrixMode(GL_MODELVIEW);
-
- // redraw the screen entirely...
- glClearColor(0,0,0,1);
- glClear(GL_COLOR_BUFFER_BIT);
- const Vector< sp<LayerBase> >& layers(
- flinger->mVisibleLayersSortedByZ);
- const size_t count = layers.size();
- for (size_t i=0 ; i<count ; ++i) {
- const sp<LayerBase>& layer(layers[i]);
- if (!strcmp(layer->getTypeId(), "LayerBuffer")) {
- // we cannot render LayerBuffer because it doens't
- // use OpenGL, and won't show-up in the FBO.
- continue;
- }
- layer->draw(screenBounds);
- }
-
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
-
- // 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(
- new MemoryHeapBase(size, 0, "screen-capture") );
- void* const ptr = base->getBase();
- if (ptr) {
- // capture the screen with glReadPixels()
- glReadPixels(0, 0, sw, sh, GL_RGBA, GL_UNSIGNED_BYTE, ptr);
- if (glGetError() == GL_NO_ERROR) {
- *heap = base;
- *w = sw;
- *h = sh;
- *f = PIXEL_FORMAT_RGBA_8888;
- result = NO_ERROR;
- }
- } else {
- result = NO_MEMORY;
- }
- }
- } else {
- result = BAD_VALUE;
- }
+ result = flinger->captureScreenImplLocked(dpy,
+ heap, w, h, f, sw, sh);
- // release FBO resources
- glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
- glDeleteRenderbuffersOES(1, &tname);
- glDeleteFramebuffersOES(1, &name);
return true;
}
};
sp<MessageBase> msg = new MessageCaptureScreen(this,
- dpy, heap, width, height, format);
+ dpy, heap, width, height, format, sw, sh);
status_t res = postMessageSync(msg);
if (res == NO_ERROR) {
res = static_cast<MessageCaptureScreen*>( msg.get() )->getResult();