Merge "Numberpicker section divider is now 2dp thick" into ics-mr1
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 27d863d..a8c7672 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -60,10 +60,16 @@
         virtual void onFrameAvailable() = 0;
     };
 
-    // tex indicates the name OpenGL texture to which images are to be streamed.
-    // This texture name cannot be changed once the SurfaceTexture is created.
+    // SurfaceTexture constructs a new SurfaceTexture object. tex indicates the
+    // name of the OpenGL ES texture to which images are to be streamed. This
+    // texture name cannot be changed once the SurfaceTexture is created.
+    // allowSynchronousMode specifies whether or not synchronous mode can be
+    // enabled. texTarget specifies the OpenGL ES texture target to which the
+    // texture will be bound in updateTexImage. useFenceSync specifies whether
+    // fences should be used to synchronize access to buffers if that behavior
+    // is enabled at compile-time.
     SurfaceTexture(GLuint tex, bool allowSynchronousMode = true,
-            GLenum texTarget = GL_TEXTURE_EXTERNAL_OES);
+            GLenum texTarget = GL_TEXTURE_EXTERNAL_OES, bool useFenceSync = true);
 
     virtual ~SurfaceTexture();
 
@@ -202,6 +208,10 @@
     // getCurrentScalingMode returns the scaling mode of the current buffer
     uint32_t getCurrentScalingMode() const;
 
+    // isSynchronousMode returns whether the SurfaceTexture is currently in
+    // synchronous mode.
+    bool isSynchronousMode() const;
+
     // abandon frees all the buffers and puts the SurfaceTexture into the
     // 'abandoned' state.  Once put in this state the SurfaceTexture can never
     // leave it.  When in the 'abandoned' state, all methods of the
@@ -272,7 +282,8 @@
               mTransform(0),
               mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
               mTimestamp(0),
-              mFrameNumber(0) {
+              mFrameNumber(0),
+              mFence(EGL_NO_SYNC_KHR) {
             mCrop.makeInvalid();
         }
 
@@ -345,6 +356,11 @@
         // mFrameNumber is the number of the queued frame for this slot.
         uint64_t mFrameNumber;
 
+        // mFence is the EGL sync object that must signal before the buffer
+        // associated with this buffer slot may be dequeued. It is initialized
+        // to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based
+        // on a compile-time option) set to a new sync object in updateTexImage.
+        EGLSyncKHR mFence;
     };
 
     // mSlots is the array of buffer slots that must be mirrored on the client
@@ -468,6 +484,12 @@
     // It is set by the setName method.
     String8 mName;
 
+    // mUseFenceSync indicates whether creation of the EGL_KHR_fence_sync
+    // extension should be used to prevent buffers from being dequeued before
+    // it's safe for them to be written. It gets set at construction time and
+    // never changes.
+    const bool mUseFenceSync;
+
     // mMutex is the mutex used to prevent concurrent access to the member
     // variables of SurfaceTexture objects. It must be locked whenever the
     // member variables are accessed.
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index 57f9e15..971a1b8 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -40,6 +40,7 @@
 
 protected:
     SurfaceTextureClient();
+    virtual ~SurfaceTextureClient();
     void setISurfaceTexture(const sp<ISurfaceTexture>& surfaceTexture);
 
 private:
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index b9deafc..6ab01f4 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -63,6 +63,7 @@
         USAGE_HW_RENDER         = GRALLOC_USAGE_HW_RENDER,
         USAGE_HW_2D             = GRALLOC_USAGE_HW_2D,
         USAGE_HW_COMPOSER       = GRALLOC_USAGE_HW_COMPOSER,
+        USAGE_HW_VIDEO_ENCODER  = GRALLOC_USAGE_HW_VIDEO_ENCODER,
         USAGE_HW_MASK           = GRALLOC_USAGE_HW_MASK
     };
 
diff --git a/include/ui/KeycodeLabels.h b/include/ui/KeycodeLabels.h
index 2efe8ca..c5bd0c5 100755
--- a/include/ui/KeycodeLabels.h
+++ b/include/ui/KeycodeLabels.h
@@ -231,6 +231,10 @@
     { "LANGUAGE_SWITCH", 204 },
     { "MANNER_MODE", 205 },
     { "3D_MODE", 206 },
+    { "CONTACTS", 207 },
+    { "CALENDAR", 208 },
+    { "MUSIC", 209 },
+    { "CALCULATOR", 210 },
 
     // NOTE: If you add a new keycode here you must also add it to several other files.
     //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 5ccf87f..5d34787 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -773,6 +773,7 @@
         bwr.read_buffer = (long unsigned int)mIn.data();
     } else {
         bwr.read_size = 0;
+        bwr.read_buffer = 0;
     }
 
     IF_LOG_COMMANDS() {
diff --git a/libs/gui/Android.mk b/libs/gui/Android.mk
index ed319f5..9767568 100644
--- a/libs/gui/Android.mk
+++ b/libs/gui/Android.mk
@@ -32,6 +32,10 @@
 
 LOCAL_MODULE:= libgui
 
+ifeq ($(TARGET_BOARD_PLATFORM), tegra)
+	LOCAL_CFLAGS += -DALLOW_DEQUEUE_CURRENT_BUFFER
+endif
+
 include $(BUILD_SHARED_LIBRARY)
 
 ifeq (,$(ONE_SHOT_MAKEFILE))
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 3c0d475..fcd287c 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -36,8 +36,28 @@
 #include <utils/Log.h>
 #include <utils/String8.h>
 
+// This compile option causes SurfaceTexture to return the buffer that is currently
+// attached to the GL texture from dequeueBuffer when no other buffers are
+// available.  It requires the drivers (Gralloc, GL, OMX IL, and Camera) to do
+// implicit cross-process synchronization to prevent the buffer from being
+// written to before the buffer has (a) been detached from the GL texture and
+// (b) all GL reads from the buffer have completed.
+#ifdef ALLOW_DEQUEUE_CURRENT_BUFFER
+#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER    true
+#warning "ALLOW_DEQUEUE_CURRENT_BUFFER enabled"
+#else
+#define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER    false
+#endif
 
-#define ALLOW_DEQUEUE_CURRENT_BUFFER    false
+// This compile option makes SurfaceTexture use the EGL_KHR_fence_sync extension
+// to synchronize access to the buffers.  It will cause dequeueBuffer to stall,
+// waiting for the GL reads for the buffer being dequeued to complete before
+// allowing the buffer to be dequeued.
+#ifdef USE_FENCE_SYNC
+#ifdef ALLOW_DEQUEUE_CURRENT_BUFFER
+#error "USE_FENCE_SYNC and ALLOW_DEQUEUE_CURRENT_BUFFER are incompatible"
+#endif
+#endif
 
 // Macros for including the SurfaceTexture name in log messages
 #define ST_LOGV(x, ...) LOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
@@ -95,7 +115,7 @@
 }
 
 SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
-        GLenum texTarget) :
+        GLenum texTarget, bool useFenceSync) :
     mDefaultWidth(1),
     mDefaultHeight(1),
     mPixelFormat(PIXEL_FORMAT_RGBA_8888),
@@ -112,6 +132,11 @@
     mAllowSynchronousMode(allowSynchronousMode),
     mConnectedApi(NO_CONNECTED_API),
     mAbandoned(false),
+#ifdef USE_FENCE_SYNC
+    mUseFenceSync(useFenceSync),
+#else
+    mUseFenceSync(false),
+#endif
     mTexTarget(texTarget),
     mFrameCounter(0) {
     // Choose a name using the PID and a process-unique ID.
@@ -257,190 +282,225 @@
         return BAD_VALUE;
     }
 
-    Mutex::Autolock lock(mMutex);
-
     status_t returnFlags(OK);
+    EGLDisplay dpy = EGL_NO_DISPLAY;
+    EGLSyncKHR fence = EGL_NO_SYNC_KHR;
 
