Merge "Support looper callbacks based on smart pointers." into jb-dev
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index f9cf0be..2635e2f 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -236,6 +236,19 @@
     static bool isExternalFormat(uint32_t format);
 
 private:
+    // this version of updateTexImage() takes a functor used to reject or not
+    // the newly acquired buffer.
+    // this API is TEMPORARY and intended to be used by SurfaceFlinger only,
+    // which is why class Layer is made a friend of SurfaceTexture below.
+    class BufferRejecter {
+        friend class SurfaceTexture;
+        virtual bool reject(const sp<GraphicBuffer>& buf,
+                const BufferQueue::BufferItem& item) = 0;
+    protected:
+        virtual ~BufferRejecter() { }
+    };
+    friend class Layer;
+    status_t updateTexImage(BufferRejecter* rejecter);
 
     // createImage creates a new EGLImage from a GraphicBuffer.
     EGLImageKHR createImage(EGLDisplay dpy,
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 30c0d9b..55be4bc 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -176,6 +176,10 @@
 }
 
 status_t SurfaceTexture::updateTexImage() {
+    return SurfaceTexture::updateTexImage(NULL);
+}
+
+status_t SurfaceTexture::updateTexImage(BufferRejecter* rejecter) {
     ATRACE_CALL();
     ST_LOGV("updateTexImage");
     Mutex::Autolock lock(mMutex);
@@ -228,6 +232,16 @@
             mEGLSlots[buf].mGraphicBuffer = item.mGraphicBuffer;
         }
 
+        // we call the rejecter here, in case the caller has a reason to
+        // not accept this buffer. this is used by SurfaceFlinger to
+        // reject buffers which have the wrong size
+        if (rejecter && rejecter->reject(mEGLSlots[buf].mGraphicBuffer, item)) {
+            mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence);
+            mEGLSlots[buf].mFence = EGL_NO_SYNC_KHR;
+            glBindTexture(mTexTarget, mTexName);
+            return NO_ERROR;
+        }
+
         // Update the GL texture object. We may have to do this even when
         // item.mGraphicBuffer == NULL, if we destroyed the EGLImage when
         // detaching from a context but the buffer has not been re-allocated.
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 6ec4f49..5e17d07 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -428,38 +428,51 @@
     const Layer::State& front(drawingState());
     const Layer::State& temp(currentState());
 
-    const bool sizeChanged = (front.requested.w != temp.requested.w) ||
-            (front.requested.h != temp.requested.h);
+    const bool sizeChanged = (temp.requested.w != front.active.w) ||
+                             (temp.requested.h != front.active.h);
 
     if (sizeChanged) {
         // the size changed, we need to ask our client to request a new buffer
         ALOGD_IF(DEBUG_RESIZE,
-                "doTransaction: "
-                "geometry (layer=%p), size: current (%dx%d), drawing (%dx%d), "
-                "crop: current (%d,%d,%d,%d [%dx%d]), drawing (%d,%d,%d,%d [%dx%d]), "
-                "scalingMode=%d",
-                this,
-                int(temp.requested.w), int(temp.requested.h),
-                int(front.requested.w), int(front.requested.h),
+                "doTransaction: geometry (layer=%p), scalingMode=%d\n"
+                "  current={ active   ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
+                "            requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n"
+                "  drawing={ active   ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
+                "            requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n",
+                this, mCurrentScalingMode,
+                temp.active.w, temp.active.h,
+                temp.active.crop.left,
+                temp.active.crop.top,
+                temp.active.crop.right,
+                temp.active.crop.bottom,
+                temp.active.crop.getWidth(),
+                temp.active.crop.getHeight(),
+                temp.requested.w, temp.requested.h,
                 temp.requested.crop.left,
                 temp.requested.crop.top,
                 temp.requested.crop.right,
                 temp.requested.crop.bottom,
                 temp.requested.crop.getWidth(),
                 temp.requested.crop.getHeight(),
+                front.active.w, front.active.h,
+                front.active.crop.left,
+                front.active.crop.top,
+                front.active.crop.right,
+                front.active.crop.bottom,
+                front.active.crop.getWidth(),
+                front.active.crop.getHeight(),
+                front.requested.w, front.requested.h,
                 front.requested.crop.left,
                 front.requested.crop.top,
                 front.requested.crop.right,
                 front.requested.crop.bottom,
                 front.requested.crop.getWidth(),
-                front.requested.crop.getHeight(),
-                mCurrentScalingMode);
+                front.requested.crop.getHeight());
 
         if (!isFixedSize()) {
             // this will make sure LayerBase::doTransaction doesn't update
             // the drawing state's geometry
-            Layer::State& editDraw(mDrawingState);
-            editDraw.requested = temp.requested;
+            flags |= eDontUpdateGeometryState;
         }
 
         // record the new size, form this point on, when the client request
