Merge "Added an EGLTest for eglTerminate"
diff --git a/include/binder/ProcessState.h b/include/binder/ProcessState.h
index 9725822..8caf1af 100644
--- a/include/binder/ProcessState.h
+++ b/include/binder/ProcessState.h
@@ -70,6 +70,8 @@
 
             void                spawnPooledThread(bool isMain);
             
+            status_t            setThreadPoolMaxThreadCount(size_t maxThreads);
+
 private:
     friend class IPCThreadState;
     
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index 1a0d779..3699cdf 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -257,6 +257,12 @@
     // before the outstanding accesses have completed.
     status_t syncForReleaseLocked(EGLDisplay dpy);
 
+    // The default consumer usage flags that SurfaceTexture always sets on its
+    // BufferQueue instance; these will be OR:d with any additional flags passed
+    // from the SurfaceTexture user. In particular, SurfaceTexture will always
+    // consume buffers as hardware textures.
+    static const uint32_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;
+
     // mCurrentTextureBuf is the graphic buffer of the current texture. It's
     // possible that this buffer is not associated with any buffer slot, so we
     // must track it separately in order to support the getCurrentBuffer method.
diff --git a/include/gui/SurfaceTextureClient.h b/include/gui/SurfaceTextureClient.h
index c0e90b3..6644751 100644
--- a/include/gui/SurfaceTextureClient.h
+++ b/include/gui/SurfaceTextureClient.h
@@ -26,6 +26,7 @@
 
 #include <utils/RefBase.h>
 #include <utils/threads.h>
+#include <utils/KeyedVector.h>
 
 struct ANativeWindow_Buffer;
 
@@ -113,6 +114,11 @@
     void freeAllBuffers();
     int getSlotFromBufferLocked(android_native_buffer_t* buffer) const;
 
+    struct BufferSlot {
+        sp<GraphicBuffer> buffer;
+        Region dirtyRegion;
+    };
+
     // mSurfaceTexture is the interface to the surface texture server. All
     // operations on the surface texture client ultimately translate into
     // interactions with the server using this interface.
@@ -124,7 +130,7 @@
     // slot that has not yet been used. The buffer allocated to a slot will also
     // be replaced if the requested buffer usage or geometry differs from that
     // of the buffer allocated to a slot.
-    sp<GraphicBuffer> mSlots[NUM_BUFFER_SLOTS];
+    BufferSlot mSlots[NUM_BUFFER_SLOTS];
 
     // mReqWidth is the buffer width that will be requested at the next dequeue
     // operation. It is initialized to 1.
@@ -189,8 +195,10 @@
     // must be used from the lock/unlock thread
     sp<GraphicBuffer>           mLockedBuffer;
     sp<GraphicBuffer>           mPostedBuffer;
-    mutable Region              mOldDirtyRegion;
     bool                        mConnectedToCpu;
+
+    // must be accessed from lock/unlock thread only
+    Region mDirtyRegion;
 };
 
 }; // namespace android