-    int found = -1;
-    int foundSync = -1;
-    int dequeuedCount = 0;
-    bool tryAgain = true;
-    while (tryAgain) {
-        if (mAbandoned) {
-            ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
-            return NO_INIT;
-        }
+    { // Scope for the lock
+        Mutex::Autolock lock(mMutex);
 
-        // We need to wait for the FIFO to drain if the number of buffer
-        // needs to change.
-        //
-        // The condition "number of buffers needs to change" is true if
-        // - the client doesn't care about how many buffers there are
-        // - AND the actual number of buffer is different from what was
-        //   set in the last setBufferCountServer()
-        //                         - OR -
-        //   setBufferCountServer() was set to a value incompatible with
-        //   the synchronization mode (for instance because the sync mode
-        //   changed since)
-        //
-        // As long as this condition is true AND the FIFO is not empty, we
-        // wait on mDequeueCondition.
-
-        const int minBufferCountNeeded = mSynchronousMode ?
-                MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
-
-        const bool numberOfBuffersNeedsToChange = !mClientBufferCount &&
-                ((mServerBufferCount != mBufferCount) ||
-                        (mServerBufferCount < minBufferCountNeeded));
-
-        if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) {
-            // wait for the FIFO to drain
-            mDequeueCondition.wait(mMutex);
-            // NOTE: we continue here because we need to reevaluate our
-            // whole state (eg: we could be abandoned or disconnected)
-            continue;
-        }
-
-        if (numberOfBuffersNeedsToChange) {
-            // here we're guaranteed that mQueue is empty
-            freeAllBuffersLocked();
-            mBufferCount = mServerBufferCount;
-            if (mBufferCount < minBufferCountNeeded)
-                mBufferCount = minBufferCountNeeded;
-            mCurrentTexture = INVALID_BUFFER_SLOT;
-            returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
-        }
-
-        // look for a free buffer to give to the client
-        found = INVALID_BUFFER_SLOT;
-        foundSync = INVALID_BUFFER_SLOT;
-        dequeuedCount = 0;
-        for (int i = 0; i < mBufferCount; i++) {
-            const int state = mSlots[i].mBufferState;
-            if (state == BufferSlot::DEQUEUED) {
-                dequeuedCount++;
+        int found = -1;
+        int foundSync = -1;
+        int dequeuedCount = 0;
+        bool tryAgain = true;
+        while (tryAgain) {
+            if (mAbandoned) {
+                ST_LOGE("dequeueBuffer: SurfaceTexture has been abandoned!");
+                return NO_INIT;
             }
 
-            // if buffer is FREE it CANNOT be current
-            LOGW_IF((state == BufferSlot::FREE) && (mCurrentTexture==i),
-                    "dequeueBuffer: buffer %d is both FREE and current!", i);
+            // We need to wait for the FIFO to drain if the number of buffer
+            // needs to change.
+            //
+            // The condition "number of buffers needs to change" is true if
+            // - the client doesn't care about how many buffers there are
+            // - AND the actual number of buffer is different from what was
+            //   set in the last setBufferCountServer()
+            //                         - OR -
+            //   setBufferCountServer() was set to a value incompatible with
+            //   the synchronization mode (for instance because the sync mode
+            //   changed since)
+            //
+            // As long as this condition is true AND the FIFO is not empty, we
+            // wait on mDequeueCondition.
 
-            if (ALLOW_DEQUEUE_CURRENT_BUFFER) {
-                if (state == BufferSlot::FREE || i == mCurrentTexture) {
-                    foundSync = i;
-                    if (i != mCurrentTexture) {
-                        found = i;
-                        break;
-                    }
+            const int minBufferCountNeeded = mSynchronousMode ?
+                    MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS;
+
+            const bool numberOfBuffersNeedsToChange = !mClientBufferCount &&
+                    ((mServerBufferCount != mBufferCount) ||
+                            (mServerBufferCount < minBufferCountNeeded));
+
+            if (!mQueue.isEmpty() && numberOfBuffersNeedsToChange) {
+                // wait for the FIFO to drain
+                mDequeueCondition.wait(mMutex);
+                // NOTE: we continue here because we need to reevaluate our
+                // whole state (eg: we could be abandoned or disconnected)
+                continue;
+            }
+
+            if (numberOfBuffersNeedsToChange) {
+                // here we're guaranteed that mQueue is empty
+                freeAllBuffersLocked();
+                mBufferCount = mServerBufferCount;
+                if (mBufferCount < minBufferCountNeeded)
+                    mBufferCount = minBufferCountNeeded;
+                mCurrentTexture = INVALID_BUFFER_SLOT;
+                returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
+            }
+
+            // look for a free buffer to give to the client
+            found = INVALID_BUFFER_SLOT;
+            foundSync = INVALID_BUFFER_SLOT;
+            dequeuedCount = 0;
+            for (int i = 0; i < mBufferCount; i++) {
+                const int state = mSlots[i].mBufferState;
+                if (state == BufferSlot::DEQUEUED) {
+                    dequeuedCount++;
                 }
-            } else {
-                if (state == BufferSlot::FREE) {
-                    /** For Asynchronous mode, we need to return the oldest of free buffers
-                    * There is only one instance when the Framecounter overflows, this logic
-                    * might return the earlier buffer to client. Which is a negligible impact
-                    **/
-                    if (found < 0 || mSlots[i].mFrameNumber < mSlots[found].mFrameNumber) {
+
+                // if buffer is FREE it CANNOT be current
+                LOGW_IF((state == BufferSlot::FREE) && (mCurrentTexture==i),
+                        "dequeueBuffer: buffer %d is both FREE and current!",
+                        i);
+
+                if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER) {
+                    if (state == BufferSlot::FREE || i == mCurrentTexture) {
                         foundSync = i;
-                        found = i;
+                        if (i != mCurrentTexture) {
+                            found = i;
+                            break;
+                        }
+                    }
+                } else {
+                    if (state == BufferSlot::FREE) {
+                        /* We return the oldest of the free buffers to avoid
+                         * stalling the producer if possible.  This is because
+                         * the consumer may still have pending reads of the
+                         * buffers in flight.
+                         */
+                        bool isOlder = mSlots[i].mFrameNumber <
+                                mSlots[found].mFrameNumber;
+                        if (found < 0 || isOlder) {
+                            foundSync = i;
+                            found = i;
+                        }
                     }
                 }
             }
-        }
 
-        // clients are not allowed to dequeue more than one buffer
-        // if they didn't set a buffer count.
-        if (!mClientBufferCount && dequeuedCount) {
-            ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
-                    "setting the buffer count");
-            return -EINVAL;
-        }
+            // clients are not allowed to dequeue more than one buffer
+            // if they didn't set a buffer count.
+            if (!mClientBufferCount && dequeuedCount) {
+                ST_LOGE("dequeueBuffer: can't dequeue multiple buffers without "
+                        "setting the buffer count");
+                return -EINVAL;
+            }
 
-        // See whether a buffer has been queued since the last setBufferCount so
-        // we know whether to perform the MIN_UNDEQUEUED_BUFFERS check below.
-        bool bufferHasBeenQueued = mCurrentTexture != INVALID_BUFFER_SLOT;
-        if (bufferHasBeenQueued) {
-            // make sure the client is not trying to dequeue more buffers
-            // than allowed.
-            const int avail = mBufferCount - (dequeuedCount+1);
-            if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) {
-                ST_LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded "
-                        "(dequeued=%d)",
-                        MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode),
-                        dequeuedCount);
-                return -EBUSY;
+            // See whether a buffer has been queued since the last
+            // setBufferCount so we know whether to perform the
+            // MIN_UNDEQUEUED_BUFFERS check below.
+            bool bufferHasBeenQueued = mCurrentTexture != INVALID_BUFFER_SLOT;
+            if (bufferHasBeenQueued) {
+                // make sure the client is not trying to dequeue more buffers
+                // than allowed.
+                const int avail = mBufferCount - (dequeuedCount+1);
+                if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) {
+                    ST_LOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded "
+                            "(dequeued=%d)",
+                            MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode),
+                            dequeuedCount);
+                    return -EBUSY;
+                }
+            }
+
+            // we're in synchronous mode and didn't find a buffer, we need to
+            // wait for some buffers to be consumed
+            tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT);
+            if (tryAgain) {
+                mDequeueCondition.wait(mMutex);
             }
         }
 