@@ -514,7 +527,91 @@
             mFlinger->signalLayerUpdate();
         }
 
-        if (mSurfaceTexture->updateTexImage() < NO_ERROR) {
+        struct Reject : public SurfaceTexture::BufferRejecter {
+            Layer::State& front;
+            Layer::State& current;
+            bool& recomputeVisibleRegions;
+            Reject(Layer::State& front, Layer::State& current,
+                    bool& recomputeVisibleRegions)
+                : front(front), current(current),
+                  recomputeVisibleRegions(recomputeVisibleRegions) {
+            }
+
+            virtual bool reject(const sp<GraphicBuffer>& buf,
+                    const BufferQueue::BufferItem& item) {
+                if (buf == NULL) {
+                    return false;
+                }
+
+                uint32_t bufWidth  = buf->getWidth();
+                uint32_t bufHeight = buf->getHeight();
+
+                // check that we received a buffer of the right size
+                // (Take the buffer's orientation into account)
+                if (item.mTransform & Transform::ROT_90) {
+                    swap(bufWidth, bufHeight);
+                }
+
+
+                bool isFixedSize = item.mScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
+                if (front.active != front.requested) {
+
+                    if (isFixedSize ||
+                            (bufWidth == front.requested.w &&
+                             bufHeight == front.requested.h))
+                    {
+                        // Here we pretend the transaction happened by updating the
+                        // current and drawing states. Drawing state is only accessed
+                        // in this thread, no need to have it locked
+                        front.active = front.requested;
+
+                        // We also need to update the current state so that
+                        // we don't end-up overwriting the drawing state with
+                        // this stale current state during the next transaction
+                        //
+                        // NOTE: We don't need to hold the transaction lock here
+                        // because State::active is only accessed from this thread.
+                        current.active = front.active;
+
+                        // recompute visible region
+                        recomputeVisibleRegions = true;
+                    }
+
+                    ALOGD_IF(DEBUG_RESIZE,
+                            "lockPageFlip: (layer=%p), buffer (%ux%u, tr=%02x), scalingMode=%d\n"
+                            "  drawing={ active   ={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }\n"
+                            "            requested={ wh={%4u,%4u} crop={%4d,%4d,%4d,%4d} (%4d,%4d) }}\n",
+                            this, bufWidth, bufHeight, item.mTransform, item.mScalingMode,
+                            front.active.w, front.active.h,
+                            front.active.crop.left,
+                            front.active.crop.top,
+                            front.active.crop.right,
+                            front.active.crop.bottom,
+                            front.active.crop.getWidth(),
+                            front.active.crop.getHeight(),
+                            front.requested.w, front.requested.h,
+                            front.requested.crop.left,
+                            front.requested.crop.top,
+                            front.requested.crop.right,
+                            front.requested.crop.bottom,
+                            front.requested.crop.getWidth(),
+                            front.requested.crop.getHeight());
+                }
+
+                if (!isFixedSize) {
+                    if (front.active.w != bufWidth ||
+                        front.active.h != bufHeight) {
+                        return true;
+                    }
+                }
+                return false;
+            }
+        };
+
+
+        Reject r(mDrawingState, currentState(), recomputeVisibleRegions);
+
+        if (mSurfaceTexture->updateTexImage(&r) < NO_ERROR) {
             // something happened!
             recomputeVisibleRegions = true;
             return;
@@ -522,14 +619,18 @@
 
         // update the active buffer
         mActiveBuffer = mSurfaceTexture->getCurrentBuffer();
-        mFrameLatencyNeeded = true;
-
-        if (oldActiveBuffer == NULL && mActiveBuffer != NULL) {
-            // the first time we receive a buffer, we need to trigger a
-            // geometry invalidation.
-            mFlinger->invalidateHwcGeometry();
+        if (mActiveBuffer == NULL) {
+            // this can only happen if the very first buffer was rejected.
+            return;
         }
 
+        mFrameLatencyNeeded = true;
+        if (oldActiveBuffer == NULL) {
+             // the first time we receive a buffer, we need to trigger a
+             // geometry invalidation.
+             mFlinger->invalidateHwcGeometry();
+         }
+
         Rect crop(mSurfaceTexture->getCurrentCrop());
         const uint32_t transform(mSurfaceTexture->getCurrentTransform());
         const uint32_t scalingMode(mSurfaceTexture->getCurrentScalingMode());
@@ -543,9 +644,9 @@
             mFlinger->invalidateHwcGeometry();
         }
 
-        uint32_t bufWidth  = mActiveBuffer->getWidth();
-        uint32_t bufHeight = mActiveBuffer->getHeight();
         if (oldActiveBuffer != NULL) {
+            uint32_t bufWidth  = mActiveBuffer->getWidth();
+            uint32_t bufHeight = mActiveBuffer->getHeight();
             if (bufWidth != uint32_t(oldActiveBuffer->width) ||
                 bufHeight != uint32_t(oldActiveBuffer->height)) {
                 mFlinger->invalidateHwcGeometry();
@@ -557,52 +658,12 @@
             recomputeVisibleRegions = true;
         }
 
-        glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-        glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
-        // update the layer size if needed
-        const Layer::State& front(drawingState());
-
         // FIXME: mPostedDirtyRegion = dirty & bounds
+        const Layer::State& front(drawingState());
         mPostedDirtyRegion.set(front.active.w, front.active.h);
 
-        if (front.active != front.requested) {
-            // check that we received a buffer of the right size
-            // (Take the buffer's orientation into account)
-            if (mCurrentTransform & Transform::ROT_90) {
-                swap(bufWidth, bufHeight);
-            }
-
-            if (isFixedSize() ||
-                    (bufWidth == front.requested.w &&
-                    bufHeight == front.requested.h))
-            {
-                // Here we pretend the transaction happened by updating the
-                // current and drawing states. Drawing state is only accessed
-                // in this thread, no need to have it locked
-                Layer::State& editDraw(mDrawingState);
-                editDraw.active = editDraw.requested;
-
-                // We also need to update the current state so that we don't
-                // end-up doing too much work during the next transaction.
-                // NOTE: We actually don't need hold the transaction lock here
-                // because State::w and State::h are only accessed from
-                // this thread
-                Layer::State& editTemp(currentState());
-                editTemp.active = editDraw.active;
-
-                // recompute visible region
-                recomputeVisibleRegions = true;
-            }
-
-            ALOGD_IF(DEBUG_RESIZE,
-                    "lockPageFlip : "
-                    "       (layer=%p), buffer (%ux%u, tr=%02x), "
-                    "requested (%dx%d)",
-                    this,
-                    bufWidth, bufHeight, mCurrentTransform,
-                    front.requested.w, front.requested.h);
-        }
+        glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     }
 }
 
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 7c6a28a..16bac8f 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -201,12 +201,14 @@
     const Layer::State& front(drawingState());
     const Layer::State& temp(currentState());
 
-    if (front.requested != temp.requested)  {
-        // geometry of the layer has changed, set the active geometry
-        // to the requested geometry.
+    // always set active to requested, unless we're asked not to
+    // this is used by Layer, which special cases resizes.
+    if (flags & eDontUpdateGeometryState)  {
+    } else {
         Layer::State& editTemp(currentState());
         editTemp.active = temp.requested;
     }
+
     if (front.active != temp.active) {
         // invalidate and recompute the visible regions if needed
         flags |= Layer::eVisibleRegion;
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index 9542424..c547a40 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -227,7 +227,8 @@
 
 
     enum { // flags for doTransaction()
-        eVisibleRegion      = 0x00000002,
+        eDontUpdateGeometryState = 0x00000001,
+        eVisibleRegion           = 0x00000002,
     };