diff --git a/include/media/hardware/CryptoAPI.h b/include/media/hardware/CryptoAPI.h
index 81d9601..810a443 100644
--- a/include/media/hardware/CryptoAPI.h
+++ b/include/media/hardware/CryptoAPI.h
@@ -22,6 +22,7 @@
 
 namespace android {
 
+struct AString;
 struct CryptoPlugin;
 
 struct CryptoFactory {
@@ -63,6 +64,12 @@
     // media data of the given mime type.
     virtual bool requiresSecureDecoderComponent(const char *mime) const = 0;
 
+    // If the error returned falls into the range
+    // ERROR_DRM_VENDOR_MIN..ERROR_DRM_VENDOR_MAX, errorDetailMsg should be
+    // filled in with an appropriate string.
+    // At the java level these special errors will then trigger a
+    // MediaCodec.CryptoException that gives clients access to both
+    // the error code and the errorDetailMsg.
     virtual status_t decrypt(
             bool secure,
             const uint8_t key[16],
@@ -70,7 +77,8 @@
             Mode mode,
             const void *srcPtr,
             const SubSample *subSamples, size_t numSubSamples,
-            void *dstPtr) = 0;
+            void *dstPtr,
+            AString *errorDetailMsg) = 0;
 
 private:
     CryptoPlugin(const CryptoPlugin &);
diff --git a/include/private/ui/RegionHelper.h b/include/private/ui/RegionHelper.h
index 8d76533..421bdda 100644
--- a/include/private/ui/RegionHelper.h
+++ b/include/private/ui/RegionHelper.h
@@ -96,6 +96,11 @@
     class SpannerBase
     {
     public:
+        SpannerBase()
+            : lhs_head(max_value), lhs_tail(max_value),
+              rhs_head(max_value), rhs_tail(max_value) {
+        }
+
         enum {
             lhs_before_rhs   = 0,
             lhs_after_rhs    = 1,
@@ -158,12 +163,16 @@
 
     public:
         inline Spanner(const region& lhs, const region& rhs)
-            : lhs(lhs), rhs(rhs) 
+        : lhs(lhs), rhs(rhs)
         {
-            SpannerBase::lhs_head = lhs.rects->top      + lhs.dy;
-            SpannerBase::lhs_tail = lhs.rects->bottom   + lhs.dy;
-            SpannerBase::rhs_head = rhs.rects->top      + rhs.dy;
-            SpannerBase::rhs_tail = rhs.rects->bottom   + rhs.dy;
+            if (lhs.count) {
+                SpannerBase::lhs_head = lhs.rects->top      + lhs.dy;
+                SpannerBase::lhs_tail = lhs.rects->bottom   + lhs.dy;
+            }
+            if (rhs.count) {
+                SpannerBase::rhs_head = rhs.rects->top      + rhs.dy;
+                SpannerBase::rhs_tail = rhs.rects->bottom   + rhs.dy;
+            }
         }
 
         inline bool isDone() const {
@@ -221,20 +230,28 @@
 
         inline void prepare(int inside) {
             if (inside == SpannerBase::lhs_before_rhs) {
-                SpannerBase::lhs_head = lhs.rects->left  + lhs.dx;
-                SpannerBase::lhs_tail = lhs.rects->right + lhs.dx;
+                if (lhs.count) {
+                    SpannerBase::lhs_head = lhs.rects->left  + lhs.dx;
+                    SpannerBase::lhs_tail = lhs.rects->right + lhs.dx;
+                }
                 SpannerBase::rhs_head = max_value;
                 SpannerBase::rhs_tail = max_value;
             } else if (inside == SpannerBase::lhs_after_rhs) {
                 SpannerBase::lhs_head = max_value;
                 SpannerBase::lhs_tail = max_value;
-                SpannerBase::rhs_head = rhs.rects->left  + rhs.dx;
-                SpannerBase::rhs_tail = rhs.rects->right + rhs.dx;
+                if (rhs.count) {
+                    SpannerBase::rhs_head = rhs.rects->left  + rhs.dx;
+                    SpannerBase::rhs_tail = rhs.rects->right + rhs.dx;
+                }
             } else {
-                SpannerBase::lhs_head = lhs.rects->left  + lhs.dx;
-                SpannerBase::lhs_tail = lhs.rects->right + lhs.dx;
-                SpannerBase::rhs_head = rhs.rects->left  + rhs.dx;
-                SpannerBase::rhs_tail = rhs.rects->right + rhs.dx;
+                if (lhs.count) {
+                    SpannerBase::lhs_head = lhs.rects->left  + lhs.dx;
+                    SpannerBase::lhs_tail = lhs.rects->right + lhs.dx;
+                }
+                if (rhs.count) {
+                    SpannerBase::rhs_head = rhs.rects->left  + rhs.dx;
+                    SpannerBase::rhs_tail = rhs.rects->right + rhs.dx;
+                }
             }
         }
 
diff --git a/include/utils/Tokenizer.h b/include/utils/Tokenizer.h
index c7db5fb..bb25f37 100644
--- a/include/utils/Tokenizer.h
+++ b/include/utils/Tokenizer.h
@@ -28,7 +28,8 @@
  * A simple tokenizer for loading and parsing ASCII text files line by line.
  */
 class Tokenizer {
-    Tokenizer(const String8& filename, FileMap* fileMap, char* buffer, size_t length);
+    Tokenizer(const String8& filename, FileMap* fileMap, char* buffer,
+            bool ownBuffer, size_t length);
 
 public:
     ~Tokenizer();
@@ -42,6 +43,15 @@
     static status_t open(const String8& filename, Tokenizer** outTokenizer);
 
     /**
+     * Prepares to tokenize the contents of a string.
+     *
+     * Returns NO_ERROR and a tokenizer for the string, if successful.
+     * Otherwise returns an error and sets outTokenizer to NULL.
+     */
+    static status_t fromContents(const String8& filename,
+            const char* contents, Tokenizer** outTokenizer);
+
+    /**
      * Returns true if at the end of the file.
      */
     inline bool isEof() const { return mCurrent == getEnd(); }
@@ -111,6 +121,7 @@
     String8 mFilename;
     FileMap* mFileMap;
     char* mBuffer;
+    bool mOwnBuffer;
     size_t mLength;
 
     const char* mCurrent;
diff --git a/include/utils/Trace.h b/include/utils/Trace.h
index a2429c0..637c146 100644
--- a/include/utils/Trace.h
+++ b/include/utils/Trace.h
@@ -45,7 +45,8 @@
 #define ATRACE_TAG_GRAPHICS (1<<1)
 #define ATRACE_TAG_INPUT    (1<<2)
 #define ATRACE_TAG_VIEW     (1<<3)
-#define ATRACE_TAG_LAST     ATRACE_TAG_VIEW
+#define ATRACE_TAG_WEBVIEW  (1<<4)
+#define ATRACE_TAG_LAST     ATRACE_TAG_WEBVIEW
 
 #define ATRACE_TAG_VALID_MASK ((ATRACE_TAG_LAST - 1) | ATRACE_TAG_LAST)
 
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 9fa412c..d95fd6f 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -73,10 +73,11 @@
 
 sp<ProcessState> ProcessState::self()
 {
-    if (gProcess != NULL) return gProcess;
-    
-    AutoMutex _l(gProcessMutex);
-    if (gProcess == NULL) gProcess = new ProcessState;
+    Mutex::Autolock _l(gProcessMutex);
+    if (gProcess != NULL) {
+        return gProcess;
+    }
+    gProcess = new ProcessState;
     return gProcess;
 }
 
@@ -294,6 +295,15 @@
     }
 }
 
+status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) {
+    status_t result = NO_ERROR;
+    if (ioctl(mDriverFD, BINDER_SET_MAX_THREADS, &maxThreads) == -1) {
+        result = -errno;
+        ALOGE("Binder ioctl to set max threads failed: %s", strerror(-result));
+    }
+    return result;
+}
+
 static int open_driver()
 {
     int fd = open("/dev/binder", O_RDWR);
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 01d08b7..a6403d4 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -57,9 +57,12 @@
 #define ST_LOGE(x, ...) ALOGE("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
 
 #define ATRACE_BUFFER_INDEX(index)                                            \
-    char ___traceBuf[1024];                                                   \
-    snprintf(___traceBuf, 1024, "%s: %d", mConsumerName.string(), (index));   \
-    android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf);
+    if (ATRACE_ENABLED()) {                                                   \
+        char ___traceBuf[1024];                                               \
+        snprintf(___traceBuf, 1024, "%s: %d", mConsumerName.string(),         \
+                (index));                                                     \
+        android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf);           \
+    }
 
 namespace android {
 
@@ -447,7 +450,6 @@
             (uint32_t(buffer->format) != format) ||
             ((uint32_t(buffer->usage) & usage) != usage))
         {
-            usage |= GraphicBuffer::USAGE_HW_TEXTURE;
             status_t error;
             sp<GraphicBuffer> graphicBuffer(
                     mGraphicBufferAlloc->createGraphicBuffer(
@@ -531,8 +533,12 @@
     ATRACE_CALL();
     ATRACE_BUFFER_INDEX(buf);
 
-    ST_LOGV("queueBuffer: slot=%d time=%lld crop=[%d,%d,%d,%d]", buf, timestamp,
-        crop.left, crop.top, crop.right, crop.bottom);
+    ST_LOGV("queueBuffer: slot=%d time=%lld crop=[%d,%d,%d,%d]", buf,
+            mSlots[buf].mTimestamp,
+            mSlots[buf].mCrop.left,
+            mSlots[buf].mCrop.top,
+            mSlots[buf].mCrop.right,
+            mSlots[buf].mCrop.bottom);
 
     sp<ConsumerListener> listener;
 
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 0fa9ca1..a6e8dbf 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -150,6 +150,7 @@
                 strerror(-err), err);
     } else {
         mBufferQueue->setConsumerName(mName);
+        mBufferQueue->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
     }
 }
 
@@ -344,6 +345,18 @@
         glDeleteTextures(1, &mTexName);
     }
 
+    // Because we're giving up the EGLDisplay we need to free all the EGLImages
+    // that are associated with it.  They'll be recreated when the
+    // SurfaceTexture gets attached to a new OpenGL ES context (and thus gets a
+    // new EGLDisplay).
+    for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+        EGLImageKHR img = mEGLSlots[i].mEglImage;
+        if (img != EGL_NO_IMAGE_KHR) {
+            eglDestroyImageKHR(mEglDisplay, img);
+            mEGLSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
+        }
+    }
+
     mEglDisplay = EGL_NO_DISPLAY;
     mEglContext = EGL_NO_CONTEXT;
     mAttached = false;
@@ -542,28 +555,16 @@
         // decoder, camera, etc.) would simply not use a crop rectangle (or at
         // least not tell the framework about it) so that the GPU can do the
         // correct edge behavior.