-        // we're in synchronous mode and didn't find a buffer, we need to wait
-        // for some buffers to be consumed
-        tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT);
-        if (tryAgain) {
-            mDequeueCondition.wait(mMutex);
+        if (mSynchronousMode && found == INVALID_BUFFER_SLOT) {
+            // foundSync guaranteed to be != INVALID_BUFFER_SLOT
+            found = foundSync;
         }
-    }
 
-    if (mSynchronousMode && found == INVALID_BUFFER_SLOT) {
-        // foundSync guaranteed to be != INVALID_BUFFER_SLOT
-        found = foundSync;
-    }
-
-    if (found == INVALID_BUFFER_SLOT) {
-        // This should not happen.
-        ST_LOGE("dequeueBuffer: no available buffer slots");
-        return -EBUSY;
-    }
-
-    const int buf = found;
-    *outBuf = found;
-
-    const bool useDefaultSize = !w && !h;
-    if (useDefaultSize) {
-        // use the default size
-        w = mDefaultWidth;
-        h = mDefaultHeight;
-    }
-
-    const bool updateFormat = (format != 0);
-    if (!updateFormat) {
-        // keep the current (or default) format
-        format = mPixelFormat;
-    }
-
-    // buffer is now in DEQUEUED (but can also be current at the same time,
-    // if we're in synchronous mode)
-    mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
-
-    const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
-    if ((buffer == NULL) ||
-        (uint32_t(buffer->width)  != w) ||
-        (uint32_t(buffer->height) != h) ||
-        (uint32_t(buffer->format) != format) ||
-        ((uint32_t(buffer->usage) & usage) != usage))
-    {
-        usage |= GraphicBuffer::USAGE_HW_TEXTURE;
-        status_t error;
-        sp<GraphicBuffer> graphicBuffer(
-                mGraphicBufferAlloc->createGraphicBuffer(
-                        w, h, format, usage, &error));
-        if (graphicBuffer == 0) {
-            ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer "
-                    "failed");
-            return error;
+        if (found == INVALID_BUFFER_SLOT) {
+            // This should not happen.
+            ST_LOGE("dequeueBuffer: no available buffer slots");
+            return -EBUSY;
         }
-        if (updateFormat) {
-            mPixelFormat = format;
+
+        const int buf = found;
+        *outBuf = found;
+
+        const bool useDefaultSize = !w && !h;
+        if (useDefaultSize) {
+            // use the default size
+            w = mDefaultWidth;
+            h = mDefaultHeight;
         }
-        mSlots[buf].mGraphicBuffer = graphicBuffer;
-        mSlots[buf].mRequestBufferCalled = false;
-        if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
-            eglDestroyImageKHR(mSlots[buf].mEglDisplay, mSlots[buf].mEglImage);
-            mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
-            mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
+
+        const bool updateFormat = (format != 0);
+        if (!updateFormat) {
+            // keep the current (or default) format
+            format = mPixelFormat;
         }
-        returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
+
+        // buffer is now in DEQUEUED (but can also be current at the same time,
+        // if we're in synchronous mode)
+        mSlots[buf].mBufferState = BufferSlot::DEQUEUED;
+
+        const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer);
+        if ((buffer == NULL) ||
+            (uint32_t(buffer->width)  != w) ||
+            (uint32_t(buffer->height) != h) ||
+            (uint32_t(buffer->format) != format) ||
+            ((uint32_t(buffer->usage) & usage) != usage))
+        {
+            usage |= GraphicBuffer::USAGE_HW_TEXTURE;
+            status_t error;
+            sp<GraphicBuffer> graphicBuffer(
+                    mGraphicBufferAlloc->createGraphicBuffer(
+                            w, h, format, usage, &error));
+            if (graphicBuffer == 0) {
+                ST_LOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer "
+                        "failed");
+                return error;
+            }
+            if (updateFormat) {
+                mPixelFormat = format;
+            }
+            mSlots[buf].mGraphicBuffer = graphicBuffer;
+            mSlots[buf].mRequestBufferCalled = false;
+            mSlots[buf].mFence = EGL_NO_SYNC_KHR;
+            if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
+                eglDestroyImageKHR(mSlots[buf].mEglDisplay,
+                        mSlots[buf].mEglImage);
+                mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
+                mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
+            }
+            if (mCurrentTexture == buf) {
+                // The current texture no longer references the buffer in this slot
+                // since we just allocated a new buffer.
+                mCurrentTexture = INVALID_BUFFER_SLOT;
+            }
+            returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
+        }
+
+        dpy = mSlots[buf].mEglDisplay;
+        fence = mSlots[buf].mFence;
+        mSlots[buf].mFence = EGL_NO_SYNC_KHR;
     }
+
+    if (fence != EGL_NO_SYNC_KHR) {
+        EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
+        // If something goes wrong, log the error, but return the buffer without
+        // synchronizing access to it.  It's too late at this point to abort the
+        // dequeue operation.
+        if (result == EGL_FALSE) {
+            LOGE("dequeueBuffer: error waiting for fence: %#x", eglGetError());
+        } else if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+            LOGE("dequeueBuffer: timeout waiting for fence");
+        }
+        eglDestroySyncKHR(dpy, fence);
+    }
+
     ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", buf,
             mSlots[buf].mGraphicBuffer->handle, returnFlags);
+
     return returnFlags;
 }
 
@@ -637,8 +697,9 @@
     Mutex::Autolock lock(mMutex);
 
     if (mAbandoned) {
-        ST_LOGE("disconnect: SurfaceTexture has been abandoned!");
-        return NO_INIT;
+        // it is not really an error to disconnect after the surface
+        // has been abandoned, it should just be a no-op.
+        return NO_ERROR;
     }
 
     int err = NO_ERROR;
@@ -702,8 +763,8 @@
 
         // Update the GL texture object.
         EGLImageKHR image = mSlots[buf].mEglImage;
+        EGLDisplay dpy = eglGetCurrentDisplay();
         if (image == EGL_NO_IMAGE_KHR) {
-            EGLDisplay dpy = eglGetCurrentDisplay();
             if (mSlots[buf].mGraphicBuffer == 0) {
                 ST_LOGE("buffer at slot %d is null", buf);
                 return BAD_VALUE;
@@ -736,16 +797,32 @@
             return -EINVAL;
         }
 
-        ST_LOGV("updateTexImage: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture,
-                mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0, buf,
-                mSlots[buf].mGraphicBuffer->handle);
+        if (mCurrentTexture != INVALID_BUFFER_SLOT) {
+            if (mUseFenceSync) {
+                EGLSyncKHR fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR,
+                        NULL);
+                if (fence == EGL_NO_SYNC_KHR) {
+                    LOGE("updateTexImage: error creating fence: %#x",
+                            eglGetError());
+                    return -EINVAL;
+                }
+                glFlush();
+                mSlots[mCurrentTexture].mFence = fence;
+            }
+        }
+
+        ST_LOGV("updateTexImage: (slot=%d buf=%p) -> (slot=%d buf=%p)",
+                mCurrentTexture,
+                mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0,
+                buf, mSlots[buf].mGraphicBuffer->handle);
 
         if (mCurrentTexture != INVALID_BUFFER_SLOT) {
             // The current buffer becomes FREE if it was still in the queued
             // state. If it has already been given to the client
             // (synchronous mode), then it stays in DEQUEUED state.
-            if (mSlots[mCurrentTexture].mBufferState == BufferSlot::QUEUED)
+            if (mSlots[mCurrentTexture].mBufferState == BufferSlot::QUEUED) {
                 mSlots[mCurrentTexture].mBufferState = BufferSlot::FREE;
+            }
         }
 
         // Update the SurfaceTexture state.
