Merge "refactored screenshot code"
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 6ce5b86..bc5e10d 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -17,32 +17,21 @@
 #include <unistd.h>
 #include <fcntl.h>
 
-#include <utils/Log.h>
-
-#include <binder/IPCThreadState.h>
-#include <binder/ProcessState.h>
-#include <binder/IServiceManager.h>
-
 #include <binder/IMemory.h>
-#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
 
 using namespace android;
 
 int main(int argc, char** argv)
 {
-    const String16 name("SurfaceFlinger");
-    sp<ISurfaceComposer> composer;
-    if (getService(name, &composer) != NO_ERROR)
+    ScreenshotClient screenshot;
+    if (screenshot.update() != NO_ERROR)
         return 0;
 
-    sp<IMemoryHeap> heap;
-    uint32_t w, h;
-    PixelFormat f;
-    status_t err = composer->captureScreen(0, &heap, &w, &h, &f);
-    if (err != NO_ERROR)
-        return 0;
-
-    uint8_t* base = (uint8_t*)heap->getBase();
+    void const* base = screenshot.getPixels();
+    uint32_t w = screenshot.getWidth();
+    uint32_t h = screenshot.getHeight();
+    uint32_t f = screenshot.getFormat();
     int fd = dup(STDOUT_FILENO);
     write(fd, &w, 4);
     write(fd, &h, 4);
diff --git a/include/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index 76307b2..6533600 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -115,7 +115,8 @@
      */
     virtual status_t captureScreen(DisplayID dpy,
             sp<IMemoryHeap>* heap,
-            uint32_t* width, uint32_t* height, PixelFormat* format) = 0;
+            uint32_t* width, uint32_t* height, PixelFormat* format,
+            uint32_t reqWidth, uint32_t reqHeight) = 0;
 
     /* Signal surfaceflinger that there might be some work to do
      * This is an ASYNCHRONOUS call.
diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h
index 8773d71..a80832d 100644
--- a/include/surfaceflinger/SurfaceComposerClient.h
+++ b/include/surfaceflinger/SurfaceComposerClient.h
@@ -170,6 +170,36 @@
 };
 
 // ---------------------------------------------------------------------------
+
+class ScreenshotClient
+{
+    sp<IMemoryHeap> mHeap;
+    uint32_t mWidth;
+    uint32_t mHeight;
+    PixelFormat mFormat;
+public:
+    ScreenshotClient();
+
+    // frees the previous screenshot and capture a new one
+    status_t update();
+    status_t update(uint32_t reqWidth, uint32_t reqHeight);
+
+    // release memory occupied by the screenshot
+    void release();
+
+    // pixels are valid until this object is freed or
+    // release() or update() is called
+    void const* getPixels() const;
+
+    uint32_t getWidth() const;
+    uint32_t getHeight() const;
+    PixelFormat getFormat() const;
+    uint32_t getStride() const;
+    // size of allocated memory in bytes
+    size_t getSize() const;
+};
+
+// ---------------------------------------------------------------------------
 }; // namespace android
 
 #endif // ANDROID_SF_SURFACE_COMPOSER_CLIENT_H
diff --git a/libs/surfaceflinger_client/ISurfaceComposer.cpp b/libs/surfaceflinger_client/ISurfaceComposer.cpp
index 040060e..d676f5e 100644
--- a/libs/surfaceflinger_client/ISurfaceComposer.cpp
+++ b/libs/surfaceflinger_client/ISurfaceComposer.cpp
@@ -126,11 +126,14 @@
 
     virtual status_t captureScreen(DisplayID dpy,
             sp<IMemoryHeap>* heap,
-            uint32_t* width, uint32_t* height, PixelFormat* format)
+            uint32_t* width, uint32_t* height, PixelFormat* format,
+            uint32_t reqWidth, uint32_t reqHeight)
     {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
         data.writeInt32(dpy);
+        data.writeInt32(reqWidth);
+        data.writeInt32(reqHeight);
         remote()->transact(BnSurfaceComposer::CAPTURE_SCREEN, data, &reply);
         *heap = interface_cast<IMemoryHeap>(reply.readStrongBinder());
         *width = reply.readInt32();
@@ -208,10 +211,13 @@
         case CAPTURE_SCREEN: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             DisplayID dpy = data.readInt32();
+            uint32_t reqWidth = data.readInt32();
+            uint32_t reqHeight = data.readInt32();
             sp<IMemoryHeap> heap;
             uint32_t w, h;
             PixelFormat f;
-            status_t res = captureScreen(dpy, &heap, &w, &h, &f);
+            status_t res = captureScreen(dpy, &heap, &w, &h, &f,
+                    reqWidth, reqHeight);
             reply->writeStrongBinder(heap->asBinder());
             reply->writeInt32(w);
             reply->writeInt32(h);
diff --git a/libs/surfaceflinger_client/SurfaceComposerClient.cpp b/libs/surfaceflinger_client/SurfaceComposerClient.cpp
index 4096ac6..f270461 100644
--- a/libs/surfaceflinger_client/SurfaceComposerClient.cpp
+++ b/libs/surfaceflinger_client/SurfaceComposerClient.cpp
@@ -545,5 +545,55 @@
 }
 
 // ----------------------------------------------------------------------------
+
+ScreenshotClient::ScreenshotClient()
+    : mWidth(0), mHeight(0), mFormat(PIXEL_FORMAT_NONE) {
+}
+
+status_t ScreenshotClient::update() {
+    sp<ISurfaceComposer> s(ComposerService::getComposerService());
+    if (s == NULL) return NO_INIT;
+    mHeap = 0;
+    return s->captureScreen(0, &mHeap,
+            &mWidth, &mHeight, &mFormat, 0, 0);
+}
+
+status_t ScreenshotClient::update(uint32_t reqWidth, uint32_t reqHeight) {
+    sp<ISurfaceComposer> s(ComposerService::getComposerService());
+    if (s == NULL) return NO_INIT;
+    mHeap = 0;
+    return s->captureScreen(0, &mHeap,
+            &mWidth, &mHeight, &mFormat, reqWidth, reqHeight);
+}
+
+void ScreenshotClient::release() {
+    mHeap = 0;
+}
+
+void const* ScreenshotClient::getPixels() const {
+    return mHeap->getBase();
+}
+
+uint32_t ScreenshotClient::getWidth() const {
+    return mWidth;
+}
+
+uint32_t ScreenshotClient::getHeight() const {
+    return mHeight;
+}
+
+PixelFormat ScreenshotClient::getFormat() const {
+    return mFormat;
+}
+
+uint32_t ScreenshotClient::getStride() const {
+    return mWidth;
+}
+
+size_t ScreenshotClient::getSize() const {
+    return mHeap->getSize();
+}
+
+// ----------------------------------------------------------------------------
 }; // namespace android
 
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 1b21a8d..fb76720 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -271,6 +271,17 @@
     }
 }
 
+void Layer::drawForSreenShot() const
+{
+    bool currentFixedSize = mFixedSize;
+    bool currentBlending = mNeedsBlending;
+    const_cast<Layer*>(this)->mFixedSize = false;
+    const_cast<Layer*>(this)->mFixedSize = true;
+    LayerBase::drawForSreenShot();
+    const_cast<Layer*>(this)->mFixedSize = currentFixedSize;
+    const_cast<Layer*>(this)->mNeedsBlending = currentBlending;
+}
+
 void Layer::onDraw(const Region& clip) const
 {
     Texture tex(mBufferManager.getActiveTexture());
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 188da6a..caa6d17 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -70,6 +70,7 @@
     // LayerBase interface
     virtual void setGeometry(hwc_layer_t* hwcl);
     virtual void setPerFrameData(hwc_layer_t* hwcl);
+    virtual void drawForSreenShot() const;
     virtual void onDraw(const Region& clip) const;
     virtual uint32_t doTransaction(uint32_t transactionFlags);
     virtual void lockPageFlip(bool& recomputeVisibleRegions);
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 3d049a7..14191cb 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -326,6 +326,12 @@
     onDraw(clip);
 }
 
+void LayerBase::drawForSreenShot() const
+{
+    const DisplayHardware& hw(graphicPlane(0).displayHardware());
+    onDraw( Region(hw.bounds()) );
+}
+
 void LayerBase::clearWithOpenGL(const Region& clip, GLclampf red,
                                 GLclampf green, GLclampf blue,
                                 GLclampf alpha) const
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index c66dc34..bdee05b 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -121,6 +121,7 @@
      * to perform the actual drawing.  
      */
     virtual void draw(const Region& clip) const;