-        int xshrink = 0, yshrink = 0;
-        if (mCurrentCrop.left > 0) {
-            tx = float(mCurrentCrop.left + 1) / float(buf->getWidth());
-            xshrink++;
-        } else {
-            tx = 0.0f;
-        }
-        if (mCurrentCrop.right < int32_t(buf->getWidth())) {
-            xshrink++;
-        }
-        if (mCurrentCrop.bottom < int32_t(buf->getHeight())) {
-            ty = (float(buf->getHeight() - mCurrentCrop.bottom) + 1.0f) /
-                    float(buf->getHeight());
-            yshrink++;
-        } else {
-            ty = 0.0f;
-        }
-        if (mCurrentCrop.top > 0) {
-            yshrink++;
-        }
-        sx = float(mCurrentCrop.width() - xshrink) / float(buf->getWidth());
-        sy = float(mCurrentCrop.height() - yshrink) / float(buf->getHeight());
+        const float shrinkAmount = 1.0f; // the amount that each edge is shrunk
+
+        tx = (float(mCurrentCrop.left) + shrinkAmount) /
+                float(buf->getWidth());
+        ty = (float(buf->getHeight() - mCurrentCrop.bottom) +
+                shrinkAmount) / float(buf->getHeight());
+        sx = (float(mCurrentCrop.width()) - (2.0f * shrinkAmount)) /
+                float(buf->getWidth());
+        sy = (float(mCurrentCrop.height()) - (2.0f * shrinkAmount)) /
+                float(buf->getHeight());
     } else {
         tx = 0.0f;
         ty = 0.0f;
@@ -680,13 +681,12 @@
     if (slotIndex == mCurrentTexture) {
         mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
     }
-    if (mEGLSlots[slotIndex].mEglImage != EGL_NO_IMAGE_KHR) {
-        EGLImageKHR img = mEGLSlots[slotIndex].mEglImage;
-        if (img != EGL_NO_IMAGE_KHR) {
-            eglDestroyImageKHR(mEglDisplay, img);
-        }
-        mEGLSlots[slotIndex].mEglImage = EGL_NO_IMAGE_KHR;
+    EGLImageKHR img = mEGLSlots[slotIndex].mEglImage;
+    if (img != EGL_NO_IMAGE_KHR) {
+        ST_LOGV("destroying EGLImage dpy=%p img=%p", mEglDisplay, img);
+        eglDestroyImageKHR(mEglDisplay, img);
     }
+    mEGLSlots[slotIndex].mEglImage = EGL_NO_IMAGE_KHR;
 }
 
 void SurfaceTexture::abandon() {
@@ -721,6 +721,7 @@
 
 status_t SurfaceTexture::setConsumerUsageBits(uint32_t usage) {
     Mutex::Autolock lock(mMutex);
+    usage |= DEFAULT_USAGE_FLAGS;
     return mBufferQueue->setConsumerUsageBits(usage);
 }
 
diff --git a/libs/gui/SurfaceTextureClient.cpp b/libs/gui/SurfaceTextureClient.cpp
index 99c025f..b37d821 100644
--- a/libs/gui/SurfaceTextureClient.cpp
+++ b/libs/gui/SurfaceTextureClient.cpp
@@ -171,7 +171,7 @@
              result);
         return result;
     }
-    sp<GraphicBuffer>& gbuf(mSlots[buf]);
+    sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
     if (result & ISurfaceTexture::RELEASE_ALL_BUFFERS) {
         freeAllBuffers();
     }
@@ -204,7 +204,8 @@
         android_native_buffer_t* buffer) const {
     bool dumpedState = false;
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
-        if (mSlots[i] != NULL && mSlots[i]->handle == buffer->handle) {
+        if (mSlots[i].buffer != NULL &&
+                mSlots[i].buffer->handle == buffer->handle) {
             return i;
         }
     }
@@ -586,7 +587,7 @@
 
 void SurfaceTextureClient::freeAllBuffers() {
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
-        mSlots[i] = 0;
+        mSlots[i].buffer = 0;
     }
 }
 
@@ -691,19 +692,32 @@
 
             if (canCopyBack) {
                 // copy the area that is invalid and not repainted this round
-                const Region copyback(mOldDirtyRegion.subtract(newDirtyRegion));
+                const Region copyback(mDirtyRegion.subtract(newDirtyRegion));
                 if (!copyback.isEmpty())
                     copyBlt(backBuffer, frontBuffer, copyback);
             } else {
                 // if we can't copy-back anything, modify the user's dirty
                 // region to make sure they redraw the whole buffer
                 newDirtyRegion.set(bounds);
+                mDirtyRegion.clear();
+                Mutex::Autolock lock(mMutex);
+                for (size_t i=0 ; i<NUM_BUFFER_SLOTS ; i++) {
+                    mSlots[i].dirtyRegion.clear();
+                }
             }
 
-            // keep track of the are of the buffer that is "clean"
-            // (ie: that will be redrawn)
-            mOldDirtyRegion = newDirtyRegion;
 
+            { // scope for the lock
+                Mutex::Autolock lock(mMutex);
+                int backBufferSlot(getSlotFromBufferLocked(backBuffer.get()));
+                if (backBufferSlot >= 0) {
+                    Region& dirtyRegion(mSlots[backBufferSlot].dirtyRegion);
+                    mDirtyRegion.subtract(dirtyRegion);
+                    dirtyRegion = newDirtyRegion;
+                }
+            }
+
+            mDirtyRegion.orSelf(newDirtyRegion);
             if (inOutDirtyBounds) {
                 *inOutDirtyBounds = newDirtyRegion.getBounds();
             }
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index aa1f94e..b576ca5 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -580,13 +580,13 @@
 
     // This accounts for the 1 texel shrink for each edge that's included in the
     // transform matrix to avoid texturing outside the crop region.
-    EXPECT_EQ(.5f, mtx[0]);
+    EXPECT_EQ(.375f, mtx[0]);
     EXPECT_EQ(0.f, mtx[1]);
     EXPECT_EQ(0.f, mtx[2]);
     EXPECT_EQ(0.f, mtx[3]);
 
     EXPECT_EQ(0.f, mtx[4]);
-    EXPECT_EQ(-.5f, mtx[5]);
+    EXPECT_EQ(-.375f, mtx[5]);
     EXPECT_EQ(0.f, mtx[6]);
     EXPECT_EQ(0.f, mtx[7]);
 
@@ -595,7 +595,7 @@
     EXPECT_EQ(1.f, mtx[10]);
     EXPECT_EQ(0.f, mtx[11]);
 
-    EXPECT_EQ(0.f, mtx[12]);
+    EXPECT_EQ(.125f, mtx[12]);
     EXPECT_EQ(.5f, mtx[13]);
     EXPECT_EQ(0.f, mtx[14]);
     EXPECT_EQ(1.f, mtx[15]);
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 6e2e731..2c7cdf0 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -619,7 +619,15 @@
 }
 
 Region::const_iterator Region::end() const {
-    return isRect() ? ((&mBounds) + 1) : (mStorage.array() + mStorage.size());
+    if (isRect()) {
+        if (isEmpty()) {
+            return &mBounds;
+        } else {
+            return &mBounds + 1;
+        }
+    } else {
+        return mStorage.array() + mStorage.size();
+    }
 }
 
 Rect const* Region::getArray(size_t* count) const {
diff --git a/libs/utils/Tokenizer.cpp b/libs/utils/Tokenizer.cpp
index efda2bf..7067533 100644
--- a/libs/utils/Tokenizer.cpp
+++ b/libs/utils/Tokenizer.cpp
@@ -35,15 +35,18 @@
     return strchr(delimiters, ch) != NULL;
 }
 
-Tokenizer::Tokenizer(const String8& filename, FileMap* fileMap, char* buffer, size_t length) :
+Tokenizer::Tokenizer(const String8& filename, FileMap* fileMap, char* buffer,
+        bool ownBuffer, size_t length) :
         mFilename(filename), mFileMap(fileMap),