@@ -1000,6 +1077,11 @@
     return mCurrentScalingMode;
 }
 
+bool SurfaceTexture::isSynchronousMode() const {
+    Mutex::Autolock lock(mMutex);
+    return mSynchronousMode;
+}
+
 int SurfaceTexture::query(int what, int* outValue)
 {
     Mutex::Autolock lock(mMutex);
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index 98fa171..48070d6 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -36,6 +36,12 @@
     SurfaceTextureClient::init();
 }
 
+SurfaceTextureClient::~SurfaceTextureClient() {
+    if (mConnectedToCpu) {
+        SurfaceTextureClient::disconnect(NATIVE_WINDOW_API_CPU);
+    }
+}
+
 void SurfaceTextureClient::init() {
     // Initialize the ANativeWindow function pointers.
     ANativeWindow::setSwapInterval  = hook_setSwapInterval;
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index 93ebfb9..c313904 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -396,7 +396,8 @@
             1.0f, 1.0f,
         };
 
-        glVertexAttribPointer(mPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, triangleVertices);
+        glVertexAttribPointer(mPositionHandle, 2, GL_FLOAT, GL_FALSE, 0,
+                triangleVertices);
         ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
         glEnableVertexAttribArray(mPositionHandle);
         ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
@@ -410,13 +411,17 @@
         // XXX: These calls are not needed for GL_TEXTURE_EXTERNAL_OES as
         // they're setting the defautls for that target, but when hacking things
         // to use GL_TEXTURE_2D they are needed to achieve the same behavior.
-        glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER,
+                GL_LINEAR);
         ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
-        glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+        glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER,
+                GL_LINEAR);
         ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
-        glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+        glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S,
+                GL_CLAMP_TO_EDGE);
         ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
-        glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+        glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T,
+                GL_CLAMP_TO_EDGE);
         ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
 
         GLfloat texMatrix[16];
@@ -531,6 +536,20 @@
     }
 }
 
+void fillRGBA8BufferSolid(uint8_t* buf, int w, int h, int stride, uint8_t r,
+        uint8_t g, uint8_t b, uint8_t a) {
+    const size_t PIXEL_SIZE = 4;
+    for (int y = 0; y < h; y++) {
+        for (int x = 0; x < h; x++) {
+            off_t offset = (y * stride + x) * PIXEL_SIZE;
+            buf[offset + 0] = r;
+            buf[offset + 1] = g;
+            buf[offset + 2] = b;
+            buf[offset + 3] = a;
+        }
+    }
+}
+
 TEST_F(SurfaceTextureGLTest, TexturingFromCpuFilledYV12BufferNpot) {
     const int texWidth = 64;
     const int texHeight = 66;
@@ -640,8 +659,8 @@
 
     for (int i = 0; i < 5; i++) {
         const android_native_rect_t& crop(crops[i]);
-        SCOPED_TRACE(String8::format("rect{ l: %d t: %d r: %d b: %d }", crop.left,
-                crop.top, crop.right, crop.bottom).string());
+        SCOPED_TRACE(String8::format("rect{ l: %d t: %d r: %d b: %d }",
+                crop.left, crop.top, crop.right, crop.bottom).string());
 
         ASSERT_EQ(NO_ERROR, native_window_set_crop(mANW.get(), &crop));
 
@@ -650,13 +669,15 @@
         ASSERT_TRUE(anb != NULL);
 
         sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
-        ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
+        ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(),
+                buf->getNativeBuffer()));
 
         uint8_t* img = NULL;
         buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
         fillYV12BufferRect(img, texWidth, texHeight, buf->getStride(), crop);
         buf->unlock();
-        ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
+        ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(),
+                buf->getNativeBuffer()));
 
         mST->updateTexImage();
 
@@ -708,7 +729,8 @@
 
     class ProducerThread : public Thread {
     public:
-        ProducerThread(const sp<ANativeWindow>& anw, const TestPixel* testPixels):
+        ProducerThread(const sp<ANativeWindow>& anw,
+                const TestPixel* testPixels):
                 mANW(anw),
                 mTestPixels(testPixels) {
         }
@@ -940,82 +962,6 @@
     EXPECT_TRUE(checkPixel( 3, 52,  35, 231,  35,  35));
 }
 