+    virtual void drawForSreenShot() const;
     
     /**
      * onDraw - draws the surface.
diff --git a/services/surfaceflinger/LayerBuffer.cpp b/services/surfaceflinger/LayerBuffer.cpp
index fdf9abc..c060895 100644
--- a/services/surfaceflinger/LayerBuffer.cpp
+++ b/services/surfaceflinger/LayerBuffer.cpp
@@ -132,6 +132,12 @@
     LayerBase::unlockPageFlip(planeTransform, outDirtyRegion);    
 }
 
+void LayerBuffer::drawForSreenShot() const
+{
+    const DisplayHardware& hw(graphicPlane(0).displayHardware());
+    clearWithOpenGL( Region(hw.bounds()) );
+}
+
 void LayerBuffer::onDraw(const Region& clip) const
 {
     sp<Source> source(getSource());
diff --git a/services/surfaceflinger/LayerBuffer.h b/services/surfaceflinger/LayerBuffer.h
index 1c0bf83..fece858 100644
--- a/services/surfaceflinger/LayerBuffer.h
+++ b/services/surfaceflinger/LayerBuffer.h
@@ -64,6 +64,7 @@
     virtual sp<LayerBaseClient::Surface> createSurface() const;
     virtual status_t ditch();
     virtual void onDraw(const Region& clip) const;
+    virtual void drawForSreenShot() const;
     virtual uint32_t doTransaction(uint32_t flags);
     virtual void unlockPageFlip(const Transform& planeTransform, Region& outDirtyRegion);
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 17b98a6..e6bdfd1 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1653,9 +1653,117 @@
 
 // ---------------------------------------------------------------------------
 
+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))
@@ -1671,12 +1779,15 @@
         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 {
@@ -1689,94 +1800,15 @@
             if (flinger->mSecureFrameBuffer)
                 return true;
 
-            // make sure to clear all GL error flags
-            while ( glGetError() != GL_NO_ERROR ) ;
+            result = flinger->captureScreenImplLocked(dpy,
+                    heap, w, h, f, sw, sh);
 
-            // 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;
-            }
-
-            // 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();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6e9ecbd..732e57e 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -197,7 +197,9 @@
                                                       sp<IMemoryHeap>* heap,
                                                       uint32_t* width,
                                                       uint32_t* height,
-                                                      PixelFormat* format);
+                                                      PixelFormat* format,
+                                                      uint32_t reqWidth,
+                                                      uint32_t reqHeight);
 
             void                        screenReleased(DisplayID dpy);
             void                        screenAcquired(DisplayID dpy);
@@ -319,6 +321,11 @@
             void        commitTransaction();
 
 
+            status_t captureScreenImplLocked(DisplayID dpy,
+                    sp<IMemoryHeap>* heap,
+                    uint32_t* width, uint32_t* height, PixelFormat* format,
+                    uint32_t reqWidth = 0, uint32_t reqHeight = 0);
+
             friend class FreezeLock;
             sp<FreezeLock> getFreezeLock() const;
             inline void incFreezeCount() {
diff --git a/services/surfaceflinger/tests/screencap/screencap.cpp b/services/surfaceflinger/tests/screencap/screencap.cpp
index 9e893f4..6cf1504 100644
--- a/services/surfaceflinger/tests/screencap/screencap.cpp
+++ b/services/surfaceflinger/tests/screencap/screencap.cpp
@@ -42,7 +42,7 @@
     sp<IMemoryHeap> heap;
     uint32_t w, h;
     PixelFormat f;
-    status_t err = composer->captureScreen(0, &heap, &w, &h, &f);
+    status_t err = composer->captureScreen(0, &heap, &w, &h, &f, 0, 0);
     if (err != NO_ERROR) {
         fprintf(stderr, "screen capture failed: %s\n", strerror(-err));
         exit(0);