-        mBuffer(buffer), mLength(length), mCurrent(buffer), mLineNumber(1) {
+        mBuffer(buffer), mOwnBuffer(ownBuffer), mLength(length),
+        mCurrent(buffer), mLineNumber(1) {
 }
 
 Tokenizer::~Tokenizer() {
     if (mFileMap) {
         mFileMap->release();
-    } else {
+    }
+    if (mOwnBuffer) {
         delete[] mBuffer;
     }
 }
@@ -65,6 +68,7 @@
             size_t length = size_t(stat.st_size);
 
             FileMap* fileMap = new FileMap();
+            bool ownBuffer = false;
             char* buffer;
             if (fileMap->create(NULL, fd, 0, length, true)) {
                 fileMap->advise(FileMap::SEQUENTIAL);
@@ -77,6 +81,7 @@
                 // The length we obtained from stat is wrong too (it will always be 4096)
                 // so we must trust that read will read the entire file.
                 buffer = new char[length];
+                ownBuffer = true;
                 ssize_t nrd = read(fd, buffer, length);
                 if (nrd < 0) {
                     result = -errno;
@@ -89,7 +94,7 @@
             }
 
             if (!result) {
-                *outTokenizer = new Tokenizer(filename, fileMap, buffer, length);
+                *outTokenizer = new Tokenizer(filename, fileMap, buffer, ownBuffer, length);
             }
         }
         close(fd);
@@ -97,6 +102,13 @@
     return result;
 }
 
+status_t Tokenizer::fromContents(const String8& filename,
+        const char* contents, Tokenizer** outTokenizer) {
+    *outTokenizer = new Tokenizer(filename, NULL,
+            const_cast<char*>(contents), false, strlen(contents));
+    return OK;
+}
+
 String8 Tokenizer::getLocation() const {
     String8 result;
     result.appendFormat("%s:%d", mFilename.string(), mLineNumber);
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 2e08f24..f2e3897 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -70,8 +70,7 @@
 egl_display_t egl_display_t::sDisplay[NUM_DISPLAYS];
 
 egl_display_t::egl_display_t() :
-    magic('_dpy'), finishOnSwap(false), traceGpuCompletion(false), refs(0),
-    mWakeCount(0), mHibernating(false), mAttemptHibernation(false) {
+    magic('_dpy'), finishOnSwap(false), traceGpuCompletion(false), refs(0) {
 }
 
 egl_display_t::~egl_display_t() {
@@ -253,6 +252,9 @@
         *major = VERSION_MAJOR;
     if (minor != NULL)
         *minor = VERSION_MINOR;
+
+    mHibernation.setDisplayValid(true);
+
     return EGL_TRUE;
 }
 
@@ -282,6 +284,8 @@
         res = EGL_TRUE;
     }
 
+    mHibernation.setDisplayValid(false);
+
     // Mark all objects remaining in the list as terminated, unless
     // there are no reference to them, it which case, we're free to
     // delete them.
@@ -351,8 +355,7 @@
             if (result == EGL_TRUE) {
                 c->onMakeCurrent(draw, read);
                 if (!cur_c) {
-                    mWakeCount++;
-                    mAttemptHibernation = false;
+                    mHibernation.incWakeCount(HibernationMachine::STRONG);
                 }
             }
         } else {
@@ -360,8 +363,7 @@
                     disp.dpy, impl_draw, impl_read, impl_ctx);
             if (result == EGL_TRUE) {
                 cur_c->onLooseCurrent();
-                mWakeCount--;
-                mAttemptHibernation = true;
+                mHibernation.decWakeCount(HibernationMachine::STRONG);
             }
         }
     }
@@ -378,14 +380,26 @@
     return result;
 }
 