-TEST_F(SurfaceTextureGLTest, TexturingFromGLFilledRGBABufferPow2) {
-    const int texWidth = 64;
-    const int texHeight = 64;
-
-    mST->setDefaultBufferSize(texWidth, texHeight);
-
-    // Do the producer side of things
-    EGLSurface stcEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
-            mANW.get(), NULL);
-    ASSERT_EQ(EGL_SUCCESS, eglGetError());
-    ASSERT_NE(EGL_NO_SURFACE, stcEglSurface);
-
-    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, stcEglSurface, stcEglSurface,
-            mEglContext));
-    ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
-    glClearColor(0.6, 0.6, 0.6, 0.6);
-    glClear(GL_COLOR_BUFFER_BIT);
-
-    glEnable(GL_SCISSOR_TEST);
-    glScissor(4, 4, 4, 4);
-    glClearColor(1.0, 0.0, 0.0, 1.0);
-    glClear(GL_COLOR_BUFFER_BIT);
-
-    glScissor(24, 48, 4, 4);
-    glClearColor(0.0, 1.0, 0.0, 1.0);
-    glClear(GL_COLOR_BUFFER_BIT);
-
-    glScissor(37, 17, 4, 4);
-    glClearColor(0.0, 0.0, 1.0, 1.0);
-    glClear(GL_COLOR_BUFFER_BIT);
-
-    eglSwapBuffers(mEglDisplay, stcEglSurface);
-
-    // Do the consumer side of things
-    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
-            mEglContext));
-    ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
-    glDisable(GL_SCISSOR_TEST);
-
-    mST->updateTexImage();
-
-    // We must wait until updateTexImage has been called to destroy the
-    // EGLSurface because we're in synchronous mode.
-    eglDestroySurface(mEglDisplay, stcEglSurface);
-
-    glClearColor(0.2, 0.2, 0.2, 0.2);
-    glClear(GL_COLOR_BUFFER_BIT);
-
-    glViewport(0, 0, texWidth, texHeight);
-    drawTexture();
-
-    EXPECT_TRUE(checkPixel( 0,  0, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel(63,  0, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel(63, 63, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel( 0, 63, 153, 153, 153, 153));
-
-    EXPECT_TRUE(checkPixel( 4,  7, 255,   0,   0, 255));
-    EXPECT_TRUE(checkPixel(25, 51,   0, 255,   0, 255));
-    EXPECT_TRUE(checkPixel(40, 19,   0,   0, 255, 255));
-    EXPECT_TRUE(checkPixel(29, 51, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel( 5, 32, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel(13,  8, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel(46,  3, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel(30, 33, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel( 6, 52, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel(55, 33, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel(16, 29, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel( 1, 30, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel(41, 37, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel(46, 29, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel(15, 25, 153, 153, 153, 153));
-    EXPECT_TRUE(checkPixel( 3, 52, 153, 153, 153, 153));
-}
-
 TEST_F(SurfaceTextureGLTest, AbandonUnblocksDequeueBuffer) {
     class ProducerThread : public Thread {
     public:
@@ -1093,13 +1039,284 @@
             reinterpret_cast<ProducerThread*>(pt.get())->getDequeueError());
 }
 
+TEST_F(SurfaceTextureGLTest, InvalidWidthOrHeightFails) {
+    int texHeight = 16;
+    ANativeWindowBuffer* anb;
+
+    GLint maxTextureSize;
+    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
+
+    // make sure it works with small textures
+    mST->setDefaultBufferSize(16, texHeight);
+    EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+    EXPECT_EQ(16, anb->width);
+    EXPECT_EQ(texHeight, anb->height);
+    EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
+    EXPECT_EQ(NO_ERROR, mST->updateTexImage());
+
+    // make sure it works with GL_MAX_TEXTURE_SIZE
+    mST->setDefaultBufferSize(maxTextureSize, texHeight);
+    EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+    EXPECT_EQ(maxTextureSize, anb->width);
+    EXPECT_EQ(texHeight, anb->height);
+    EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
+    EXPECT_EQ(NO_ERROR, mST->updateTexImage());
+
+    // make sure it fails with GL_MAX_TEXTURE_SIZE+1
+    mST->setDefaultBufferSize(maxTextureSize+1, texHeight);
+    EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+    EXPECT_EQ(maxTextureSize+1, anb->width);
+    EXPECT_EQ(texHeight, anb->height);
+    EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
+    ASSERT_NE(NO_ERROR, mST->updateTexImage());
+}
+
 /*
- * This test is for testing GL -> GL texture streaming via SurfaceTexture.  It
- * contains functionality to create a producer thread that will perform GL
- * rendering to an ANativeWindow that feeds frames to a SurfaceTexture.
- * Additionally it supports interlocking the producer and consumer threads so
- * that a specific sequence of calls can be deterministically created by the
- * test.
+ * This test fixture is for testing GL -> GL texture streaming.  It creates an
+ * EGLSurface and an EGLContext for the image producer to use.
+ */
+class SurfaceTextureGLToGLTest : public SurfaceTextureGLTest {
+protected:
+    SurfaceTextureGLToGLTest():
+            mProducerEglSurface(EGL_NO_SURFACE),
+            mProducerEglContext(EGL_NO_CONTEXT) {
+    }
+
+    virtual void SetUp() {
+        SurfaceTextureGLTest::SetUp();
+
+        EGLConfig myConfig = {0};
+        EGLint numConfigs = 0;
+        EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &myConfig,
+                1, &numConfigs));
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+        mProducerEglSurface = eglCreateWindowSurface(mEglDisplay, myConfig,
+                mANW.get(), NULL);
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+        ASSERT_NE(EGL_NO_SURFACE, mProducerEglSurface);
+
+        mProducerEglContext = eglCreateContext(mEglDisplay, myConfig,
+                EGL_NO_CONTEXT, getContextAttribs());
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+        ASSERT_NE(EGL_NO_CONTEXT, mProducerEglContext);
+    }
+
+    virtual void TearDown() {
+        if (mProducerEglContext != EGL_NO_CONTEXT) {
+            eglDestroyContext(mEglDisplay, mProducerEglContext);
+        }
+        if (mProducerEglSurface != EGL_NO_SURFACE) {
+            eglDestroySurface(mEglDisplay, mProducerEglSurface);
+        }
+        SurfaceTextureGLTest::TearDown();
+    }
+
+    EGLSurface mProducerEglSurface;
+    EGLContext mProducerEglContext;
+};
+
+TEST_F(SurfaceTextureGLToGLTest, TexturingFromGLFilledRGBABufferPow2) {
+    const int texWidth = 64;
+    const int texHeight = 64;
+
+    mST->setDefaultBufferSize(texWidth, texHeight);
+
+    // Do the producer side of things
+    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
+            mProducerEglSurface, mProducerEglContext));
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+    // This is needed to ensure we pick up a buffer of the correct size.
+    eglSwapBuffers(mEglDisplay, mProducerEglSurface);
+
+    glClearColor(0.6, 0.6, 0.6, 0.6);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    glEnable(GL_SCISSOR_TEST);
+    glScissor(4, 4, 4, 4);
+    glClearColor(1.0, 0.0, 0.0, 1.0);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    glScissor(24, 48, 4, 4);
+    glClearColor(0.0, 1.0, 0.0, 1.0);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    glScissor(37, 17, 4, 4);
+    glClearColor(0.0, 0.0, 1.0, 1.0);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    eglSwapBuffers(mEglDisplay, mProducerEglSurface);
+
+    // Do the consumer side of things
+    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
+            mEglContext));
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+    glDisable(GL_SCISSOR_TEST);
+
+    mST->updateTexImage(); // Skip the first frame, which was empty
+    mST->updateTexImage();
+
+    glClearColor(0.2, 0.2, 0.2, 0.2);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    glViewport(0, 0, texWidth, texHeight);
+    drawTexture();
+
+    EXPECT_TRUE(checkPixel( 0,  0, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel(63,  0, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel(63, 63, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel( 0, 63, 153, 153, 153, 153));
+
+    EXPECT_TRUE(checkPixel( 4,  7, 255,   0,   0, 255));
+    EXPECT_TRUE(checkPixel(25, 51,   0, 255,   0, 255));
+    EXPECT_TRUE(checkPixel(40, 19,   0,   0, 255, 255));
+    EXPECT_TRUE(checkPixel(29, 51, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel( 5, 32, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel(13,  8, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel(46,  3, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel(30, 33, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel( 6, 52, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel(55, 33, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel(16, 29, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel( 1, 30, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel(41, 37, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel(46, 29, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel(15, 25, 153, 153, 153, 153));
+    EXPECT_TRUE(checkPixel( 3, 52, 153, 153, 153, 153));
+}
+
+TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceUnrefsBuffers) {
+    sp<GraphicBuffer> buffers[3];
+
+    // This test requires async mode to run on a single thread.
+    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
+            mProducerEglSurface, mProducerEglContext));
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    EXPECT_TRUE(eglSwapInterval(mEglDisplay, 0));
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+    for (int i = 0; i < 3; i++) {
+        // Produce a frame
+        EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
+                mProducerEglSurface, mProducerEglContext));
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+        glClear(GL_COLOR_BUFFER_BIT);
+        eglSwapBuffers(mEglDisplay, mProducerEglSurface);
+
+        // Consume a frame
+        EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
+                mEglContext));
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+        mST->updateTexImage();
+        buffers[i] = mST->getCurrentBuffer();
+    }
+
+    // Destroy the GL texture object to release its ref on buffers[2].
+    GLuint texID = TEX_ID;
+    glDeleteTextures(1, &texID);
+
+    // Destroy the EGLSurface
+    EXPECT_TRUE(eglDestroySurface(mEglDisplay, mProducerEglSurface));
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+    // Release the ref that the SurfaceTexture has on buffers[2].
+    mST->abandon();
+
+    EXPECT_EQ(1, buffers[0]->getStrongCount());
+    EXPECT_EQ(1, buffers[1]->getStrongCount());
+
+    // Depending on how lazily the GL driver dequeues buffers, we may end up
+    // with either two or three total buffers.  If there are three, make sure
+    // the last one was properly down-ref'd.
+    if (buffers[2] != buffers[0]) {
+        EXPECT_EQ(1, buffers[2]->getStrongCount());
+    }
+}
+
+TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) {
+    sp<GraphicBuffer> buffers[3];
+
+    // This test requires async mode to run on a single thread.
+    EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
+            mProducerEglSurface, mProducerEglContext));
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    EXPECT_TRUE(eglSwapInterval(mEglDisplay, 0));
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+    for (int i = 0; i < 3; i++) {
+        // Produce a frame
+        EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
+                mProducerEglSurface, mProducerEglContext));
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+        glClear(GL_COLOR_BUFFER_BIT);
+        EXPECT_TRUE(eglSwapBuffers(mEglDisplay, mProducerEglSurface));
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+        // Consume a frame
+        EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
+                mEglContext));
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+        ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+        buffers[i] = mST->getCurrentBuffer();
+    }
+
+    // Abandon the SurfaceTexture, releasing the ref that the SurfaceTexture has
+    // on buffers[2].
+    mST->abandon();
+
+    // Destroy the GL texture object to release its ref on buffers[2].
+    GLuint texID = TEX_ID;
+    glDeleteTextures(1, &texID);
+
+    // Destroy the EGLSurface.
+    EXPECT_TRUE(eglDestroySurface(mEglDisplay, mProducerEglSurface));
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+    EXPECT_EQ(1, buffers[0]->getStrongCount());
+    EXPECT_EQ(1, buffers[1]->getStrongCount());
+
+    // Depending on how lazily the GL driver dequeues buffers, we may end up
+    // with either two or three total buffers.  If there are three, make sure
+    // the last one was properly down-ref'd.
+    if (buffers[2] != buffers[0]) {
+        EXPECT_EQ(1, buffers[2]->getStrongCount());
+    }
+}
+
+TEST_F(SurfaceTextureGLToGLTest, EglSurfaceDefaultsToSynchronousMode) {
+    // This test requires 3 buffers to run on a single thread.
+    mST->setBufferCountServer(3);
+
+    ASSERT_TRUE(mST->isSynchronousMode());
+
+    for (int i = 0; i < 10; i++) {
+        // Produce a frame
+        EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
+                mProducerEglSurface, mProducerEglContext));
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+        glClear(GL_COLOR_BUFFER_BIT);
+        EXPECT_TRUE(eglSwapBuffers(mEglDisplay, mProducerEglSurface));
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+        // Consume a frame
+        EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
+                mEglContext));
+        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+        ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+    }
+
+    ASSERT_TRUE(mST->isSynchronousMode());
+}
+
+/*
+ * This test fixture is for testing GL -> GL texture streaming from one thread
+ * to another.  It contains functionality to create a producer thread that will
+ * perform GL rendering to an ANativeWindow that feeds frames to a
+ * SurfaceTexture.  Additionally it supports interlocking the producer and
+ * consumer threads so that a specific sequence of calls can be
+ * deterministically created by the test.
  *
  * The intended usage is as follows:
  *
@@ -1122,7 +1339,7 @@
  * }
  *
  */
-class SurfaceTextureGLToGLTest : public SurfaceTextureGLTest {
+class SurfaceTextureGLThreadToGLTest : public SurfaceTextureGLToGLTest {
 protected:
 
     // ProducerThread is an abstract base class to simplify the creation of
@@ -1223,30 +1440,8 @@
         Condition mFrameFinishCondition;
     };
 
-    SurfaceTextureGLToGLTest():
-            mProducerEglSurface(EGL_NO_SURFACE),
-            mProducerEglContext(EGL_NO_CONTEXT) {
-    }
-
     virtual void SetUp() {
-        SurfaceTextureGLTest::SetUp();
-
-        EGLConfig myConfig = {0};
-        EGLint numConfigs = 0;
-        EXPECT_TRUE(eglChooseConfig(mEglDisplay, getConfigAttribs(), &myConfig,
-                1, &numConfigs));
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
-        mProducerEglSurface = eglCreateWindowSurface(mEglDisplay, myConfig,
-                mANW.get(), NULL);
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-        ASSERT_NE(EGL_NO_SURFACE, mProducerEglSurface);
-
-        mProducerEglContext = eglCreateContext(mEglDisplay, myConfig,
-                EGL_NO_CONTEXT, getContextAttribs());
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-        ASSERT_NE(EGL_NO_CONTEXT, mProducerEglContext);
-
+        SurfaceTextureGLToGLTest::SetUp();
         mFC = new FrameCondition();
         mST->setFrameAvailableListener(mFC);
     }
@@ -1255,15 +1450,9 @@
         if (mProducerThread != NULL) {
             mProducerThread->requestExitAndWait();
         }
-        if (mProducerEglContext != EGL_NO_CONTEXT) {
-            eglDestroyContext(mEglDisplay, mProducerEglContext);
-        }
-        if (mProducerEglSurface != EGL_NO_SURFACE) {
-            eglDestroySurface(mEglDisplay, mProducerEglSurface);
-        }
         mProducerThread.clear();
         mFC.clear();
-        SurfaceTextureGLTest::TearDown();
+        SurfaceTextureGLToGLTest::TearDown();
     }
 
     void runProducerThread(const sp<ProducerThread> producerThread) {
@@ -1274,13 +1463,12 @@
         producerThread->run();
     }
 
-    EGLSurface mProducerEglSurface;
-    EGLContext mProducerEglContext;
     sp<ProducerThread> mProducerThread;
     sp<FrameCondition> mFC;
 };
 
-TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageBeforeFrameFinishedCompletes) {
+TEST_F(SurfaceTextureGLThreadToGLTest,
+        UpdateTexImageBeforeFrameFinishedCompletes) {
     class PT : public ProducerThread {
         virtual void render() {
             glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
@@ -1298,7 +1486,8 @@
     // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
 }
 
-TEST_F(SurfaceTextureGLToGLTest, UpdateTexImageAfterFrameFinishedCompletes) {
+TEST_F(SurfaceTextureGLThreadToGLTest,
+        UpdateTexImageAfterFrameFinishedCompletes) {
     class PT : public ProducerThread {
         virtual void render() {
             glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
@@ -1316,7 +1505,8 @@
     // TODO: Add frame verification once RGB TEX_EXTERNAL_OES is supported!
 }
 
-TEST_F(SurfaceTextureGLToGLTest, RepeatedUpdateTexImageBeforeFrameFinishedCompletes) {
+TEST_F(SurfaceTextureGLThreadToGLTest,
+        RepeatedUpdateTexImageBeforeFrameFinishedCompletes) {
     enum { NUM_ITERATIONS = 1024 };
 
     class PT : public ProducerThread {
@@ -1344,7 +1534,8 @@
     }
 }
 
-TEST_F(SurfaceTextureGLToGLTest, RepeatedUpdateTexImageAfterFrameFinishedCompletes) {
+TEST_F(SurfaceTextureGLThreadToGLTest,
+        RepeatedUpdateTexImageAfterFrameFinishedCompletes) {
     enum { NUM_ITERATIONS = 1024 };
 
     class PT : public ProducerThread {
@@ -1373,7 +1564,8 @@
 }
 
 // XXX: This test is disabled because it is currently hanging on some devices.
-TEST_F(SurfaceTextureGLToGLTest, DISABLED_RepeatedSwapBuffersWhileDequeueStalledCompletes) {
+TEST_F(SurfaceTextureGLThreadToGLTest,
+        DISABLED_RepeatedSwapBuffersWhileDequeueStalledCompletes) {
     enum { NUM_ITERATIONS = 64 };
 
     class PT : public ProducerThread {
@@ -1438,118 +1630,101 @@
     }
 }
 
-TEST_F(SurfaceTextureGLTest, EglDestroySurfaceUnrefsBuffers) {
-    EGLSurface stcEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
-            mANW.get(), NULL);
-    ASSERT_EQ(EGL_SUCCESS, eglGetError());
-    ASSERT_NE(EGL_NO_SURFACE, stcEglSurface);
+class SurfaceTextureFBOTest : public SurfaceTextureGLTest {
+protected:
 
-    sp<GraphicBuffer> buffers[3];
+    virtual void SetUp() {
+        SurfaceTextureGLTest::SetUp();
 
-    for (int i = 0; i < 3; i++) {
-        // Produce a frame
-        EXPECT_TRUE(eglMakeCurrent(mEglDisplay, stcEglSurface, stcEglSurface,
-                mEglContext));
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-        glClear(GL_COLOR_BUFFER_BIT);
-        eglSwapBuffers(mEglDisplay, stcEglSurface);
+        glGenFramebuffers(1, &mFbo);
+        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
 
-        // Consume a frame
-        EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
-                mEglContext));
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-        mST->updateTexImage();
-        buffers[i] = mST->getCurrentBuffer();
+        glGenTextures(1, &mFboTex);
+        glBindTexture(GL_TEXTURE_2D, mFboTex);
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getSurfaceWidth(),
+                getSurfaceHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+        glBindTexture(GL_TEXTURE_2D, 0);
+        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+
+        glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
+        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                GL_TEXTURE_2D, mFboTex, 0);
+        glBindFramebuffer(GL_FRAMEBUFFER, 0);
+        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
     }
 
-    // Destroy the GL texture object to release its ref on buffers[2].
-    GLuint texID = TEX_ID;
-    glDeleteTextures(1, &texID);
+    virtual void TearDown() {
+        SurfaceTextureGLTest::TearDown();
 
-    // Destroy the EGLSurface
-    EXPECT_TRUE(eglDestroySurface(mEglDisplay, stcEglSurface));
-    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+        glDeleteTextures(1, &mFboTex);
+        glDeleteFramebuffers(1, &mFbo);
+    }
 
-    // Release the ref that the SurfaceTexture has on buffers[2].
-    mST->abandon();
+    GLuint mFbo;
+    GLuint mFboTex;
+};
 
-    EXPECT_EQ(1, buffers[0]->getStrongCount());
-    EXPECT_EQ(1, buffers[1]->getStrongCount());
-    EXPECT_EQ(1, buffers[2]->getStrongCount());
-}
+// This test is intended to verify that proper synchronization is done when
+// rendering into an FBO.
+TEST_F(SurfaceTextureFBOTest, BlitFromCpuFilledBufferToFbo) {
+    const int texWidth = 64;
+    const int texHeight = 64;
 
-TEST_F(SurfaceTextureGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) {
-    EGLSurface stcEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
-            mANW.get(), NULL);
-    ASSERT_EQ(EGL_SUCCESS, eglGetError());
-    ASSERT_NE(EGL_NO_SURFACE, stcEglSurface);
+    ASSERT_EQ(NO_ERROR, native_window_set_buffers_geometry(mANW.get(),
+            texWidth, texHeight, HAL_PIXEL_FORMAT_RGBA_8888));
+    ASSERT_EQ(NO_ERROR, native_window_set_usage(mANW.get(),
+            GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN));
 
-    sp<GraphicBuffer> buffers[3];
+    android_native_buffer_t* anb;
+    ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+    ASSERT_TRUE(anb != NULL);
 
-    for (int i = 0; i < 3; i++) {
-        // Produce a frame
-        EXPECT_TRUE(eglMakeCurrent(mEglDisplay, stcEglSurface, stcEglSurface,
-                mEglContext));
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
-        glClear(GL_COLOR_BUFFER_BIT);
-        EXPECT_TRUE(eglSwapBuffers(mEglDisplay, stcEglSurface));
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+    ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
 
-        // Consume a frame
-        EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
-                mEglContext));
-        ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    // Fill the buffer with green
+    uint8_t* img = NULL;
+    buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+    fillRGBA8BufferSolid(img, texWidth, texHeight, buf->getStride(), 0, 255,
+            0, 255);
+    buf->unlock();
+    ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), buf->getNativeBuffer()));
+
+    ASSERT_EQ(NO_ERROR, mST->updateTexImage());
+
+    glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
+    drawTexture();
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+    for (int i = 0; i < 4; i++) {
+        SCOPED_TRACE(String8::format("frame %d", i).string());
+
+        ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+        ASSERT_TRUE(anb != NULL);
+
+        buf = new GraphicBuffer(anb, false);
+        ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(),
+                buf->getNativeBuffer()));
+
+        // Fill the buffer with red
+        ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN,
+                (void**)(&img)));
+        fillRGBA8BufferSolid(img, texWidth, texHeight, buf->getStride(), 255, 0,
+                0, 255);
+        ASSERT_EQ(NO_ERROR, buf->unlock());
+        ASSERT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(),
+                buf->getNativeBuffer()));
+
         ASSERT_EQ(NO_ERROR, mST->updateTexImage());
-        buffers[i] = mST->getCurrentBuffer();
+
+        drawTexture();
+
+        EXPECT_TRUE(checkPixel( 24, 39, 255, 0, 0, 255));
     }
 
-    // Abandon the SurfaceTexture, releasing the ref that the SurfaceTexture has
-    // on buffers[2].
-    mST->abandon();
+    glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
 
-    // Destroy the GL texture object to release its ref on buffers[2].
-    GLuint texID = TEX_ID;
-    glDeleteTextures(1, &texID);
-
-    // Destroy the EGLSurface.
-    EXPECT_TRUE(eglDestroySurface(mEglDisplay, stcEglSurface));
-    ASSERT_EQ(EGL_SUCCESS, eglGetError());
-
-    EXPECT_EQ(1, buffers[0]->getStrongCount());
-    EXPECT_EQ(1, buffers[1]->getStrongCount());
-    EXPECT_EQ(1, buffers[2]->getStrongCount());
-}
-
-TEST_F(SurfaceTextureGLTest, InvalidWidthOrHeightFails) {
-    int texHeight = 16;
-    ANativeWindowBuffer* anb;
-
-    GLint maxTextureSize;
-    glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
-
-    // make sure it works with small textures
-    mST->setDefaultBufferSize(16, texHeight);
-    EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
-    EXPECT_EQ(16, anb->width);
-    EXPECT_EQ(texHeight, anb->height);
-    EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
-    EXPECT_EQ(NO_ERROR, mST->updateTexImage());
-
-    // make sure it works with GL_MAX_TEXTURE_SIZE
-    mST->setDefaultBufferSize(maxTextureSize, texHeight);
-    EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
-    EXPECT_EQ(maxTextureSize, anb->width);
-    EXPECT_EQ(texHeight, anb->height);
-    EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
-    EXPECT_EQ(NO_ERROR, mST->updateTexImage());
-
-    // make sure it fails with GL_MAX_TEXTURE_SIZE+1
-    mST->setDefaultBufferSize(maxTextureSize+1, texHeight);
-    EXPECT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
-    EXPECT_EQ(maxTextureSize+1, anb->width);
-    EXPECT_EQ(texHeight, anb->height);
-    EXPECT_EQ(NO_ERROR, mANW->queueBuffer(mANW.get(), anb));
-    ASSERT_NE(NO_ERROR, mST->updateTexImage());
+    EXPECT_TRUE(checkPixel( 24, 39, 0, 255, 0, 255));
 }
 
 } // namespace android
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 5855b63..9c1a10e 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -44,10 +44,17 @@
   LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
 endif
 