-bool egl_display_t::enter() {
-    Mutex::Autolock _l(lock);
+// ----------------------------------------------------------------------------
+
+bool egl_display_t::HibernationMachine::incWakeCount(WakeRefStrength strength) {
+    Mutex::Autolock _l(mLock);
     ALOGE_IF(mWakeCount < 0 || mWakeCount == INT32_MAX,
              "Invalid WakeCount (%d) on enter\n", mWakeCount);
+
     mWakeCount++;
+    if (strength == STRONG)
+        mAttemptHibernation = false;
+
     if (CC_UNLIKELY(mHibernating)) {
         ALOGV("Awakening\n");
         egl_connection_t* const cnx = &gEGLImpl;
+
+        // These conditions should be guaranteed before entering hibernation;
+        // we don't want to get into a state where we can't wake up.
+        ALOGD_IF(!mDpyValid || !cnx->egl.eglAwakenProcessIMG,
+                 "Invalid hibernation state, unable to awaken\n");
+
         if (!cnx->egl.eglAwakenProcessIMG()) {
             ALOGE("Failed to awaken EGL implementation\n");
             return false;
@@ -395,13 +409,20 @@
     return true;
 }
 
-void egl_display_t::leave() {
-    Mutex::Autolock _l(lock);
+void egl_display_t::HibernationMachine::decWakeCount(WakeRefStrength strength) {
+    Mutex::Autolock _l(mLock);
     ALOGE_IF(mWakeCount <= 0, "Invalid WakeCount (%d) on leave\n", mWakeCount);
-    if (--mWakeCount == 0 && CC_UNLIKELY(mAttemptHibernation)) {
+
+    mWakeCount--;
+    if (strength == STRONG)
+        mAttemptHibernation = true;
+
+    if (mWakeCount == 0 && CC_UNLIKELY(mAttemptHibernation)) {
         egl_connection_t* const cnx = &gEGLImpl;
         mAttemptHibernation = false;
-        if (cnx->egl.eglHibernateProcessIMG && cnx->egl.eglAwakenProcessIMG) {
+        if (mDpyValid &&
+                cnx->egl.eglHibernateProcessIMG &&
+                cnx->egl.eglAwakenProcessIMG) {
             ALOGV("Hibernating\n");
             if (!cnx->egl.eglHibernateProcessIMG()) {
                 ALOGE("Failed to hibernate EGL implementation\n");
@@ -412,16 +433,9 @@
     }
 }
 
-void egl_display_t::onWindowSurfaceCreated() {
-    Mutex::Autolock _l(lock);
-    mWakeCount++;
-    mAttemptHibernation = false;
-}
-
-void egl_display_t::onWindowSurfaceDestroyed() {
-    Mutex::Autolock _l(lock);
-    mWakeCount--;
-    mAttemptHibernation = true;
+void egl_display_t::HibernationMachine::setDisplayValid(bool valid) {
+    Mutex::Autolock _l(mLock);
+    mDpyValid = valid;
 }
 
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index 28607da..412568b 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -77,8 +77,12 @@
     // proper hibernate/wakeup sequencing. If a surface destruction triggers
     // hibernation, hibernation will be delayed at least until the calling
     // thread's egl_display_ptr is destroyed.
-    void onWindowSurfaceCreated();
-    void onWindowSurfaceDestroyed();
+    void onWindowSurfaceCreated() {
+        mHibernation.incWakeCount(HibernationMachine::STRONG);
+    }
+    void onWindowSurfaceDestroyed() {
+        mHibernation.decWakeCount(HibernationMachine::STRONG);
+    }
 
     static egl_display_t* get(EGLDisplay dpy);
     static EGLDisplay getFromNativeDisplay(EGLNativeDisplayType disp);
@@ -123,8 +127,8 @@
 
 private:
     friend class egl_display_ptr;
-    bool enter();
-    void leave();
+    bool enter() { return mHibernation.incWakeCount(HibernationMachine::WEAK); }
+    void leave() { return mHibernation.decWakeCount(HibernationMachine::WEAK); }
 
             uint32_t                    refs;
     mutable Mutex                       lock;
@@ -133,9 +137,41 @@
             String8 mVersionString;
             String8 mClientApiString;
             String8 mExtensionString;
-            int32_t mWakeCount;
-            bool    mHibernating;
-            bool    mAttemptHibernation;
+
+    // HibernationMachine uses its own internal mutex to protect its own data.
+    // The owning egl_display_t's lock may be but is not required to be held
+    // when calling HibernationMachine methods. As a result, nothing in this
+    // class may call back up to egl_display_t directly or indirectly.
+    class HibernationMachine {
+    public:
+        // STRONG refs cancel (inc) or initiate (dec) a hibernation attempt
+        // the next time the wakecount reaches zero. WEAK refs don't affect
+        // whether a hibernation attempt will be made. Use STRONG refs only
+        // for infrequent/heavy changes that are likely to indicate the
+        // EGLDisplay is entering or leaving a long-term idle state.
+        enum WakeRefStrength {
+            WEAK   = 0,
+            STRONG = 1,
+        };
+
+        HibernationMachine(): mWakeCount(0), mHibernating(false),
+                mAttemptHibernation(false), mDpyValid(false)
+        {}
+        ~HibernationMachine() {}
+
+        bool incWakeCount(WakeRefStrength strenth);
+        void decWakeCount(WakeRefStrength strenth);
+
+        void setDisplayValid(bool valid);
+
+    private:
+        Mutex   mLock;
+        int32_t mWakeCount;
+        bool    mHibernating;
+        bool    mAttemptHibernation;
+        bool    mDpyValid;
+    };
+    HibernationMachine mHibernation;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index c46e630..48651b6 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -280,12 +280,6 @@
                 EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED);
     }
 
-    if (eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &dummy) == EGL_TRUE) {
-        if (dummy == EGL_BUFFER_PRESERVED) {
-            mFlags |= BUFFER_PRESERVED;
-        }
-    }
-
     /*
      * Create our OpenGL ES context
      */
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index 84a3eff..f1dee91 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -51,7 +51,6 @@
 
     enum {
         COPY_BITS_EXTENSION         = 0x00000008,
-        BUFFER_PRESERVED            = 0x00010000,
         PARTIAL_UPDATES             = 0x00020000,   // video driver feature
         SLOW_CONFIG                 = 0x00040000,   // software
         SWAP_RECTANGLE              = 0x00080000,
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index e764001..694ecde 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -43,7 +43,7 @@
     : dpy(display), contentDirty(false),
       sequence(uint32_t(android_atomic_inc(&sSequence))),
       mFlinger(flinger), mFiltering(false),
-      mNeedsFiltering(false), mInOverlay(false),
+      mNeedsFiltering(false),
       mOrientation(0),
       mPlaneOrientation(0),
       mTransactionFlags(0),
@@ -231,7 +231,9 @@
     const uint32_t hw_h = hw.getHeight();
 
     uint32_t w = s.w;
-    uint32_t h = s.h;    
+    uint32_t h = s.h;
+
+    mNumVertices = 4;
     tr.transform(mVertices[0], 0, 0);
     tr.transform(mVertices[1], 0, h);
     tr.transform(mVertices[2], w, h);
@@ -268,27 +270,6 @@
         const Transform& planeTransform, Region& outDirtyRegion) {
 }
 
-void LayerBase::drawRegion(const Region& reg) const
-{
-    Region::const_iterator it = reg.begin();
-    Region::const_iterator const end = reg.end();
-    if (it != end) {
-        Rect r;
-        const DisplayHardware& hw(graphicPlane(0).displayHardware());
-        const int32_t fbWidth  = hw.getWidth();
-        const int32_t fbHeight = hw.getHeight();
-        const GLshort vertices[][2] = { { 0, 0 }, { fbWidth, 0 }, 
-                { fbWidth, fbHeight }, { 0, fbHeight }  };
-        glVertexPointer(2, GL_SHORT, 0, vertices);
-        while (it != end) {
-            const Rect& r = *it++;
-            const GLint sy = fbHeight - (r.top + r.height());
-            glScissor(r.left, sy, r.width(), r.height());
-            glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 
-        }
-    }
-}
-
 void LayerBase::setGeometry(hwc_layer_t* hwcl)
 {
     hwcl->compositionType = HWC_FRAMEBUFFER;
@@ -333,14 +314,6 @@
     hwcl->handle = NULL;
 }
 
-void LayerBase::setOverlay(bool inOverlay) {
-    mInOverlay = inOverlay;
-}
-
-bool LayerBase::isOverlay() const {
-    return mInOverlay;
-}
-
 void LayerBase::setFiltering(bool filtering)
 {
     mFiltering = filtering;
@@ -353,9 +326,6 @@
 
 void LayerBase::draw(const Region& clip) const
 {
-    // reset GL state
-    glEnable(GL_SCISSOR_TEST);
-
     onDraw(clip);
 }
 
@@ -379,16 +349,8 @@
     glDisable(GL_TEXTURE_2D);
     glDisable(GL_BLEND);
 
-    Region::const_iterator it = clip.begin();
-    Region::const_iterator const end = clip.end();
-    glEnable(GL_SCISSOR_TEST);
     glVertexPointer(2, GL_FLOAT, 0, mVertices);
-    while (it != end) {
-        const Rect& r = *it++;
-        const GLint sy = fbHeight - (r.top + r.height());
-        glScissor(r.left, sy, r.width(), r.height());
-        glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 
-    }
+    glDrawArrays(GL_TRIANGLE_FAN, 0, mNumVertices);
 }
 
 void LayerBase::clearWithOpenGL(const Region& clip) const
@@ -442,15 +404,8 @@
     glEnableClientState(GL_TEXTURE_COORD_ARRAY);
     glVertexPointer(2, GL_FLOAT, 0, mVertices);
     glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+    glDrawArrays(GL_TRIANGLE_FAN, 0, mNumVertices);
 
-    Region::const_iterator it = clip.begin();
-    Region::const_iterator const end = clip.end();
-    while (it != end) {
-        const Rect& r = *it++;
-        const GLint sy = fbHeight - (r.top + r.height());
-        glScissor(r.left, sy, r.width(), r.height());
-        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-    }
     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
     glDisable(GL_BLEND);
 }
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index cd6efdd..d123d9b 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -100,7 +100,6 @@
             uint32_t setTransactionFlags(uint32_t flags);
             
             Rect visibleBounds() const;
-            void drawRegion(const Region& reg) const;
 
     virtual sp<LayerBaseClient> getLayerBaseClient() const { return 0; }
     virtual sp<Layer> getLayer() const { return 0; }
@@ -109,8 +108,6 @@
 
     virtual void setGeometry(hwc_layer_t* hwcl);
     virtual void setPerFrameData(hwc_layer_t* hwcl);
-            void setOverlay(bool inOverlay);
-            bool isOverlay() const;
 
 
     /**
@@ -230,14 +227,15 @@
 
     int32_t  getOrientation() const { return mOrientation; }
     int32_t  getPlaneOrientation() const { return mPlaneOrientation; }
-    
+
+    void clearWithOpenGL(const Region& clip) const;
+
 protected:
     const GraphicPlane& graphicPlane(int dpy) const;
           GraphicPlane& graphicPlane(int dpy);
 
           void clearWithOpenGL(const Region& clip, GLclampf r, GLclampf g,
                                GLclampf b, GLclampf alpha) const;
-          void clearWithOpenGL(const Region& clip) const;
           void drawWithOpenGL(const Region& clip) const;
 
           void setFiltering(bool filtering);
@@ -255,17 +253,13 @@
                 // Whether filtering is needed b/c of the drawingstate
                 bool            mNeedsFiltering;
 
-                // this layer is currently handled by the hwc. this is
-                // updated at composition time, always frmo the composition
-                // thread.
-                bool            mInOverlay;
-
 protected:
                 // cached during validateVisibility()
                 int32_t         mOrientation;
                 int32_t         mPlaneOrientation;
                 Transform       mTransform;
                 GLfloat         mVertices[4][2];
+                size_t          mNumVertices;
                 Rect            mTransformedBounds;
             
                 // these are protected by an external lock
diff --git a/services/surfaceflinger/LayerDim.cpp b/services/surfaceflinger/LayerDim.cpp
index e665d7a..96a310f 100644
--- a/services/surfaceflinger/LayerDim.cpp
+++ b/services/surfaceflinger/LayerDim.cpp
@@ -43,9 +43,7 @@
 void LayerDim::onDraw(const Region& clip) const
 {
     const State& s(drawingState());
-    Region::const_iterator it = clip.begin();
-    Region::const_iterator const end = clip.end();
-    if (s.alpha>0 && (it != end)) {
+    if (s.alpha>0) {
         const DisplayHardware& hw(graphicPlane(0).displayHardware());
         const GLfloat alpha = s.alpha/255.0f;
         const uint32_t fbHeight = hw.getHeight();
@@ -62,13 +60,8 @@
         glColor4f(0, 0, 0, alpha);
 
         glVertexPointer(2, GL_FLOAT, 0, mVertices);
+        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 
-        while (it != end) {
-            const Rect& r = *it++;
-            const GLint sy = fbHeight - (r.top + r.height());
-            glScissor(r.left, sy, r.width(), r.height());
-            glDrawArrays(GL_TRIANGLE_FAN, 0, 4); 
-        }
         glDisable(GL_BLEND);
         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
     }
diff --git a/services/surfaceflinger/LayerScreenshot.cpp b/services/surfaceflinger/LayerScreenshot.cpp
index c7cf46e..b42353c 100644
--- a/services/surfaceflinger/LayerScreenshot.cpp
+++ b/services/surfaceflinger/LayerScreenshot.cpp
@@ -70,8 +70,6 @@
     glBindTexture(GL_TEXTURE_2D, mTextureName);
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
     glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     mTexCoords[0] = 0;         mTexCoords[1] = v;
     mTexCoords[2] = 0;         mTexCoords[3] = 0;
     mTexCoords[4] = u;         mTexCoords[5] = 0;
@@ -111,9 +109,7 @@
 void LayerScreenshot::onDraw(const Region& clip) const
 {
     const State& s(drawingState());
-    Region::const_iterator it = clip.begin();
-    Region::const_iterator const end = clip.end();
-    if (s.alpha>0 && (it != end)) {
+    if (s.alpha>0) {
         const DisplayHardware& hw(graphicPlane(0).displayHardware());
         const GLfloat alpha = s.alpha/255.0f;
         const uint32_t fbHeight = hw.getHeight();
@@ -139,13 +135,7 @@
         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
         glTexCoordPointer(2, GL_FLOAT, 0, mTexCoords);
         glVertexPointer(2, GL_FLOAT, 0, mVertices);
-
-        while (it != end) {
-            const Rect& r = *it++;
-            const GLint sy = fbHeight - (r.top + r.height());
-            glScissor(r.left, sy, r.width(), r.height());
-            glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-        }
+        glDrawArrays(GL_TRIANGLE_FAN, 0, mNumVertices);
 
         glDisable(GL_BLEND);
         glDisable(GL_TEXTURE_2D);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index fb0c305..0d4d2b9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -87,7 +87,6 @@
         mHwWorkListDirty(false),
         mElectronBeamAnimationMode(0),
         mDebugRegion(0),
-        mDebugBackground(0),
         mDebugDDMS(0),
         mDebugDisableHWC(0),
         mDebugDisableTransformHint(0),
@@ -111,9 +110,6 @@
     property_get("debug.sf.showupdates", value, "0");
     mDebugRegion = atoi(value);
 
-    property_get("debug.sf.showbackground", value, "0");
-    mDebugBackground = atoi(value);
-
 #ifdef DDMS_DEBUGGING
     property_get("debug.sf.ddms", value, "0");
     mDebugDDMS = atoi(value);
@@ -123,7 +119,6 @@
 #endif
 
     ALOGI_IF(mDebugRegion,       "showupdates enabled");
-    ALOGI_IF(mDebugBackground,   "showbackground enabled");
     ALOGI_IF(mDebugDDMS,         "DDMS debugging enabled");
 }
 
@@ -265,7 +260,6 @@
     glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
     glPixelStorei(GL_PACK_ALIGNMENT, 4);
     glEnableClientState(GL_VERTEX_ARRAY);
-    glEnable(GL_SCISSOR_TEST);
     glShadeModel(GL_FLAT);
     glDisable(GL_DITHER);
     glDisable(GL_CULL_FACE);
@@ -834,22 +828,11 @@
     glLoadIdentity();
 
     uint32_t flags = hw.getFlags();
-    if ((flags & DisplayHardware::SWAP_RECTANGLE) ||
-        (flags & DisplayHardware::BUFFER_PRESERVED))
-    {
+    if (flags & DisplayHardware::SWAP_RECTANGLE) {
         // we can redraw only what's dirty, but since SWAP_RECTANGLE only
         // takes a rectangle, we must make sure to update that whole
         // rectangle in that case
-        if (flags & DisplayHardware::SWAP_RECTANGLE) {
-            // TODO: we really should be able to pass a region to
-            // SWAP_RECTANGLE so that we don't have to redraw all this.
-            mDirtyRegion.set(mSwapRegion.bounds());
-        } else {
-            // in the BUFFER_PRESERVED case, obviously, we can update only
-            // what's needed and nothing more.
-            // NOTE: this is NOT a common case, as preserving the backbuffer
-            // is costly and usually involves copying the whole update back.
-        }
+        mDirtyRegion.set(mSwapRegion.bounds());
     } else {
         if (flags & DisplayHardware::PARTIAL_UPDATES) {
             // We need to redraw the rectangle that will be updated
@@ -864,7 +847,7 @@
         }
     }
 
-    setupHardwareComposer(mDirtyRegion);
+    setupHardwareComposer();
     composeSurfaces(mDirtyRegion);
 
     // update the swap region and clear the dirty region
@@ -872,7 +855,7 @@
     mDirtyRegion.clear();
 }
 
-void SurfaceFlinger::setupHardwareComposer(Region& dirtyInOut)
+void SurfaceFlinger::setupHardwareComposer()
 {
     const DisplayHardware& hw(graphicPlane(0).displayHardware());
     HWComposer& hwc(hw.getHwComposer());
@@ -901,120 +884,59 @@
         const sp<LayerBase>& layer(layers[i]);
         layer->setPerFrameData(&cur[i]);
     }
-    const size_t fbLayerCount = hwc.getLayerCount(HWC_FRAMEBUFFER);
     status_t err = hwc.prepare();
     ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
-
-    if (err == NO_ERROR) {
-        // what's happening here is tricky.
-        // we want to clear all the layers with the CLEAR_FB flags
-        // that are opaque.
-        // however, since some GPU are efficient at preserving
-        // the backbuffer, we want to take advantage of that so we do the
-        // clear only in the dirty region (other areas will be preserved
-        // on those GPUs).
-        //   NOTE: on non backbuffer preserving GPU, the dirty region
-        //   has already been expanded as needed, so the code is correct
-        //   there too.
-        //
-        // However, the content of the framebuffer cannot be trusted when
-        // we switch to/from FB/OVERLAY, in which case we need to
-        // expand the dirty region to those areas too.
-        //
-        // Note also that there is a special case when switching from
-        // "no layers in FB" to "some layers in FB", where we need to redraw
-        // the entire FB, since some areas might contain uninitialized
-        // data.
-        //
-        // Also we want to make sure to not clear areas that belong to
-        // layers above that won't redraw (we would just be erasing them),
-        // that is, we can't erase anything outside the dirty region.
-
-        Region transparent;
-
-        if (!fbLayerCount && hwc.getLayerCount(HWC_FRAMEBUFFER)) {
-            transparent.set(hw.getBounds());
-            dirtyInOut = transparent;
-        } else {
-            for (size_t i=0 ; i<count ; i++) {
-                const sp<LayerBase>& layer(layers[i]);
-                if ((cur[i].hints & HWC_HINT_CLEAR_FB) && layer->isOpaque()) {
-                    transparent.orSelf(layer->visibleRegionScreen);
-                }
-                bool isOverlay = (cur[i].compositionType != HWC_FRAMEBUFFER);
-                if (isOverlay != layer->isOverlay()) {
-                    // we transitioned to/from overlay, so add this layer
-                    // to the dirty region so the framebuffer can be either
-                    // cleared or redrawn.
-                    dirtyInOut.orSelf(layer->visibleRegionScreen);
-                }
-                layer->setOverlay(isOverlay);
-            }
-            // don't erase stuff outside the dirty region
-            transparent.andSelf(dirtyInOut);
-        }
-
-        /*
-         *  clear the area of the FB that need to be transparent
-         */
-        if (!transparent.isEmpty()) {
-            glClearColor(0,0,0,0);
-            Region::const_iterator it = transparent.begin();
-            Region::const_iterator const end = transparent.end();
-            const int32_t height = hw.getHeight();
-            while (it != end) {
-                const Rect& r(*it++);
-                const GLint sy = height - (r.top + r.height());
-                glScissor(r.left, sy, r.width(), r.height());
-                glClear(GL_COLOR_BUFFER_BIT);
-            }
-        }
-    }
 }
 
 void SurfaceFlinger::composeSurfaces(const Region& dirty)
 {
     const DisplayHardware& hw(graphicPlane(0).displayHardware());
     HWComposer& hwc(hw.getHwComposer());
+    hwc_layer_t* const cur(hwc.getLayers());
 
     const size_t fbLayerCount = hwc.getLayerCount(HWC_FRAMEBUFFER);
-    if (CC_UNLIKELY(fbLayerCount && !mWormholeRegion.isEmpty())) {
-        // should never happen unless the window manager has a bug
-        // draw something...
-        drawWormhole();
-    }
+    if (!cur || fbLayerCount) {
+        // Never touch the framebuffer if we don't have any framebuffer layers
 
-    /*
-     * and then, render the layers targeted at the framebuffer
-     */
-
-    hwc_layer_t* const cur(hwc.getLayers());
-    const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
-    size_t count = layers.size();
-
-
-    // FIXME: workaround for b/6020860
-    if (hw.getFlags() & DisplayHardware::BUFFER_PRESERVED) {
-        for (size_t i=0 ; i<count ; i++) {
-            if (cur && (cur[i].compositionType == HWC_FRAMEBUFFER)) {
-                glEnable(GL_SCISSOR_TEST);
-                glScissor(0,0,0,0);
-                glClear(GL_COLOR_BUFFER_BIT);
-                break;
+        if (hwc.getLayerCount(HWC_OVERLAY)) {
+            // when using overlays, we assume a fully transparent framebuffer
+            // NOTE: we could reduce how much we need to clear, for instance
+            // remove where there are opaque FB layers. however, on some
+            // GPUs doing a "clean slate" glClear might be more efficient.
+            // We'll revisit later if needed.
+            glClearColor(0, 0, 0, 0);
+            glClear(GL_COLOR_BUFFER_BIT);
+        } else {
+            // screen is already cleared here
+            if (!mWormholeRegion.isEmpty()) {
+                // can happen with SurfaceView
+                drawWormhole();
             }
         }
-    }
-    // FIXME: bug6020860 for b/6020860
 
+        /*
+         * and then, render the layers targeted at the framebuffer
+         */
 
-    for (size_t i=0 ; i<count ; i++) {
-        if (cur && (cur[i].compositionType != HWC_FRAMEBUFFER)) {
-            continue;
-        }
-        const sp<LayerBase>& layer(layers[i]);
-        const Region clip(dirty.intersect(layer->visibleRegionScreen));
-        if (!clip.isEmpty()) {
-            layer->draw(clip);
+        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]);
+            const Region clip(dirty.intersect(layer->visibleRegionScreen));
+            if (!clip.isEmpty()) {
+                if (cur && (cur[i].compositionType == HWC_OVERLAY)) {
+                    if (i && (cur[i].hints & HWC_HINT_CLEAR_FB)
+                            && layer->isOpaque()) {
+                        // never clear the very first layer since we're
+                        // guaranteed the FB is already cleared
+                        layer->clearWithOpenGL(clip);
+                    }
+                    continue;
+                }
+                // render the layer
+                layer->draw(clip);
+            }
         }
     }
 }
@@ -1028,8 +950,7 @@
         return;
     }
 
-    if (!((flags & DisplayHardware::SWAP_RECTANGLE) ||
-            (flags & DisplayHardware::BUFFER_PRESERVED))) {
+    if (!(flags & DisplayHardware::SWAP_RECTANGLE)) {
         const Region repaint((flags & DisplayHardware::PARTIAL_UPDATES) ?
                 mDirtyRegion.bounds() : hw.bounds());
         composeSurfaces(repaint);
@@ -1066,8 +987,6 @@
 
     if (mDebugRegion > 1)
         usleep(mDebugRegion * 1000);
-
-    glEnable(GL_SCISSOR_TEST);
 }
 
 void SurfaceFlinger::drawWormhole() const
@@ -1076,51 +995,26 @@
     if (region.isEmpty())
         return;
 
-    const DisplayHardware& hw(graphicPlane(0).displayHardware());
-    const int32_t width = hw.getWidth();
-    const int32_t height = hw.getHeight();
+    glDisable(GL_TEXTURE_EXTERNAL_OES);
+    glDisable(GL_TEXTURE_2D);
+    glDisable(GL_BLEND);
+    glColor4f(0,0,0,0);
 
-    if (CC_LIKELY(!mDebugBackground)) {
-        glClearColor(0,0,0,0);
-        Region::const_iterator it = region.begin();
-        Region::const_iterator const end = region.end();
-        while (it != end) {
-            const Rect& r = *it++;
-            const GLint sy = height - (r.top + r.height());
-            glScissor(r.left, sy, r.width(), r.height());
-            glClear(GL_COLOR_BUFFER_BIT);
-        }
-    } else {
-        const GLshort vertices[][2] = { { 0, 0 }, { width, 0 },
-                { width, height }, { 0, height }  };
-        const GLshort tcoords[][2] = { { 0, 0 }, { 1, 0 },  { 1, 1 }, { 0, 1 } };
-
-        glVertexPointer(2, GL_SHORT, 0, vertices);
-        glTexCoordPointer(2, GL_SHORT, 0, tcoords);
-        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-
-        glDisable(GL_TEXTURE_EXTERNAL_OES);
-        glEnable(GL_TEXTURE_2D);
-        glBindTexture(GL_TEXTURE_2D, mWormholeTexName);
-        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-        glMatrixMode(GL_TEXTURE);
-        glLoadIdentity();
-
-        glDisable(GL_BLEND);
-
-        glScalef(width*(1.0f/32.0f), height*(1.0f/32.0f), 1);
-        Region::const_iterator it = region.begin();
-        Region::const_iterator const end = region.end();
-        while (it != end) {
-            const Rect& r = *it++;
-            const GLint sy = height - (r.top + r.height());
-            glScissor(r.left, sy, r.width(), r.height());
-            glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-        }
-        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-        glDisable(GL_TEXTURE_2D);
-        glLoadIdentity();
-        glMatrixMode(GL_MODELVIEW);
+    GLfloat vertices[4][2];
+    glVertexPointer(2, GL_FLOAT, 0, vertices);
+    Region::const_iterator it = region.begin();
+    Region::const_iterator const end = region.end();
+    while (it != end) {
+        const Rect& r = *it++;
+        vertices[0][0] = r.left;
+        vertices[0][1] = r.top;
+        vertices[1][0] = r.right;
+        vertices[1][1] = r.top;
+        vertices[2][0] = r.right;
+        vertices[2][1] = r.bottom;
+        vertices[3][0] = r.left;
+        vertices[3][1] = r.bottom;
+        glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
     }
 }
 
@@ -1807,10 +1701,6 @@
                 invalidateHwcGeometry();
                 repaintEverything();
                 return NO_ERROR;
-            case 1003:  // SHOW_BACKGROUND
-                n = data.readInt32();
-                mDebugBackground = n ? 1 : 0;
-                return NO_ERROR;
             case 1004:{ // repaint everything
                 repaintEverything();
                 return NO_ERROR;
@@ -1839,7 +1729,7 @@
                 reply->writeInt32(0);
                 reply->writeInt32(0);
                 reply->writeInt32(mDebugRegion);
-                reply->writeInt32(mDebugBackground);
+                reply->writeInt32(0);
                 reply->writeInt32(mDebugDisableHWC);
                 return NO_ERROR;
             case 1013: {
@@ -1903,6 +1793,8 @@
     GLuint name, tname;
     glGenTextures(1, &tname);
     glBindTexture(GL_TEXTURE_2D, tname);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
             hw_w, hw_h, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
     if (glGetError() != GL_NO_ERROR) {
@@ -1925,7 +1817,6 @@
     glDisable(GL_SCISSOR_TEST);
     glClearColor(0,0,0,1);
     glClear(GL_COLOR_BUFFER_BIT);
-    glEnable(GL_SCISSOR_TEST);
     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
     const Vector< sp<LayerBase> >& layers(mVisibleLayersSortedByZ);
@@ -2110,11 +2001,11 @@
     }
 
     glColorMask(1,1,1,1);
-    glEnable(GL_SCISSOR_TEST);
     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
     glDeleteTextures(1, &tname);
     glDisable(GL_TEXTURE_2D);
     glDisable(GL_BLEND);
+    glDisable(GL_SCISSOR_TEST);
     return NO_ERROR;
 }
 
@@ -2253,11 +2144,11 @@
     }
 
     glColorMask(1,1,1,1);
-    glEnable(GL_SCISSOR_TEST);
     glDisableClientState(GL_TEXTURE_COORD_ARRAY);
     glDeleteTextures(1, &tname);
     glDisable(GL_TEXTURE_2D);
     glDisable(GL_BLEND);
+    glDisable(GL_SCISSOR_TEST);
 
     return NO_ERROR;
 }
@@ -2287,7 +2178,6 @@
     glClearColor(0,0,0,1);
     glDisable(GL_SCISSOR_TEST);
     glClear(GL_COLOR_BUFFER_BIT);
-    glEnable(GL_SCISSOR_TEST);
     hw.flip( Region(hw.bounds()) );
 
     return NO_ERROR;
@@ -2425,7 +2315,6 @@
         // invert everything, b/c glReadPixel() below will invert the FB
         glViewport(0, 0, sw, sh);
         glScissor(0, 0, sw, sh);
-        glEnable(GL_SCISSOR_TEST);
         glMatrixMode(GL_PROJECTION);
         glPushMatrix();
         glLoadIdentity();
@@ -2478,7 +2367,7 @@
                 result = NO_MEMORY;
             }
         }
-        glEnable(GL_SCISSOR_TEST);
+        glDisable(GL_SCISSOR_TEST);
         glViewport(0, 0, hw_w, hw_h);
         glMatrixMode(GL_PROJECTION);
         glPopMatrix();
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 46bbab2..d9c2033 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -318,7 +318,7 @@
             void        handleWorkList();
             void        handleRepaint();
             void        postFramebuffer();
-            void        setupHardwareComposer(Region& dirtyInOut);
+            void        setupHardwareComposer();
             void        composeSurfaces(const Region& dirty);
 
 
@@ -350,7 +350,7 @@
 
             void        debugFlashRegions();
             void        drawWormhole() const;
-           
+
             void listLayersLocked(const Vector<String16>& args, size_t& index,
                     String8& result, char* buffer, size_t SIZE) const;
             void dumpStatsLocked(const Vector<String16>& args, size_t& index,
@@ -402,7 +402,6 @@
 
                 // don't use a lock for these, we don't care
                 int                         mDebugRegion;
-                int                         mDebugBackground;
                 int                         mDebugDDMS;
                 int                         mDebugDisableHWC;
                 int                         mDebugDisableTransformHint;
diff --git a/services/surfaceflinger/SurfaceTextureLayer.cpp b/services/surfaceflinger/SurfaceTextureLayer.cpp
index d7fd39e..2b647bb 100644
--- a/services/surfaceflinger/SurfaceTextureLayer.cpp
+++ b/services/surfaceflinger/SurfaceTextureLayer.cpp
@@ -40,10 +40,6 @@
             outWidth, outHeight, outTransform);
     if (err == NO_ERROR) {
         switch(api) {
-            case NATIVE_WINDOW_API_CPU:
-                // SurfaceTextureClient supports only 2 buffers for CPU connections
-                this->setBufferCountServer(2);
-                break;
             case NATIVE_WINDOW_API_MEDIA:
             case NATIVE_WINDOW_API_CAMERA:
                 // Camera preview and videos are rate-limited on the producer