+ifneq ($(MAX_EGL_CACHE_ENTRY_SIZE),)
+  LOCAL_CFLAGS += -DMAX_EGL_CACHE_ENTRY_SIZE=$(MAX_EGL_CACHE_ENTRY_SIZE)
+endif
+
+ifneq ($(MAX_EGL_CACHE_SIZE),)
+  LOCAL_CFLAGS += -DMAX_EGL_CACHE_SIZE=$(MAX_EGL_CACHE_SIZE)
+endif
+
 include $(BUILD_SHARED_LIBRARY)
 installed_libEGL := $(LOCAL_INSTALLED_MODULE)
 
-
 # OpenGL drivers config file
 ifneq ($(BOARD_EGL_CFG),)
 
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 2237eb6..2b0ed5d 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -49,6 +49,8 @@
 
 // ----------------------------------------------------------------------------
 
+#define EGL_VERSION_HW_ANDROID  0x3143
+
 struct extention_map_t {
     const char* name;
     __eglMustCastToProperFunctionPointerType address;
@@ -370,6 +372,11 @@
             }
         }
 
+        // the EGL spec requires that a new EGLSurface default to swap interval
+        // 1, so explicitly set that on the window here.
+        ANativeWindow* anw = reinterpret_cast<ANativeWindow*>(window);
+        anw->setSwapInterval(anw, 1);
+
         EGLSurface surface = cnx->egl.eglCreateWindowSurface(
                 iDpy, iConfig, window, attrib_list);
         if (surface != EGL_NO_SURFACE) {
@@ -967,6 +974,12 @@
             return dp->getExtensionString();
         case EGL_CLIENT_APIS:
             return dp->getClientApiString();
+        case EGL_VERSION_HW_ANDROID: {
+            if (gEGLImpl[IMPL_HARDWARE].dso) {
+                return dp->disp[IMPL_HARDWARE].queryString.version;
+            }
+            return dp->disp[IMPL_SOFTWARE].queryString.version;
+        }
     }
     return setError(EGL_BAD_PARAMETER, (const char *)0);
 }
diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp
index 13a4929..c4a7466 100644
--- a/opengl/libs/EGL/egl_cache.cpp
+++ b/opengl/libs/EGL/egl_cache.cpp
@@ -25,10 +25,18 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#ifndef MAX_EGL_CACHE_ENTRY_SIZE
+#define MAX_EGL_CACHE_ENTRY_SIZE (16 * 1024);
+#endif
+
+#ifndef MAX_EGL_CACHE_SIZE
+#define MAX_EGL_CACHE_SIZE (64 * 1024);
+#endif
+
 // Cache size limits.
 static const size_t maxKeySize = 1024;
-static const size_t maxValueSize = 4096;
-static const size_t maxTotalSize = 64 * 1024;
+static const size_t maxValueSize = MAX_EGL_CACHE_ENTRY_SIZE;
+static const size_t maxTotalSize = MAX_EGL_CACHE_SIZE;
 
 // Cache file header
 static const char* cacheFileMagic = "EGL$";
@@ -85,7 +93,7 @@
             bool atStart = !strncmp(BC_EXT_STR " ", exts, bcExtLen+1);
             bool atEnd = (bcExtLen+1) < extsLen &&
                     !strcmp(" " BC_EXT_STR, exts + extsLen - (bcExtLen+1));
-            bool inMiddle = strstr(" " BC_EXT_STR " ", exts);
+            bool inMiddle = strstr(exts, " " BC_EXT_STR " ");
             if (equal || atStart || atEnd || inMiddle) {
                 PFNEGLSETBLOBCACHEFUNCSANDROIDPROC eglSetBlobCacheFuncsANDROID;
                 eglSetBlobCacheFuncsANDROID =
diff --git a/opengl/specs/README b/opengl/specs/README
index 2fa2587..16b278f 100644
--- a/opengl/specs/README
+++ b/opengl/specs/README
@@ -9,4 +9,5 @@
 0x3140               EGL_ANDROID_image_native_buffer
 0x3141               (unused)
 0x3142               EGL_ANDROID_recordable
-0x3143 - 0x314F      (unused)
+0x3143               EGL_VERSION_HW_ANDROID (internal use)
+0x3144 - 0x314F      (unused)
diff --git a/opengl/tools/glgen/stubs/gles11/GLES11ExtHeader.java-if b/opengl/tools/glgen/stubs/gles11/GLES11ExtHeader.java-if
index c5e34cd..0c5fa04 100644
--- a/opengl/tools/glgen/stubs/gles11/GLES11ExtHeader.java-if
+++ b/opengl/tools/glgen/stubs/gles11/GLES11ExtHeader.java-if
@@ -124,6 +124,10 @@
     public static final int GL_TEXTURE_MAX_ANISOTROPY_EXT                           = 0x84FE;
     public static final int GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT                       = 0x84FF;
     public static final int GL_BGRA                                                 = 0x80E1;
+    public static final int GL_TEXTURE_EXTERNAL_OES                                 = 0x8D65;
+    public static final int GL_SAMPLER_EXTERNAL_OES                                 = 0x8D66;
+    public static final int GL_TEXTURE_BINDING_EXTERNAL_OES                         = 0x8D67;
+    public static final int GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES                     = 0x8D68;
 
     native private static void _nativeClassInit();
     static {
@@ -135,4 +139,4 @@
     private static final int GL_FLOAT = GLES10.GL_FLOAT;
     private static final int GL_SHORT = GLES10.GL_SHORT;
     
-    private static Buffer _matrixIndexPointerOES;
\ No newline at end of file
+    private static Buffer _matrixIndexPointerOES;
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 61a8358..f63c0c1 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -28,6 +28,7 @@
 endif
 ifeq ($(TARGET_BOARD_PLATFORM), s5pc110)
 	LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY -DNEVER_DEFAULT_TO_ASYNC_MODE
+	LOCAL_CFLAGS += -DREFRESH_RATE=56
 endif
 
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 1b00e93..24bd2a6 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -65,6 +65,8 @@
 #define AID_GRAPHICS 1003
 #endif
 
+#define EGL_VERSION_HW_ANDROID  0x3143
+
 #define DISPLAY_COUNT       1
 
 namespace android {
@@ -708,6 +710,14 @@
 
 void SurfaceFlinger::commitTransaction()
 {
+    if (!mLayersPendingRemoval.isEmpty()) {
+        // Notify removed layers now that they can't be drawn from
+        for (size_t i = 0; i < mLayersPendingRemoval.size(); i++) {
+            mLayersPendingRemoval[i]->onRemoved();
+        }
+        mLayersPendingRemoval.clear();
+    }
+
     mDrawingState = mCurrentState;
     mTransationPending = false;
     mTransactionCV.broadcast();
@@ -1160,7 +1170,7 @@
         mLayerPurgatory.add(layerBase);
     }
 
-    layerBase->onRemoved();
+    mLayersPendingRemoval.push(layerBase);
 
     // it's possible that we don't find a layer, because it might
     // have been destroyed already -- this is not technically an error
@@ -1527,7 +1537,7 @@
          * Dump the layers in the purgatory
          */
 
-        const size_t purgatorySize =  mLayerPurgatory.size();
+        const size_t purgatorySize = mLayerPurgatory.size();
         snprintf(buffer, SIZE, "Purgatory state (%d entries)\n", purgatorySize);
         result.append(buffer);
         for (size_t i=0 ; i<purgatorySize ; i++) {
@@ -1548,6 +1558,12 @@
                 extensions.getRenderer(),
                 extensions.getVersion());
         result.append(buffer);
+
+        snprintf(buffer, SIZE, "EGL : %s\n",
+                eglQueryString(graphicPlane(0).getEGLDisplay(),
+                        EGL_VERSION_HW_ANDROID));
+        result.append(buffer);
+
         snprintf(buffer, SIZE, "EXTS: %s\n", extensions.getExtension());
         result.append(buffer);
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 17028db..17b80a6 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -345,6 +345,7 @@
                 Condition               mTransactionCV;
                 SortedVector< sp<LayerBase> > mLayerPurgatory;
                 bool                    mTransationPending;
+                Vector< sp<LayerBase> > mLayersPendingRemoval;
 
                 // protected by mStateLock (but we could use another lock)
                 GraphicPlane                mGraphicPlanes[1];
diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp
index 4390ca1..5020e00 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.cpp
+++ b/services/surfaceflinger/SurfaceTextureLayer.cpp
@@ -28,7 +28,7 @@
 
 
 SurfaceTextureLayer::SurfaceTextureLayer(GLuint tex, const sp<Layer>& layer)
-    : SurfaceTexture(tex), mLayer(layer) {
+    : SurfaceTexture(tex, true, GL_TEXTURE_EXTERNAL_OES, false), mLayer(layer) {
 }
 
 SurfaceTextureLayer::~SurfaceTextureLayer() {