am 00697a90: docs: Add missing intent flag to Android U nav class

* commit '00697a90bec4e0536cfa0873602b64bb6785022e':
  docs: Add missing intent flag to Android U nav class
diff --git a/include/binder/CursorWindow.h b/include/binder/CursorWindow.h
index 5d490ed..f0284de 100644
--- a/include/binder/CursorWindow.h
+++ b/include/binder/CursorWindow.h
@@ -80,8 +80,7 @@
 
     ~CursorWindow();
 
-    static status_t create(const String8& name, size_t size, bool localOnly,
-            CursorWindow** outCursorWindow);
+    static status_t create(const String8& name, size_t size, CursorWindow** outCursorWindow);
     static status_t createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow);
 
     status_t writeToParcel(Parcel* parcel);
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index e2d6179..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();
 
@@ -79,7 +85,11 @@
     // pointed to by the buf argument and a status of OK is returned.  If no
     // slot is available then a status of -EBUSY is returned and buf is
     // unmodified.
-    virtual status_t dequeueBuffer(int *buf, uint32_t w, uint32_t h,
+    // The width and height parameters must be no greater than the minimum of
+    // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv).
+    // An error due to invalid dimensions might not be reported until
+    // updateTexImage() is called.
+    virtual status_t dequeueBuffer(int *buf, uint32_t width, uint32_t height,
             uint32_t format, uint32_t usage);
 
     // queueBuffer returns a filled buffer to the SurfaceTexture. In addition, a
@@ -176,7 +186,11 @@
     // requestBuffers when a with and height of zero is requested.
     // A call to setDefaultBufferSize() may trigger requestBuffers() to
     // be called from the client.
-    status_t setDefaultBufferSize(uint32_t w, uint32_t h);
+    // The width and height parameters must be no greater than the minimum of
+    // GL_MAX_VIEWPORT_DIMS and GL_MAX_TEXTURE_SIZE (see: glGetIntegerv).
+    // An error due to invalid dimensions might not be reported until
+    // updateTexImage() is called.
+    status_t setDefaultBufferSize(uint32_t width, uint32_t height);
 
     // getCurrentBuffer returns the buffer associated with the current image.
     sp<GraphicBuffer> getCurrentBuffer() const;
@@ -194,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
@@ -263,7 +281,9 @@
               mRequestBufferCalled(false),
               mTransform(0),
               mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
-              mTimestamp(0) {
+              mTimestamp(0),
+              mFrameNumber(0),
+              mFence(EGL_NO_SYNC_KHR) {
             mCrop.makeInvalid();
         }
 
@@ -332,6 +352,15 @@
         // mTimestamp is the current timestamp for this buffer slot. This gets
         // to set by queueBuffer each time this slot is queued.
         int64_t mTimestamp;
+
+        // 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
@@ -455,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.
@@ -468,6 +503,12 @@
     // around a GL driver limitation on the number of FBO attachments, which the
     // browser's tile cache exceeds.
     const GLenum mTexTarget;
+
+    // mFrameCounter is the free running counter, incremented for every buffer queued
+    // with the surface Texture.
+    uint64_t mFrameCounter;
+
+
 };
 
 // ----------------------------------------------------------------------------
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/surfaceflinger/ISurfaceComposer.h b/include/surfaceflinger/ISurfaceComposer.h
index e7a33f1..5eb09c7 100644
--- a/include/surfaceflinger/ISurfaceComposer.h
+++ b/include/surfaceflinger/ISurfaceComposer.h
@@ -84,7 +84,11 @@
         eOrientationUnchanged   = 4,
         eOrientationSwapMask    = 0x01
     };
-    
+
+    enum {
+        eSynchronous            = 0x01,
+    };
+
     enum {
         eElectronBeamAnimationOn  = 0x01,
         eElectronBeamAnimationOff = 0x10
@@ -104,7 +108,7 @@
 
     /* open/close transactions. requires ACCESS_SURFACE_FLINGER permission */
     virtual void setTransactionState(const Vector<ComposerState>& state,
-            int orientation) = 0;
+            int orientation, uint32_t flags) = 0;
 
     /* signal that we're done booting.
      * Requires ACCESS_SURFACE_FLINGER permission
@@ -143,8 +147,6 @@
         GET_CBLK,
         SET_TRANSACTION_STATE,
         SET_ORIENTATION,
-        FREEZE_DISPLAY,
-        UNFREEZE_DISPLAY,
         CAPTURE_SCREEN,
         TURN_ELECTRON_BEAM_OFF,
         TURN_ELECTRON_BEAM_ON,
diff --git a/include/surfaceflinger/SurfaceComposerClient.h b/include/surfaceflinger/SurfaceComposerClient.h
index 14e5b23..8226abe 100644
--- a/include/surfaceflinger/SurfaceComposerClient.h
+++ b/include/surfaceflinger/SurfaceComposerClient.h
@@ -112,7 +112,7 @@
     static void openGlobalTransaction();
         
     //! Close a composer transaction on all active SurfaceComposerClients.
-    static void closeGlobalTransaction();
+    static void closeGlobalTransaction(bool synchronous = false);
     
     //! Freeze the specified display but not transactions.
     static status_t freezeDisplay(DisplayID dpy, uint32_t flags = 0);
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/Input.h b/include/ui/Input.h
index 438a1a0..c2cbe1d 100644
--- a/include/ui/Input.h
+++ b/include/ui/Input.h
@@ -826,6 +826,9 @@
     inline void setKeyboardType(int32_t keyboardType) { mKeyboardType = keyboardType; }
     inline int32_t getKeyboardType() const { return mKeyboardType; }
 
+    inline void setKeyCharacterMapFile(const String8& value) { mKeyCharacterMapFile = value; }
+    inline const String8& getKeyCharacterMapFile() const { return mKeyCharacterMapFile; }
+
     inline const Vector<MotionRange>& getMotionRanges() const {
         return mMotionRanges;
     }
@@ -835,6 +838,7 @@
     String8 mName;
     uint32_t mSources;
     int32_t mKeyboardType;
+    String8 mKeyCharacterMapFile;
 
     Vector<MotionRange> mMotionRanges;
 };
diff --git a/include/ui/KeyCharacterMap.h b/include/ui/KeyCharacterMap.h
index 10a3810..be14432 100644
--- a/include/ui/KeyCharacterMap.h
+++ b/include/ui/KeyCharacterMap.h
@@ -53,7 +53,6 @@
     ~KeyCharacterMap();
 
     static status_t load(const String8& filename, KeyCharacterMap** outMap);
-    static status_t loadByDeviceId(int32_t deviceId, KeyCharacterMap** outMap);
 
     /* Gets the keyboard type. */
     int32_t getKeyboardType() const;
diff --git a/include/ui/Keyboard.h b/include/ui/Keyboard.h
index 609f319..274f526 100644
--- a/include/ui/Keyboard.h
+++ b/include/ui/Keyboard.h
@@ -81,24 +81,6 @@
         const PropertyMap* deviceConfiguration, const KeyMap* keyMap);
 
 /**
- * Sets keyboard system properties.
- */
-extern void setKeyboardProperties(int32_t deviceId, const InputDeviceIdentifier& deviceIdentifier,
-        const String8& keyLayoutFile, const String8& keyCharacterMapFile);
-
-/**
- * Clears keyboard system properties.
- */
-extern void clearKeyboardProperties(int32_t deviceId);
-
-/**
- * Gets the key character map filename for a device using inspecting system properties
- * and then falling back on a default key character map if necessary.
- * Returns a NAME_NOT_FOUND if none found.
- */
-extern status_t getKeyCharacterMapFile(int32_t deviceId, String8& outKeyCharacterMapFile);
-
-/**
  * Gets a key code by its short form label, eg. "HOME".
  * Returns 0 if unknown.
  */
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/include/utils/BlobCache.h b/include/utils/BlobCache.h
index dc45ff0..4f342a2 100644
--- a/include/utils/BlobCache.h
+++ b/include/utils/BlobCache.h
@@ -19,19 +19,21 @@
 
 #include <stddef.h>
 
+#include <utils/Flattenable.h>
 #include <utils/RefBase.h>
 #include <utils/SortedVector.h>
 #include <utils/threads.h>
 
 namespace android {
 
-// A BlobCache is an in-memory cache for binary key/value pairs. All the public
-// methods are thread-safe.
+// A BlobCache is an in-memory cache for binary key/value pairs.  A BlobCache
+// does NOT provide any thread-safety guarantees.
 //
-// The cache contents can be serialized to a file and reloaded in a subsequent
-// execution of the program. This serialization is non-portable and should only
-// be loaded by the device that generated it.
-class BlobCache : public RefBase {
+// The cache contents can be serialized to an in-memory buffer or mmap'd file
+// and then reloaded in a subsequent execution of the program.  This
+// serialization is non-portable and the data should only be used by the device
+// that generated it.
+class BlobCache : public RefBase, public Flattenable {
 public:
 
     // Create an empty blob cache. The blob cache will cache key/value pairs
@@ -58,14 +60,13 @@
     void set(const void* key, size_t keySize, const void* value,
             size_t valueSize);
 
-    // The get function retrieves from the cache the binary value associated
-    // with a given binary key.  If the key is present in the cache then the
-    // length of the binary value associated with that key is returned.  If the
-    // value argument is non-NULL and the size of the cached value is less than
-    // valueSize bytes then the cached value is copied into the buffer pointed
-    // to by the value argument.  If the key is not present in the cache then 0
-    // is returned and the buffer pointed to by the value argument is not
-    // modified.
+    // get retrieves from the cache the binary value associated with a given
+    // binary key.  If the key is present in the cache then the length of the
+    // binary value associated with that key is returned.  If the value argument
+    // is non-NULL and the size of the cached value is less than valueSize bytes
+    // then the cached value is copied into the buffer pointed to by the value
+    // argument.  If the key is not present in the cache then 0 is returned and
+    // the buffer pointed to by the value argument is not modified.
     //
     // Note that when calling get multiple times with the same key, the later
     // calls may fail, returning 0, even if earlier calls succeeded.  The return
@@ -77,6 +78,37 @@
     //   0 <= valueSize
     size_t get(const void* key, size_t keySize, void* value, size_t valueSize);
 
+    // getFlattenedSize returns the number of bytes needed to store the entire
+    // serialized cache.
+    virtual size_t getFlattenedSize() const;
+
+    // getFdCount returns the number of file descriptors that will result from
+    // flattening the cache.  This will always return 0 so as to allow the
+    // flattened cache to be saved to disk and then later restored.
+    virtual size_t getFdCount() const;
+
+    // flatten serializes the current contents of the cache into the memory
+    // pointed to by 'buffer'.  The serialized cache contents can later be
+    // loaded into a BlobCache object using the unflatten method.  The contents
+    // of the BlobCache object will not be modified.
+    //
+    // Preconditions:
+    //   size >= this.getFlattenedSize()
+    //   count == 0
+    virtual status_t flatten(void* buffer, size_t size, int fds[],
+            size_t count) const;
+
+    // unflatten replaces the contents of the cache with the serialized cache
+    // contents in the memory pointed to by 'buffer'.  The previous contents of
+    // the BlobCache will be evicted from the cache.  If an error occurs while
+    // unflattening the serialized cache contents then the BlobCache will be
+    // left in an empty state.
+    //
+    // Preconditions:
+    //   count == 0
+    virtual status_t unflatten(void const* buffer, size_t size, int fds[],
+            size_t count);
+
 private:
     // Copying is disallowed.
     BlobCache(const BlobCache&);
@@ -144,6 +176,46 @@
         sp<Blob> mValue;
     };
 
+    // A Header is the header for the entire BlobCache serialization format. No
+    // need to make this portable, so we simply write the struct out.
+    struct Header {
+        // mMagicNumber is the magic number that identifies the data as
+        // serialized BlobCache contents.  It must always contain 'Blb$'.
+        uint32_t mMagicNumber;
+
+        // mBlobCacheVersion is the serialization format version.
+        uint32_t mBlobCacheVersion;
+
+        // mDeviceVersion is the device-specific version of the cache.  This can
+        // be used to invalidate the cache.
+        uint32_t mDeviceVersion;
+
+        // mNumEntries is number of cache entries following the header in the
+        // data.
+        size_t mNumEntries;
+    };
+
+    // An EntryHeader is the header for a serialized cache entry.  No need to
+    // make this portable, so we simply write the struct out.  Each EntryHeader
+    // is followed imediately by the key data and then the value data.
+    //
+    // The beginning of each serialized EntryHeader is 4-byte aligned, so the
+    // number of bytes that a serialized cache entry will occupy is:
+    //
+    //   ((sizeof(EntryHeader) + keySize + valueSize) + 3) & ~3
+    //
+    struct EntryHeader {
+        // mKeySize is the size of the entry key in bytes.
+        size_t mKeySize;
+
+        // mValueSize is the size of the entry value in bytes.
+        size_t mValueSize;
+
+        // mData contains both the key and value data for the cache entry.  The
+        // key comes first followed immediately by the value.
+        uint8_t mData[];
+    };
+
     // mMaxKeySize is the maximum key size that will be cached. Calls to
     // BlobCache::set with a keySize parameter larger than mMaxKeySize will
     // simply not add the key/value pair to the cache.
@@ -166,17 +238,12 @@
     size_t mTotalSize;
 
     // mRandState is the pseudo-random number generator state. It is passed to
-    // nrand48 to generate random numbers when needed. It must be protected by
-    // mMutex.
+    // nrand48 to generate random numbers when needed.
     unsigned short mRandState[3];
 
     // mCacheEntries stores all the cache entries that are resident in memory.
     // Cache entries are added to it by the 'set' method.
     SortedVector<CacheEntry> mCacheEntries;
-
-    // mMutex is used to synchronize access to all member variables.  It must be
-    // locked any time the member variables are written or read.
-    Mutex mMutex;
 };
 
 }
diff --git a/include/utils/Singleton.h b/include/utils/Singleton.h
index e1ee8eb..a42ce21 100644
--- a/include/utils/Singleton.h
+++ b/include/utils/Singleton.h
@@ -20,12 +20,13 @@
 #include <stdint.h>
 #include <sys/types.h>
 #include <utils/threads.h>
+#include <cutils/compiler.h>
 
 namespace android {
 // ---------------------------------------------------------------------------
 
 template <typename TYPE>
-class Singleton
+class ANDROID_API Singleton
 {
 public:
     static TYPE& getInstance() {
diff --git a/libs/binder/CursorWindow.cpp b/libs/binder/CursorWindow.cpp
index 60681c4..0733378 100644
--- a/libs/binder/CursorWindow.cpp
+++ b/libs/binder/CursorWindow.cpp
@@ -40,11 +40,9 @@
     ::close(mAshmemFd);
 }
 
-status_t CursorWindow::create(const String8& name, size_t size, bool localOnly,
-        CursorWindow** outCursorWindow) {
+status_t CursorWindow::create(const String8& name, size_t size, CursorWindow** outCursorWindow) {
     String8 ashmemName("CursorWindow: ");
     ashmemName.append(name);
-    ashmemName.append(localOnly ? " (local)" : " (remote)");
 
     status_t result;
     int ashmemFd = ashmem_create_region(ashmemName.string(), size);
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/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index eb90147..86bc62a 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -79,7 +79,7 @@
     }
 
     virtual void setTransactionState(const Vector<ComposerState>& state,
-            int orientation)
+            int orientation, uint32_t flags)
     {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -90,6 +90,7 @@
             b->write(data);
         }
         data.writeInt32(orientation);
+        data.writeInt32(flags);
         remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE, data, &reply);
     }
 
@@ -204,7 +205,8 @@
                 state.add(s);
             }
             int orientation = data.readInt32();
-            setTransactionState(state, orientation);
+            uint32_t flags = data.readInt32();
+            setTransactionState(state, orientation, flags);
         } break;
         case BOOT_FINISHED: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 5f3d608..4ad6c22 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -92,11 +92,14 @@
     mutable Mutex               mLock;
     SortedVector<ComposerState> mStates;
     int                         mOrientation;
+    uint32_t                    mForceSynchronous;
 
     Composer() : Singleton<Composer>(),
-        mOrientation(ISurfaceComposer::eOrientationUnchanged) { }
+        mOrientation(ISurfaceComposer::eOrientationUnchanged),
+        mForceSynchronous(0)
+    { }
 
-    void closeGlobalTransactionImpl();
+    void closeGlobalTransactionImpl(bool synchronous);
 
     layer_state_t* getLayerStateLocked(
             const sp<SurfaceComposerClient>& client, SurfaceID id);
@@ -123,8 +126,8 @@
             uint32_t tint);
     status_t setOrientation(int orientation);
 
-    static void closeGlobalTransaction() {
-        Composer::getInstance().closeGlobalTransactionImpl();
+    static void closeGlobalTransaction(bool synchronous) {
+        Composer::getInstance().closeGlobalTransactionImpl(synchronous);
     }
 };
 
@@ -132,11 +135,12 @@
 
 // ---------------------------------------------------------------------------
 
-void Composer::closeGlobalTransactionImpl() {
+void Composer::closeGlobalTransactionImpl(bool synchronous) {
     sp<ISurfaceComposer> sm(getComposerService());
 
     Vector<ComposerState> transaction;
     int orientation;
+    uint32_t flags = 0;
 
     { // scope for the lock
         Mutex::Autolock _l(mLock);
@@ -145,9 +149,14 @@
 
         orientation = mOrientation;
         mOrientation = ISurfaceComposer::eOrientationUnchanged;
+
+        if (synchronous || mForceSynchronous) {
+            flags |= ISurfaceComposer::eSynchronous;
+        }
+        mForceSynchronous = false;
     }
 
-   sm->setTransactionState(transaction, orientation);
+   sm->setTransactionState(transaction, orientation, flags);
 }
 
 layer_state_t* Composer::getLayerStateLocked(
@@ -188,6 +197,10 @@
     s->what |= ISurfaceComposer::eSizeChanged;
     s->w = w;
     s->h = h;
+
+    // Resizing a surface makes the transaction synchronous.
+    mForceSynchronous = true;
+
     return NO_ERROR;
 }
 
@@ -270,6 +283,10 @@
 status_t Composer::setOrientation(int orientation) {
     Mutex::Autolock _l(mLock);
     mOrientation = orientation;
+
+    // Changing the orientation makes the transaction synchronous.
+    mForceSynchronous = true;
+
     return NO_ERROR;
 }
 
@@ -375,8 +392,8 @@
     // Currently a no-op
 }
 
-void SurfaceComposerClient::closeGlobalTransaction() {
-    Composer::closeGlobalTransaction();
+void SurfaceComposerClient::closeGlobalTransaction(bool synchronous) {
+    Composer::closeGlobalTransaction(synchronous);
 }
 
 // ----------------------------------------------------------------------------
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index c72a45b..4772189 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,11 +132,17 @@
     mAllowSynchronousMode(allowSynchronousMode),
     mConnectedApi(NO_CONNECTED_API),
     mAbandoned(false),
-    mTexTarget(texTarget) {
+#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.
     mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
 
-    ST_LOGV("SurfaceTexture::SurfaceTexture");
+    ST_LOGV("SurfaceTexture");
     sp<ISurfaceComposer> composer(ComposerService::getComposerService());
     mGraphicBufferAlloc = composer->createGraphicBufferAlloc();
     mNextCrop.makeInvalid();
@@ -125,7 +151,7 @@
 }
 
 SurfaceTexture::~SurfaceTexture() {
-    ST_LOGV("SurfaceTexture::~SurfaceTexture");
+    ST_LOGV("~SurfaceTexture");
     freeAllBuffersLocked();
 }
 
@@ -169,7 +195,7 @@
 }
 
 status_t SurfaceTexture::setBufferCount(int bufferCount) {
-    ST_LOGV("SurfaceTexture::setBufferCount");
+    ST_LOGV("setBufferCount: count=%d", bufferCount);
     Mutex::Autolock lock(mMutex);
 
     if (mAbandoned) {
@@ -217,6 +243,7 @@
 
 status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h)
 {
+    ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h);
     if (!w || !h) {
         ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)",
                 w, h);
@@ -230,7 +257,7 @@
 }
 
 status_t SurfaceTexture::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
-    ST_LOGV("SurfaceTexture::requestBuffer");
+    ST_LOGV("requestBuffer: slot=%d", slot);
     Mutex::Autolock lock(mMutex);
     if (mAbandoned) {
         ST_LOGE("requestBuffer: SurfaceTexture has been abandoned!");
@@ -248,189 +275,237 @@
 
 status_t SurfaceTexture::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h,
         uint32_t format, uint32_t usage) {
-    ST_LOGV("SurfaceTexture::dequeueBuffer");
+    ST_LOGV("dequeueBuffer: w=%d h=%d fmt=%#x usage=%#x", w, h, format, usage);
 
     if ((w && !h) || (!w && h)) {
         ST_LOGE("dequeueBuffer: invalid size: w=%u, h=%u", w, h);
         return BAD_VALUE;
     }
 
-    Mutex::Autolock lock(mMutex);
-
     status_t returnFlags(OK);
+    EGLDisplay dpy = EGL_NO_DISPLAY;
+    EGLSyncKHR fence = EGL_NO_SYNC_KHR;
 
-    int found, foundSync;
-    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++;
+                }
+
+                // 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;
+                        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;
+                        }
                     }
                 }
-            } else {
-                if (state == BufferSlot::FREE) {
-                    foundSync = i;
-                    found = i;
-                    break;
+            }
+
+            // 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;
                 }
             }
-        }
 
-        // clients are not allowed to dequeue more than one buffer
-        // if they didn't set a buffer count.
-        if (!mClientBufferCount && dequeuedCount) {
-            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;
+            // 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) {
-        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", *outBuf,
+            mSlots[*outBuf].mGraphicBuffer->handle, returnFlags);
+
     return returnFlags;
 }
 
 status_t SurfaceTexture::setSynchronousMode(bool enabled) {
+    ST_LOGV("setSynchronousMode: enabled=%d", enabled);
     Mutex::Autolock lock(mMutex);
 
     if (mAbandoned) {
@@ -462,7 +537,7 @@
 
 status_t SurfaceTexture::queueBuffer(int buf, int64_t timestamp,
         uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
-    ST_LOGV("SurfaceTexture::queueBuffer");
+    ST_LOGV("queueBuffer: slot=%d time=%lld", buf, timestamp);
 
     sp<FrameAvailableListener> listener;
 
@@ -519,6 +594,9 @@
         mSlots[buf].mTransform = mNextTransform;
         mSlots[buf].mScalingMode = mNextScalingMode;
         mSlots[buf].mTimestamp = timestamp;
+        mFrameCounter++;
+        mSlots[buf].mFrameNumber = mFrameCounter;
+
         mDequeueCondition.signal();
 
         *outWidth = mDefaultWidth;
@@ -534,7 +612,7 @@
 }
 
 void SurfaceTexture::cancelBuffer(int buf) {
-    ST_LOGV("SurfaceTexture::cancelBuffer");
+    ST_LOGV("cancelBuffer: slot=%d", buf);
     Mutex::Autolock lock(mMutex);
 
     if (mAbandoned) {
@@ -552,11 +630,14 @@
         return;
     }
     mSlots[buf].mBufferState = BufferSlot::FREE;
+    mSlots[buf].mFrameNumber = 0;
     mDequeueCondition.signal();
 }
 
 status_t SurfaceTexture::setCrop(const Rect& crop) {
-    ST_LOGV("SurfaceTexture::setCrop");
+    ST_LOGV("setCrop: crop=[%d,%d,%d,%d]", crop.left, crop.top, crop.right,
+            crop.bottom);
+
     Mutex::Autolock lock(mMutex);
     if (mAbandoned) {
         ST_LOGE("setCrop: SurfaceTexture has been abandoned!");
@@ -567,7 +648,7 @@
 }
 
 status_t SurfaceTexture::setTransform(uint32_t transform) {
-    ST_LOGV("SurfaceTexture::setTransform");
+    ST_LOGV("setTransform: xform=%#x", transform);
     Mutex::Autolock lock(mMutex);
     if (mAbandoned) {
         ST_LOGE("setTransform: SurfaceTexture has been abandoned!");
@@ -579,7 +660,7 @@
 
 status_t SurfaceTexture::connect(int api,
         uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) {
-    ST_LOGV("SurfaceTexture::connect(this=%p, %d)", this, api);
+    ST_LOGV("connect: api=%d", api);
     Mutex::Autolock lock(mMutex);
 
     if (mAbandoned) {
@@ -612,12 +693,13 @@
 }
 
 status_t SurfaceTexture::disconnect(int api) {
-    ST_LOGV("SurfaceTexture::disconnect(this=%p, %d)", this, api);
+    ST_LOGV("disconnect: api=%d", api);
     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;
@@ -640,6 +722,7 @@
             }
             break;
         default:
+            ST_LOGE("disconnect: unknown API %d", api);
             err = -EINVAL;
             break;
     }
@@ -647,13 +730,14 @@
 }
 
 status_t SurfaceTexture::setScalingMode(int mode) {
-    ST_LOGV("SurfaceTexture::setScalingMode(%d)", mode);
+    ST_LOGV("setScalingMode: mode=%d", mode);
 
     switch (mode) {
         case NATIVE_WINDOW_SCALING_MODE_FREEZE:
         case NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW:
             break;
         default:
+            ST_LOGE("unknown scaling mode: %d", mode);
             return BAD_VALUE;
     }
 
@@ -663,7 +747,7 @@
 }
 
 status_t SurfaceTexture::updateTexImage() {
-    ST_LOGV("SurfaceTexture::updateTexImage");
+    ST_LOGV("updateTexImage");
     Mutex::Autolock lock(mMutex);
 
     if (mAbandoned) {
@@ -679,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;
@@ -714,11 +798,31 @@
         }
 
         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.
@@ -771,7 +875,7 @@
 }
 
 void SurfaceTexture::computeCurrentTransformMatrix() {
-    ST_LOGV("SurfaceTexture::computeCurrentTransformMatrix");
+    ST_LOGV("computeCurrentTransformMatrix");
 
     float xform[16];
     for (int i = 0; i < 16; i++) {
@@ -862,14 +966,14 @@
 }
 
 nsecs_t SurfaceTexture::getTimestamp() {
-    ST_LOGV("SurfaceTexture::getTimestamp");
+    ST_LOGV("getTimestamp");
     Mutex::Autolock lock(mMutex);
     return mCurrentTimestamp;
 }
 
 void SurfaceTexture::setFrameAvailableListener(
         const sp<FrameAvailableListener>& listener) {
-    ST_LOGV("SurfaceTexture::setFrameAvailableListener");
+    ST_LOGV("setFrameAvailableListener");
     Mutex::Autolock lock(mMutex);
     mFrameAvailableListener = listener;
 }
@@ -877,6 +981,7 @@
 void SurfaceTexture::freeBufferLocked(int i) {
     mSlots[i].mGraphicBuffer = 0;
     mSlots[i].mBufferState = BufferSlot::FREE;
+    mSlots[i].mFrameNumber = 0;
     if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
         eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
         mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
@@ -972,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 b8bc454..c313904 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -334,7 +334,7 @@
 
 class SurfaceTextureGLTest : public GLTest {
 protected:
-    static const GLint TEX_ID = 123;
+    enum { TEX_ID = 123 };
 
     virtual void SetUp() {
         GLTest::SetUp();
@@ -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,4 +1630,101 @@
     }
 }
 
+class SurfaceTextureFBOTest : public SurfaceTextureGLTest {
+protected:
+
+    virtual void SetUp() {
+        SurfaceTextureGLTest::SetUp();
+
+        glGenFramebuffers(1, &mFbo);
+        ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
+
+        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());
+    }
+
+    virtual void TearDown() {
+        SurfaceTextureGLTest::TearDown();
+
+        glDeleteTextures(1, &mFboTex);
+        glDeleteFramebuffers(1, &mFbo);
+    }
+
+    GLuint mFbo;
+    GLuint mFboTex;
+};
+
+// 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;
+
+    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));
+
+    android_native_buffer_t* anb;
+    ASSERT_EQ(NO_ERROR, mANW->dequeueBuffer(mANW.get(), &anb));
+    ASSERT_TRUE(anb != NULL);
+
+    sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+    ASSERT_EQ(NO_ERROR, mANW->lockBuffer(mANW.get(), buf->getNativeBuffer()));
+
+    // 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());
+
+        drawTexture();
+
+        EXPECT_TRUE(checkPixel( 24, 39, 255, 0, 0, 255));
+    }
+
+    glBindFramebuffer(GL_FRAMEBUFFER, mFbo);
+
+    EXPECT_TRUE(checkPixel( 24, 39, 0, 255, 0, 255));
+}
+
 } // namespace android
diff --git a/libs/ui/KeyCharacterMap.cpp b/libs/ui/KeyCharacterMap.cpp
index 2decfe9..77f18de 100644
--- a/libs/ui/KeyCharacterMap.cpp
+++ b/libs/ui/KeyCharacterMap.cpp
@@ -124,17 +124,6 @@
     return status;
 }
 
-status_t KeyCharacterMap::loadByDeviceId(int32_t deviceId, KeyCharacterMap** outMap) {
-    *outMap = NULL;
-
-    String8 filename;
-    status_t result = getKeyCharacterMapFile(deviceId, filename);
-    if (!result) {
-        result = load(filename, outMap);
-    }
-    return result;
-}
-
 int32_t KeyCharacterMap::getKeyboardType() const {
     return mType;
 }
diff --git a/libs/ui/Keyboard.cpp b/libs/ui/Keyboard.cpp
index 600a951..10bb39c 100644
--- a/libs/ui/Keyboard.cpp
+++ b/libs/ui/Keyboard.cpp
@@ -173,50 +173,6 @@
     return strstr(deviceIdentifier.name.string(), "-keypad");
 }
 
-void setKeyboardProperties(int32_t deviceId,
-        const InputDeviceIdentifier& deviceIdentifier,
-        const String8& keyLayoutFile, const String8& keyCharacterMapFile) {
-    char propName[PROPERTY_KEY_MAX];
-    snprintf(propName, sizeof(propName), "hw.keyboards.%u.devname", deviceId);
-    property_set(propName, deviceIdentifier.name.string());
-    snprintf(propName, sizeof(propName), "hw.keyboards.%u.klfile", deviceId);
-    property_set(propName, keyLayoutFile.string());
-    snprintf(propName, sizeof(propName), "hw.keyboards.%u.kcmfile", deviceId);
-    property_set(propName, keyCharacterMapFile.string());
-}
-
-void clearKeyboardProperties(int32_t deviceId) {
-    char propName[PROPERTY_KEY_MAX];
-    snprintf(propName, sizeof(propName), "hw.keyboards.%u.devname", deviceId);
-    property_set(propName, "");
-    snprintf(propName, sizeof(propName), "hw.keyboards.%u.klfile", deviceId);
-    property_set(propName, "");
-    snprintf(propName, sizeof(propName), "hw.keyboards.%u.kcmfile", deviceId);
-    property_set(propName, "");
-}
-
-status_t getKeyCharacterMapFile(int32_t deviceId, String8& outKeyCharacterMapFile) {
-    if (deviceId != DEVICE_ID_VIRTUAL_KEYBOARD) {
-        char propName[PROPERTY_KEY_MAX];
-        char fn[PROPERTY_VALUE_MAX];
-        snprintf(propName, sizeof(propName), "hw.keyboards.%u.kcmfile", deviceId);
-        if (property_get(propName, fn, "") > 0) {
-            outKeyCharacterMapFile.setTo(fn);
-            return OK;
-        }
-    }
-
-    // Default to Virtual since the keyboard does not appear to be installed.
-    outKeyCharacterMapFile.setTo(getInputDeviceConfigurationFilePathByName(String8("Virtual"),
-            INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_CHARACTER_MAP));
-    if (!outKeyCharacterMapFile.isEmpty()) {
-        return OK;
-    }
-
-    LOGE("Can't find any key character map files including the Virtual key map!");
-    return NAME_NOT_FOUND;
-}
-
 static int lookupValueByLabel(const char* literal, const KeycodeLabel *list) {
     while (list->literal) {
         if (strcmp(literal, list->literal) == 0) {
diff --git a/libs/utils/Android.mk b/libs/utils/Android.mk
index 638f72f..831d9e3 100644
--- a/libs/utils/Android.mk
+++ b/libs/utils/Android.mk
@@ -71,6 +71,10 @@
 endif
 endif
 
+ifeq ($(TARGET_OS),linux)
+LOCAL_LDLIBS += -lrt -ldl
+endif
+
 include $(BUILD_HOST_STATIC_LIBRARY)
 
 
diff --git a/libs/utils/BlobCache.cpp b/libs/utils/BlobCache.cpp
index 590576a..d38aae9 100644
--- a/libs/utils/BlobCache.cpp
+++ b/libs/utils/BlobCache.cpp
@@ -21,10 +21,20 @@
 #include <string.h>
 
 #include <utils/BlobCache.h>
+#include <utils/Errors.h>
 #include <utils/Log.h>
 
 namespace android {
 
+// BlobCache::Header::mMagicNumber value
+static const uint32_t blobCacheMagic = '_Bb$';
+
+// BlobCache::Header::mBlobCacheVersion value
+static const uint32_t blobCacheVersion = 1;
+
+// BlobCache::Header::mDeviceVersion value
+static const uint32_t blobCacheDeviceVersion = 1;
+
 BlobCache::BlobCache(size_t maxKeySize, size_t maxValueSize, size_t maxTotalSize):
         mMaxKeySize(maxKeySize),
         mMaxValueSize(maxValueSize),
@@ -67,12 +77,10 @@
         return;
     }
 
-    Mutex::Autolock lock(mMutex);
     sp<Blob> dummyKey(new Blob(key, keySize, false));
     CacheEntry dummyEntry(dummyKey, NULL);
 
     while (true) {
-
         ssize_t index = mCacheEntries.indexOf(dummyEntry);
         if (index < 0) {
             // Create a new cache entry.
@@ -129,7 +137,6 @@
                 keySize, mMaxKeySize);
         return 0;
     }
-    Mutex::Autolock lock(mMutex);
     sp<Blob> dummyKey(new Blob(key, keySize, false));
     CacheEntry dummyEntry(dummyKey, NULL);
     ssize_t index = mCacheEntries.indexOf(dummyEntry);
@@ -152,6 +159,133 @@
     return valueBlobSize;
 }
 
+static inline size_t align4(size_t size) {
+    return (size + 3) & ~3;
+}
+
+size_t BlobCache::getFlattenedSize() const {
+    size_t size = sizeof(Header);
+    for (size_t i = 0; i < mCacheEntries.size(); i++) {
+        const CacheEntry& e(mCacheEntries[i]);
+        sp<Blob> keyBlob = e.getKey();
+        sp<Blob> valueBlob = e.getValue();
+        size = align4(size);
+        size += sizeof(EntryHeader) + keyBlob->getSize() +
+                valueBlob->getSize();
+    }
+    return size;
+}
+
+size_t BlobCache::getFdCount() const {
+    return 0;
+}
+
+status_t BlobCache::flatten(void* buffer, size_t size, int fds[], size_t count)
+        const {
+    if (count != 0) {
+        LOGE("flatten: nonzero fd count: %d", count);
+        return BAD_VALUE;
+    }
+
+    // Write the cache header
+    if (size < sizeof(Header)) {
+        LOGE("flatten: not enough room for cache header");
+        return BAD_VALUE;
+    }
+    Header* header = reinterpret_cast<Header*>(buffer);
+    header->mMagicNumber = blobCacheMagic;
+    header->mBlobCacheVersion = blobCacheVersion;
+    header->mDeviceVersion = blobCacheDeviceVersion;
+    header->mNumEntries = mCacheEntries.size();
+
+    // Write cache entries
+    uint8_t* byteBuffer = reinterpret_cast<uint8_t*>(buffer);
+    off_t byteOffset = align4(sizeof(Header));
+    for (size_t i = 0; i < mCacheEntries.size(); i++) {
+        const CacheEntry& e(mCacheEntries[i]);
+        sp<Blob> keyBlob = e.getKey();
+        sp<Blob> valueBlob = e.getValue();
+        size_t keySize = keyBlob->getSize();
+        size_t valueSize = valueBlob->getSize();
+
+        size_t entrySize = sizeof(EntryHeader) + keySize + valueSize;
+        if (byteOffset + entrySize > size) {
+            LOGE("flatten: not enough room for cache entries");
+            return BAD_VALUE;
+        }
+
+        EntryHeader* eheader = reinterpret_cast<EntryHeader*>(
+            &byteBuffer[byteOffset]);
+        eheader->mKeySize = keySize;
+        eheader->mValueSize = valueSize;
+
+        memcpy(eheader->mData, keyBlob->getData(), keySize);
+        memcpy(eheader->mData + keySize, valueBlob->getData(), valueSize);
+
+        byteOffset += align4(entrySize);
+    }
+
+    return OK;
+}
+
+status_t BlobCache::unflatten(void const* buffer, size_t size, int fds[],
+        size_t count) {
+    // All errors should result in the BlobCache being in an empty state.
+    mCacheEntries.clear();
+
+    if (count != 0) {
+        LOGE("unflatten: nonzero fd count: %d", count);
+        return BAD_VALUE;
+    }
+
+    // Read the cache header
+    if (size < sizeof(Header)) {
+        LOGE("unflatten: not enough room for cache header");
+        return BAD_VALUE;
+    }
+    const Header* header = reinterpret_cast<const Header*>(buffer);
+    if (header->mMagicNumber != blobCacheMagic) {
+        LOGE("unflatten: bad magic number: %d", header->mMagicNumber);
+        return BAD_VALUE;
+    }
+    if (header->mBlobCacheVersion != blobCacheVersion ||
+            header->mDeviceVersion != blobCacheDeviceVersion) {
+        // We treat version mismatches as an empty cache.
+        return OK;
+    }
+
+    // Read cache entries
+    const uint8_t* byteBuffer = reinterpret_cast<const uint8_t*>(buffer);
+    off_t byteOffset = align4(sizeof(Header));
+    size_t numEntries = header->mNumEntries;
+    for (size_t i = 0; i < numEntries; i++) {
+        if (byteOffset + sizeof(EntryHeader) > size) {
+            mCacheEntries.clear();
+            LOGE("unflatten: not enough room for cache entry headers");
+            return BAD_VALUE;
+        }
+
+        const EntryHeader* eheader = reinterpret_cast<const EntryHeader*>(
+                &byteBuffer[byteOffset]);
+        size_t keySize = eheader->mKeySize;
+        size_t valueSize = eheader->mValueSize;
+        size_t entrySize = sizeof(EntryHeader) + keySize + valueSize;
+
+        if (byteOffset + entrySize > size) {
+            mCacheEntries.clear();
+            LOGE("unflatten: not enough room for cache entry headers");
+            return BAD_VALUE;
+        }
+
+        const uint8_t* data = eheader->mData;
+        set(data, keySize, data + keySize, valueSize);
+
+        byteOffset += align4(entrySize);
+    }
+
+    return OK;
+}
+
 long int BlobCache::blob_random() {
 #ifdef _WIN32
     return rand();
@@ -179,7 +313,7 @@
         mData(copyData ? malloc(size) : data),
         mSize(size),
         mOwnsData(copyData) {
-    if (copyData) {
+    if (data != NULL && copyData) {
         memcpy(const_cast<void*>(mData), data, size);
     }
 }
diff --git a/libs/utils/tests/BlobCache_test.cpp b/libs/utils/tests/BlobCache_test.cpp
index 653ea5e..b64cc39 100644
--- a/libs/utils/tests/BlobCache_test.cpp
+++ b/libs/utils/tests/BlobCache_test.cpp
@@ -14,9 +14,13 @@
  ** limitations under the License.
  */
 
+#include <fcntl.h>
+#include <stdio.h>
+
 #include <gtest/gtest.h>
 
 #include <utils/BlobCache.h>
+#include <utils/Errors.h>
 
 namespace android {
 
@@ -254,4 +258,164 @@
     ASSERT_EQ(maxEntries/2 + 1, numCached);
 }
 
+class BlobCacheFlattenTest : public BlobCacheTest {
+protected:
+    virtual void SetUp() {
+        BlobCacheTest::SetUp();
+        mBC2 = new BlobCache(MAX_KEY_SIZE, MAX_VALUE_SIZE, MAX_TOTAL_SIZE);
+    }
+
+    virtual void TearDown() {
+        mBC2.clear();
+        BlobCacheTest::TearDown();
+    }
+
+    void roundTrip() {
+        size_t size = mBC->getFlattenedSize();
+        uint8_t* flat = new uint8_t[size];
+        ASSERT_EQ(OK, mBC->flatten(flat, size, NULL, 0));
+        ASSERT_EQ(OK, mBC2->unflatten(flat, size, NULL, 0));
+        delete[] flat;
+    }
+
+    sp<BlobCache> mBC2;
+};
+
+TEST_F(BlobCacheFlattenTest, FlattenOneValue) {
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+    roundTrip();
+    ASSERT_EQ(size_t(4), mBC2->get("abcd", 4, buf, 4));
+    ASSERT_EQ('e', buf[0]);
+    ASSERT_EQ('f', buf[1]);
+    ASSERT_EQ('g', buf[2]);
+    ASSERT_EQ('h', buf[3]);
+}
+
+TEST_F(BlobCacheFlattenTest, FlattenFullCache) {
+    // Fill up the entire cache with 1 char key/value pairs.
+    const int maxEntries = MAX_TOTAL_SIZE / 2;
+    for (int i = 0; i < maxEntries; i++) {
+        uint8_t k = i;
+        mBC->set(&k, 1, &k, 1);
+    }
+
+    roundTrip();
+
+    // Verify the deserialized cache
+    for (int i = 0; i < maxEntries; i++) {
+        uint8_t k = i;
+        uint8_t v = 0xee;
+        ASSERT_EQ(size_t(1), mBC2->get(&k, 1, &v, 1));
+        ASSERT_EQ(k, v);
+    }
+}
+
+TEST_F(BlobCacheFlattenTest, FlattenDoesntChangeCache) {
+    // Fill up the entire cache with 1 char key/value pairs.
+    const int maxEntries = MAX_TOTAL_SIZE / 2;
+    for (int i = 0; i < maxEntries; i++) {
+        uint8_t k = i;
+        mBC->set(&k, 1, &k, 1);
+    }
+
+    size_t size = mBC->getFlattenedSize();
+    uint8_t* flat = new uint8_t[size];
+    ASSERT_EQ(OK, mBC->flatten(flat, size, NULL, 0));
+    delete[] flat;
+
+    // Verify the cache that we just serialized
+    for (int i = 0; i < maxEntries; i++) {
+        uint8_t k = i;
+        uint8_t v = 0xee;
+        ASSERT_EQ(size_t(1), mBC->get(&k, 1, &v, 1));
+        ASSERT_EQ(k, v);
+    }
+}
+
+TEST_F(BlobCacheFlattenTest, FlattenCatchesBufferTooSmall) {
+    // Fill up the entire cache with 1 char key/value pairs.
+    const int maxEntries = MAX_TOTAL_SIZE / 2;
+    for (int i = 0; i < maxEntries; i++) {
+        uint8_t k = i;
+        mBC->set(&k, 1, &k, 1);
+    }
+
+    size_t size = mBC->getFlattenedSize() - 1;
+    uint8_t* flat = new uint8_t[size];
+    ASSERT_EQ(BAD_VALUE, mBC->flatten(flat, size, NULL, 0));
+    delete[] flat;
+}
+
+TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadMagic) {
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+
+    size_t size = mBC->getFlattenedSize();
+    uint8_t* flat = new uint8_t[size];
+    ASSERT_EQ(OK, mBC->flatten(flat, size, NULL, 0));
+    flat[1] = ~flat[1];
+
+    // Bad magic should cause an error.
+    ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size, NULL, 0));
+    delete[] flat;
+
+    // The error should cause the unflatten to result in an empty cache
+    ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4));
+}
+
+TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheVersion) {
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+
+    size_t size = mBC->getFlattenedSize();
+    uint8_t* flat = new uint8_t[size];
+    ASSERT_EQ(OK, mBC->flatten(flat, size, NULL, 0));
+    flat[5] = ~flat[5];
+
+    // Version mismatches shouldn't cause errors, but should not use the
+    // serialized entries
+    ASSERT_EQ(OK, mBC2->unflatten(flat, size, NULL, 0));
+    delete[] flat;
+
+    // The version mismatch should cause the unflatten to result in an empty
+    // cache
+    ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4));
+}
+
+TEST_F(BlobCacheFlattenTest, UnflattenCatchesBadBlobCacheDeviceVersion) {
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+
+    size_t size = mBC->getFlattenedSize();
+    uint8_t* flat = new uint8_t[size];
+    ASSERT_EQ(OK, mBC->flatten(flat, size, NULL, 0));
+    flat[10] = ~flat[10];
+
+    // Version mismatches shouldn't cause errors, but should not use the
+    // serialized entries
+    ASSERT_EQ(OK, mBC2->unflatten(flat, size, NULL, 0));
+    delete[] flat;
+
+    // The version mismatch should cause the unflatten to result in an empty
+    // cache
+    ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4));
+}
+
+TEST_F(BlobCacheFlattenTest, UnflattenCatchesBufferTooSmall) {
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mBC->set("abcd", 4, "efgh", 4);
+
+    size_t size = mBC->getFlattenedSize();
+    uint8_t* flat = new uint8_t[size];
+    ASSERT_EQ(OK, mBC->flatten(flat, size, NULL, 0));
+
+    // A buffer truncation shouldt cause an error
+    ASSERT_EQ(BAD_VALUE, mBC2->unflatten(flat, size-1, NULL, 0));
+    delete[] flat;
+
+    // The error should cause the unflatten to result in an empty cache
+    ASSERT_EQ(size_t(0), mBC2->get("abcd", 4, buf, 4));
+}
+
 } // namespace android
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index a08932a..ca11863 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -229,14 +229,6 @@
 #define EGL_NATIVE_BUFFER_ANDROID               0x3140  /* eglCreateImageKHR target */
 #endif
 
-#ifndef EGL_ANDROID_swap_rectangle
-#define EGL_ANDROID_swap_rectangle 1
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean EGLAPIENTRY eglSetSwapRectangleANDROID (EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height);
-#endif /* EGL_EGLEXT_PROTOTYPES */
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETSWAPRECTANGLEANDROIDPROC) (EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height);
-#endif
-
 #ifndef EGL_ANDROID_recordable
 #define EGL_ANDROID_recordable 1
 #define EGL_RECORDABLE_ANDROID                  0x3142  /* EGLConfig attribute */
@@ -256,6 +248,21 @@
 typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMENVPROC)(void);
 #endif
 
+
+/* EGL_ANDROID_blob_cache
+ */
+#ifndef EGL_ANDROID_blob_cache
+#define EGL_ANDROID_blob_cache 1
+typedef khronos_ssize_t EGLsizeiANDROID;
+typedef void (*EGLSetBlobFuncANDROID) (const void* key, EGLsizeiANDROID keySize, const void* value, EGLsizeiANDROID valueSize);
+typedef EGLsizeiANDROID (*EGLGetBlobFuncANDROID) (const void* key, EGLsizeiANDROID keySize, void* value, EGLsizeiANDROID valueSize);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI void EGLAPIENTRY eglSetBlobCacheFuncsANDROID(EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef void (EGLAPIENTRYP PFNEGLSETBLOBCACHEFUNCSANDROIDPROC) (EGLDisplay dpy,
+        EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get);
+#endif
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 03db8d7..6d4098c 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -49,6 +49,11 @@
 #undef NELEM
 #define NELEM(x) (sizeof(x)/sizeof(*(x)))
 
+
+EGLBoolean EGLAPI eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
+        EGLint left, EGLint top, EGLint width, EGLint height);
+
+
 // ----------------------------------------------------------------------------
 namespace android {
 // ----------------------------------------------------------------------------
diff --git a/opengl/libagl2/Android.mk b/opengl/libagl2/Android.mk
deleted file mode 100644
index b442a2d..0000000
--- a/opengl/libagl2/Android.mk
+++ /dev/null
@@ -1,56 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-#
-# Build the software OpenGL ES library
-#
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	src/api.cpp \
-	src/egl.cpp \
-    src/get.cpp \
-	src/shader.cpp \
-	src/state.cpp \
-	src/texture.cpp \
-	src/vertex.cpp
-
-LOCAL_C_INCLUDES :=	\
-    $(LOCAL_PATH) \
-    external/mesa3d/include \
-    external/mesa3d/src \
-    external/stlport/stlport \
-    bionic
-    
-#LOCAL_CFLAGS += -DLOG_TAG=\"libagl2\"
-#LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-#LOCAL_CFLAGS += -fvisibility=hidden
-#LOCAL_CFLAGS += -O0 -g -DDEBUG -UNDEBUG
-LOCAL_CFLAGS += -O3
-LOCAL_STATIC_LIBRARIES := libMesa
-LOCAL_SHARED_LIBRARIES := libstlport libcutils libhardware libutils libbcc libdl
-LOCAL_LDLIBS := -lpthread
-
-ifeq ($(TARGET_ARCH),arm)
-	LOCAL_CFLAGS += -fstrict-aliasing
-endif
-
-ifeq ($(ARCH_ARM_HAVE_TLS_REGISTER),true)
-    LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
-endif
-
-# we need to access the private Bionic header <bionic_tls.h>
-# on ARM platforms, we need to mirror the ARCH_ARM_HAVE_TLS_REGISTER
-# behavior from the bionic Android.mk file
-ifeq ($(TARGET_ARCH)-$(ARCH_ARM_HAVE_TLS_REGISTER),arm-true)
-    LOCAL_CFLAGS += -DHAVE_ARM_TLS_REGISTER
-endif
-LOCAL_C_INCLUDES += bionic/libc/private
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/egl
-#replace libagl for now
-LOCAL_MODULE:= libGLES_android
-LOCAL_MODULE_TAGS := eng
-
-## Disable this makefile for now
-## include $(BUILD_SHARED_LIBRARY)
diff --git a/opengl/libagl2/README b/opengl/libagl2/README
deleted file mode 100644
index 34746d3..0000000
--- a/opengl/libagl2/README
+++ /dev/null
@@ -1,26 +0,0 @@
-libAgl2 provides software GL ES 2.0 implementation using Pixelflinger2 in external/mesa3d
-
-To build, enable Android.mk, which builds libGLES_android.so, then replace the one built from libAgl in system/lib/egl.
-ES 1.0 functions are not implemented and will cause exit, so do not setprop debug.egl.hw 0 until launcher is loaded.
-
-All functions have little to none error checking.
-Not thread safe, Pixelflinger2 uses some static data.
-
-Most shader functions are implemented, however, most Get* functions for shaders/programs/uniforms/attribs are not.
-No name system for shaders/programs, just using the pointers as names.
-
-Basic glTexImage2D, glTexSubImage2D, glCopyImage2D and glCopySubImage2D are implemented, with a range of 8/16/24/32bpp formats.
-Cube map support is minimal. No mipmapping.
-TexParameter is mostly implemented, supports texcoord wrap modes, and only linear for both min and mag, or nearest for both min and mag filtering.
-Texture names are implemented, but bad.
-
-Frame buffer and render buffers are not implemented.
-
-Depth and stencil are implemented, but not tested.
-Blending seems to work.
-Colorbuffer supports RGBA_8888 and RGB_565.
-
-Vertex buffer objects are implemented.
-Some GL_TRIANGLES and GL_TRIANGLE_STRIPS modes for glDrawArrays and glDrawElements are implemented, but vertex order is probably wrong so culling is disabled.
-
-Basic apps should work, and some libhwui should work, except for frame buffer operations, which will cause exit.
diff --git a/opengl/libagl2/libagl2.project b/opengl/libagl2/libagl2.project
deleted file mode 100644
index f234421..0000000
--- a/opengl/libagl2/libagl2.project
+++ /dev/null
@@ -1,108 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<CodeLite_Project Name="libagl2" InternalType="Console">
-  <Plugins>
-    <Plugin Name="qmake">
-      <![CDATA[00010001N0005Debug000000000000]]>
-    </Plugin>
-  </Plugins>
-  <Description/>
-  <Dependencies/>
-  <Dependencies Name="Release"/>
-  <VirtualDirectory Name="src">
-    <File Name="src/egl.cpp"/>
-    <File Name="src/api.cpp"/>
-    <File Name="src/gles2context.h"/>
-    <File Name="src/shader.cpp"/>
-    <File Name="src/vertex.cpp"/>
-    <File Name="src/state.cpp"/>
-    <File Name="src/texture.cpp"/>
-    <File Name="src/get.cpp"/>
-  </VirtualDirectory>
-  <VirtualDirectory Name="include"/>
-  <Settings Type="Executable">
-    <Configuration Name="Debug" CompilerType="gnu gcc" DebuggerType="GNU gdb debugger" Type="Executable" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
-      <Compiler Options="-g;-m32" Required="yes" PreCompiledHeader="">
-        <IncludePath Value="/usr/include/c++/4.4"/>
-        <IncludePath Value="/usr/include/c++/4.4/ext"/>
-        <IncludePath Value="."/>
-        <IncludePath Value="include"/>
-        <IncludePath Value="../../../../external/mesa3d/include"/>
-        <IncludePath Value="../../../../external/mesa3d/src"/>
-        <IncludePath Value="../../../../hardware/libhardware/include"/>
-        <IncludePath Value="../../../../system/core/include"/>
-        <IncludePath Value="../include"/>
-        <IncludePath Value="../../include"/>
-        <IncludePath Value="../../../../development/ndk/platforms/android-9/include"/>
-        <IncludePath Value="../../../../bionic/libc/include/"/>
-        <IncludePath Value="/../../../../development/ndk/platforms/android-5/arch-x86/include"/>
-        <IncludePath Value="../../../../bionic/libc/arch-x86/include"/>
-        <IncludePath Value="../../../../bionic/libc/kernel/arch-x86"/>
-        <IncludePath Value="/../../../../external/kernel-headers/original"/>
-        <IncludePath Value="../../../../prebuilt/ndk/android-ndk-r4/platforms/android-8/arch-x86/usr/include"/>
-      </Compiler>
-      <Linker Options="-m32;-lstdc++" Required="yes"/>
-      <ResourceCompiler Options="" Required="no"/>
-      <General OutputFile="$(IntermediateDirectory)/$(ProjectName)" IntermediateDirectory="./Debug" Command="./$(ProjectName)" CommandArguments="" WorkingDirectory="$(IntermediateDirectory)" PauseExecWhenProcTerminates="yes"/>
-      <Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="">
-        <PostConnectCommands/>
-        <StartupCommands/>
-      </Debugger>
-      <PreBuild/>
-      <PostBuild/>
-      <CustomBuild Enabled="no">
-        <RebuildCommand/>
-        <CleanCommand/>
-        <BuildCommand/>
-        <PreprocessFileCommand/>
-        <SingleFileCommand/>
-        <MakefileGenerationCommand/>
-        <ThirdPartyToolName>None</ThirdPartyToolName>
-        <WorkingDirectory/>
-      </CustomBuild>
-      <AdditionalRules>
-        <CustomPostBuild/>
-        <CustomPreBuild/>
-      </AdditionalRules>
-    </Configuration>
-    <Configuration Name="Release" CompilerType="gnu gcc" DebuggerType="GNU gdb debugger" Type="" BuildCmpWithGlobalSettings="append" BuildLnkWithGlobalSettings="append" BuildResWithGlobalSettings="append">
-      <Compiler Options="" Required="yes" PreCompiledHeader="">
-        <IncludePath Value="."/>
-      </Compiler>
-      <Linker Options="-O2" Required="yes"/>
-      <ResourceCompiler Options="" Required="no"/>
-      <General OutputFile="$(IntermediateDirectory)/$(ProjectName)" IntermediateDirectory="./Release" Command="./$(ProjectName)" CommandArguments="" WorkingDirectory="$(IntermediateDirectory)" PauseExecWhenProcTerminates="yes"/>
-      <Debugger IsRemote="no" RemoteHostName="" RemoteHostPort="" DebuggerPath="">
-        <PostConnectCommands/>
-        <StartupCommands/>
-      </Debugger>
-      <PreBuild/>
-      <PostBuild/>
-      <CustomBuild Enabled="no">
-        <RebuildCommand/>
-        <CleanCommand/>
-        <BuildCommand/>
-        <PreprocessFileCommand/>
-        <SingleFileCommand/>
-        <MakefileGenerationCommand/>
-        <ThirdPartyToolName>None</ThirdPartyToolName>
-        <WorkingDirectory/>
-      </CustomBuild>
-      <AdditionalRules>
-        <CustomPostBuild/>
-        <CustomPreBuild/>
-      </AdditionalRules>
-    </Configuration>
-    <GlobalSettings>
-      <Compiler Options="">
-        <IncludePath Value="."/>
-      </Compiler>
-      <Linker Options="">
-        <LibraryPath Value="."/>
-      </Linker>
-      <ResourceCompiler Options=""/>
-    </GlobalSettings>
-  </Settings>
-  <Dependencies Name="Debug">
-    <Project Name="libMesa"/>
-  </Dependencies>
-</CodeLite_Project>
diff --git a/opengl/libagl2/src/api.cpp b/opengl/libagl2/src/api.cpp
deleted file mode 100644
index bb8d62b..0000000
--- a/opengl/libagl2/src/api.cpp
+++ /dev/null
@@ -1,266 +0,0 @@
-#include "gles2context.h"
-
-#define API_ENTRY
-#define CALL_GL_API(NAME,...) LOGD("?"#NAME); assert(0);
-#define CALL_GL_API_RETURN(NAME,...) LOGD("?"#NAME); assert(0); return 0;
-
-
-void API_ENTRY(glBindFramebuffer)(GLenum target, GLuint framebuffer)
-{
-   CALL_GL_API(glBindFramebuffer, target, framebuffer);
-}
-void API_ENTRY(glBindRenderbuffer)(GLenum target, GLuint renderbuffer)
-{
-   CALL_GL_API(glBindRenderbuffer, target, renderbuffer);
-}
-GLenum API_ENTRY(glCheckFramebufferStatus)(GLenum target)
-{
-   CALL_GL_API_RETURN(glCheckFramebufferStatus, target);
-}
-void API_ENTRY(glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
-{
-   CALL_GL_API(glColorMask, red, green, blue, alpha);
-}
-void API_ENTRY(glDeleteFramebuffers)(GLsizei n, const GLuint* framebuffers)
-{
-   CALL_GL_API(glDeleteFramebuffers, n, framebuffers);
-}
-void API_ENTRY(glDeleteRenderbuffers)(GLsizei n, const GLuint* renderbuffers)
-{
-   CALL_GL_API(glDeleteRenderbuffers, n, renderbuffers);
-}
-void API_ENTRY(glDepthFunc)(GLenum func)
-{
-   CALL_GL_API(glDepthFunc, func);
-}
-void API_ENTRY(glDepthMask)(GLboolean flag)
-{
-   CALL_GL_API(glDepthMask, flag);
-}
-void API_ENTRY(glDepthRangef)(GLclampf zNear, GLclampf zFar)
-{
-   CALL_GL_API(glDepthRangef, zNear, zFar);
-}
-void API_ENTRY(glFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
-{
-   CALL_GL_API(glFramebufferRenderbuffer, target, attachment, renderbuffertarget, renderbuffer);
-}
-void API_ENTRY(glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
-{
-   CALL_GL_API(glFramebufferTexture2D, target, attachment, textarget, texture, level);
-}
-void glGenerateMipmap(GLenum target)
-{
-   //CALL_GL_API(glGenerateMipmap, target);
-   LOGD("agl2: glGenerateMipmap not implemented");
-}
-void API_ENTRY(glGenFramebuffers)(GLsizei n, GLuint* framebuffers)
-{
-   CALL_GL_API(glGenFramebuffers, n, framebuffers);
-}
-void API_ENTRY(glGenRenderbuffers)(GLsizei n, GLuint* renderbuffers)
-{
-   CALL_GL_API(glGenRenderbuffers, n, renderbuffers);
-}
-void API_ENTRY(glGetActiveAttrib)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
-{
-   CALL_GL_API(glGetActiveAttrib, program, index, bufsize, length, size, type, name);
-}
-void API_ENTRY(glGetActiveUniform)(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name)
-{
-   CALL_GL_API(glGetActiveUniform, program, index, bufsize, length, size, type, name);
-}
-void API_ENTRY(glGetAttachedShaders)(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders)
-{
-   CALL_GL_API(glGetAttachedShaders, program, maxcount, count, shaders);
-}
-void API_ENTRY(glGetBooleanv)(GLenum pname, GLboolean* params)
-{
-   CALL_GL_API(glGetBooleanv, pname, params);
-}
-void API_ENTRY(glGetBufferParameteriv)(GLenum target, GLenum pname, GLint* params)
-{
-   CALL_GL_API(glGetBufferParameteriv, target, pname, params);
-}
-GLenum glGetError(void)
-{
-   puts("agl2: glGetError");
-   return GL_NO_ERROR;
-   //CALL_GL_API_RETURN(glGetError);
-}
-void API_ENTRY(glGetFloatv)(GLenum pname, GLfloat* params)
-{
-   CALL_GL_API(glGetFloatv, pname, params);
-}
-void API_ENTRY(glGetFramebufferAttachmentParameteriv)(GLenum target, GLenum attachment, GLenum pname, GLint* params)
-{
-   CALL_GL_API(glGetFramebufferAttachmentParameteriv, target, attachment, pname, params);
-}
-void API_ENTRY(glGetRenderbufferParameteriv)(GLenum target, GLenum pname, GLint* params)
-{
-   CALL_GL_API(glGetRenderbufferParameteriv, target, pname, params);
-}
-void API_ENTRY(glGetShaderPrecisionFormat)(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision)
-{
-   CALL_GL_API(glGetShaderPrecisionFormat, shadertype, precisiontype, range, precision);
-}
-void API_ENTRY(glGetShaderSource)(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source)
-{
-   CALL_GL_API(glGetShaderSource, shader, bufsize, length, source);
-}
-void API_ENTRY(glGetUniformfv)(GLuint program, GLint location, GLfloat* params)
-{
-   CALL_GL_API(glGetUniformfv, program, location, params);
-}
-void API_ENTRY(glGetUniformiv)(GLuint program, GLint location, GLint* params)
-{
-   CALL_GL_API(glGetUniformiv, program, location, params);
-}
-void API_ENTRY(glGetVertexAttribfv)(GLuint index, GLenum pname, GLfloat* params)
-{
-   CALL_GL_API(glGetVertexAttribfv, index, pname, params);
-}
-void API_ENTRY(glGetVertexAttribiv)(GLuint index, GLenum pname, GLint* params)
-{
-   CALL_GL_API(glGetVertexAttribiv, index, pname, params);
-}
-void API_ENTRY(glGetVertexAttribPointerv)(GLuint index, GLenum pname, GLvoid** pointer)
-{
-   CALL_GL_API(glGetVertexAttribPointerv, index, pname, pointer);
-}
-GLboolean API_ENTRY(glIsBuffer)(GLuint buffer)
-{
-   CALL_GL_API_RETURN(glIsBuffer, buffer);
-}
-GLboolean API_ENTRY(glIsEnabled)(GLenum cap)
-{
-   CALL_GL_API_RETURN(glIsEnabled, cap);
-}
-GLboolean API_ENTRY(glIsFramebuffer)(GLuint framebuffer)
-{
-   CALL_GL_API_RETURN(glIsFramebuffer, framebuffer);
-}
-GLboolean API_ENTRY(glIsProgram)(GLuint program)
-{
-   CALL_GL_API_RETURN(glIsProgram, program);
-}
-GLboolean API_ENTRY(glIsRenderbuffer)(GLuint renderbuffer)
-{
-   CALL_GL_API_RETURN(glIsRenderbuffer, renderbuffer);
-}
-GLboolean API_ENTRY(glIsShader)(GLuint shader)
-{
-   CALL_GL_API_RETURN(glIsShader, shader);
-}
-void API_ENTRY(glLineWidth)(GLfloat width)
-{
-   CALL_GL_API(glLineWidth, width);
-}
-void API_ENTRY(glPolygonOffset)(GLfloat factor, GLfloat units)
-{
-   CALL_GL_API(glPolygonOffset, factor, units);
-}
-void API_ENTRY(glReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels)
-{
-   CALL_GL_API(glReadPixels, x, y, width, height, format, type, pixels);
-}
-void API_ENTRY(glReleaseShaderCompiler)(void)
-{
-   CALL_GL_API(glReleaseShaderCompiler);
-}
-void API_ENTRY(glRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
-{
-   CALL_GL_API(glRenderbufferStorage, target, internalformat, width, height);
-}
-void API_ENTRY(glSampleCoverage)(GLclampf value, GLboolean invert)
-{
-   CALL_GL_API(glSampleCoverage, value, invert);
-}
-void API_ENTRY(glShaderBinary)(GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length)
-{
-   CALL_GL_API(glShaderBinary, n, shaders, binaryformat, binary, length);
-}
-void API_ENTRY(glStencilFunc)(GLenum func, GLint ref, GLuint mask)
-{
-   CALL_GL_API(glStencilFunc, func, ref, mask);
-}
-void API_ENTRY(glStencilFuncSeparate)(GLenum face, GLenum func, GLint ref, GLuint mask)
-{
-   CALL_GL_API(glStencilFuncSeparate, face, func, ref, mask);
-}
-void API_ENTRY(glStencilMask)(GLuint mask)
-{
-   CALL_GL_API(glStencilMask, mask);
-}
-void API_ENTRY(glStencilMaskSeparate)(GLenum face, GLuint mask)
-{
-   CALL_GL_API(glStencilMaskSeparate, face, mask);
-}
-void API_ENTRY(glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass)
-{
-   CALL_GL_API(glStencilOp, fail, zfail, zpass);
-}
-void API_ENTRY(glStencilOpSeparate)(GLenum face, GLenum fail, GLenum zfail, GLenum zpass)
-{
-   CALL_GL_API(glStencilOpSeparate, face, fail, zfail, zpass);
-}
-void API_ENTRY(glUniform1fv)(GLint location, GLsizei count, const GLfloat* v)
-{
-   CALL_GL_API(glUniform1fv, location, count, v);
-}
-void API_ENTRY(glUniform1iv)(GLint location, GLsizei count, const GLint* v)
-{
-   CALL_GL_API(glUniform1iv, location, count, v);
-}
-void API_ENTRY(glUniform2fv)(GLint location, GLsizei count, const GLfloat* v)
-{
-   CALL_GL_API(glUniform2fv, location, count, v);
-}
-void API_ENTRY(glUniform2i)(GLint location, GLint x, GLint y)
-{
-   CALL_GL_API(glUniform2i, location, x, y);
-}
-void API_ENTRY(glUniform2iv)(GLint location, GLsizei count, const GLint* v)
-{
-   CALL_GL_API(glUniform2iv, location, count, v);
-}
-void API_ENTRY(glUniform3f)(GLint location, GLfloat x, GLfloat y, GLfloat z)
-{
-   CALL_GL_API(glUniform3f, location, x, y, z);
-}
-void API_ENTRY(glUniform3fv)(GLint location, GLsizei count, const GLfloat* v)
-{
-   CALL_GL_API(glUniform3fv, location, count, v);
-}
-void API_ENTRY(glUniform3i)(GLint location, GLint x, GLint y, GLint z)
-{
-   CALL_GL_API(glUniform3i, location, x, y, z);
-}
-void API_ENTRY(glUniform3iv)(GLint location, GLsizei count, const GLint* v)
-{
-   CALL_GL_API(glUniform3iv, location, count, v);
-}
-void API_ENTRY(glUniform4fv)(GLint location, GLsizei count, const GLfloat* v)
-{
-   CALL_GL_API(glUniform4fv, location, count, v);
-}
-void API_ENTRY(glUniform4i)(GLint location, GLint x, GLint y, GLint z, GLint w)
-{
-   CALL_GL_API(glUniform4i, location, x, y, z, w);
-}
-void API_ENTRY(glUniform4iv)(GLint location, GLsizei count, const GLint* v)
-{
-   CALL_GL_API(glUniform4iv, location, count, v);
-}
-void API_ENTRY(glUniformMatrix2fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
-{
-   CALL_GL_API(glUniformMatrix2fv, location, count, transpose, value);
-}
-void API_ENTRY(glUniformMatrix3fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
-{
-   CALL_GL_API(glUniformMatrix3fv, location, count, transpose, value);
-}
-void API_ENTRY(glValidateProgram)(GLuint program)
-{
-   CALL_GL_API(glValidateProgram, program);
-}
diff --git a/opengl/libagl2/src/egl.cpp b/opengl/libagl2/src/egl.cpp
deleted file mode 100644
index 0d02ce6..0000000
--- a/opengl/libagl2/src/egl.cpp
+++ /dev/null
@@ -1,2172 +0,0 @@
-/*
- **
- ** Copyright 2007 The Android Open Source Project
- **
- ** Licensed under the Apache License Version 2.0(the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- **     http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing software
- ** distributed under the License is distributed on an "AS IS" BASIS
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
-
-#include <errno.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-
-#include <cutils/atomic.h>
-
-
-#include <private/ui/android_natives_priv.h>
-
-#include "gles2context.h"
-
-// ----------------------------------------------------------------------------
-namespace android
-{
-// ----------------------------------------------------------------------------
-
-const unsigned int NUM_DISPLAYS = 1;
-
-static pthread_mutex_t gInitMutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t gErrorKeyMutex = PTHREAD_MUTEX_INITIALIZER;
-static pthread_key_t gEGLErrorKey = -1;
-#ifndef HAVE_ANDROID_OS
-namespace gl {
-pthread_key_t gGLKey = -1;
-}; // namespace gl
-#endif
-
-template<typename T>
-static T setError(GLint error, T returnValue)
-{
-    if (ggl_unlikely(gEGLErrorKey == -1)) {
-        pthread_mutex_lock(&gErrorKeyMutex);
-        if (gEGLErrorKey == -1)
-            pthread_key_create(&gEGLErrorKey, NULL);
-        pthread_mutex_unlock(&gErrorKeyMutex);
-    }
-    pthread_setspecific(gEGLErrorKey, (void*)error);
-    return returnValue;
-}
-
-static GLint getError()
-{
-    if (ggl_unlikely(gEGLErrorKey == -1))
-        return EGL_SUCCESS;
-    GLint error = (GLint)pthread_getspecific(gEGLErrorKey);
-    if (error == 0) {
-        // The TLS key has been created by another thread, but the value for
-        // this thread has not been initialized.
-        return EGL_SUCCESS;
-    }
-    pthread_setspecific(gEGLErrorKey, (void*)EGL_SUCCESS);
-    return error;
-}
-
-// ----------------------------------------------------------------------------
-
-struct egl_display_t {
-    egl_display_t() : type(0), initialized(0) { }
-
-    static egl_display_t& get_display(EGLDisplay dpy);
-
-    static EGLBoolean is_valid(EGLDisplay dpy) {
-        return ((uintptr_t(dpy)-1U) >= NUM_DISPLAYS) ? EGL_FALSE : EGL_TRUE;
-    }
-
-    NativeDisplayType   type;
-    volatile int32_t    initialized;
-};
-
-static egl_display_t gDisplays[NUM_DISPLAYS];
-
-egl_display_t& egl_display_t::get_display(EGLDisplay dpy)
-{
-    return gDisplays[uintptr_t(dpy)-1U];
-}
-
-// ----------------------------------------------------------------------------
-
-struct egl_surface_t {
-    enum {
-        PAGE_FLIP = 0x00000001,
-        MAGIC     = 0x31415265
-    };
-
-    uint32_t            magic;
-    EGLDisplay          dpy;
-    EGLConfig           config;
-    EGLContext          ctx;
-
-    egl_surface_t(EGLDisplay dpy, EGLConfig config, int32_t depthFormat);
-    virtual     ~egl_surface_t();
-    bool    isValid() const;
-    virtual     bool    initCheck() const = 0;
-
-    virtual     EGLBoolean  bindDrawSurface(GLES2Context* gl) = 0;
-    virtual     EGLBoolean  bindReadSurface(GLES2Context* gl) = 0;
-    virtual     EGLBoolean  connect() {
-        return EGL_TRUE;
-    }
-    virtual     void        disconnect() {}
-    virtual     EGLint      getWidth() const = 0;
-    virtual     EGLint      getHeight() const = 0;
-
-    virtual     EGLint      getHorizontalResolution() const;
-    virtual     EGLint      getVerticalResolution() const;
-    virtual     EGLint      getRefreshRate() const;
-    virtual     EGLint      getSwapBehavior() const;
-    virtual     EGLBoolean  swapBuffers();
-    virtual     EGLBoolean  setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
-protected:
-    GGLSurface              depth;
-};
-
-egl_surface_t::egl_surface_t(EGLDisplay dpy,
-        EGLConfig config,
-        int32_t depthFormat)
-: magic(MAGIC), dpy(dpy), config(config), ctx(0)
-{
-    depth.version = sizeof(GGLSurface);
-    depth.data = 0;
-    depth.format = (GGLPixelFormat)depthFormat;
-}
-egl_surface_t::~egl_surface_t()
-{
-    magic = 0;
-    free(depth.data);
-}
-bool egl_surface_t::isValid() const
-{
-    LOGE_IF(magic != MAGIC, "invalid EGLSurface (%p)", this);
-    return magic == MAGIC;
-}
-
-EGLBoolean egl_surface_t::swapBuffers()
-{
-    return EGL_FALSE;
-}
-EGLint egl_surface_t::getHorizontalResolution() const
-{
-    return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
-}
-EGLint egl_surface_t::getVerticalResolution() const
-{
-    return (0 * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
-}
-EGLint egl_surface_t::getRefreshRate() const
-{
-    return (60 * EGL_DISPLAY_SCALING);
-}
-EGLint egl_surface_t::getSwapBehavior() const
-{
-    return EGL_BUFFER_PRESERVED;
-}
-EGLBoolean egl_surface_t::setSwapRectangle(
-        EGLint l, EGLint t, EGLint w, EGLint h)
-{
-    return EGL_FALSE;
-}
-
-// ----------------------------------------------------------------------------
-
-struct egl_window_surface_v2_t : public egl_surface_t {
-    egl_window_surface_v2_t(
-            EGLDisplay dpy, EGLConfig config,
-            int32_t depthFormat,
-            ANativeWindow* window);
-
-    ~egl_window_surface_v2_t();
-
-    virtual     bool        initCheck() const {
-        return true;   // TODO: report failure if ctor fails
-    }
-    virtual     EGLBoolean  swapBuffers();
-    virtual     EGLBoolean  bindDrawSurface(GLES2Context* gl);
-    virtual     EGLBoolean  bindReadSurface(GLES2Context* gl);
-    virtual     EGLBoolean  connect();
-    virtual     void        disconnect();
-    virtual     EGLint      getWidth() const    {
-        return width;
-    }
-    virtual     EGLint      getHeight() const   {
-        return height;
-    }
-    virtual     EGLint      getHorizontalResolution() const;
-    virtual     EGLint      getVerticalResolution() const;
-    virtual     EGLint      getRefreshRate() const;
-    virtual     EGLint      getSwapBehavior() const;
-    virtual     EGLBoolean  setSwapRectangle(EGLint l, EGLint t, EGLint w, EGLint h);
-
-private:
-    status_t lock(ANativeWindowBuffer* buf, int usage, void** vaddr);
-    status_t unlock(ANativeWindowBuffer* buf);
-    ANativeWindow*   nativeWindow;
-    ANativeWindowBuffer*   buffer;
-    ANativeWindowBuffer*   previousBuffer;
-    gralloc_module_t const*    module;
-    int width;
-    int height;
-    void* bits;
-    GGLFormat const* pixelFormatTable;
-
-    struct Rect {
-        inline Rect() { };
-        inline Rect(int32_t w, int32_t h)
-        : left(0), top(0), right(w), bottom(h) { }
-        inline Rect(int32_t l, int32_t t, int32_t r, int32_t b)
-        : left(l), top(t), right(r), bottom(b) { }
-        Rect& andSelf(const Rect& r) {
-            left   = max(left, r.left);
-            top    = max(top, r.top);
-            right  = min(right, r.right);
-            bottom = min(bottom, r.bottom);
-            return *this;
-        }
-        bool isEmpty() const {
-            return (left>=right || top>=bottom);
-        }
-        void dump(char const* what) {
-            LOGD("%s { %5d, %5d, w=%5d, h=%5d }",
-                    what, left, top, right-left, bottom-top);
-        }
-
-        int32_t left;
-        int32_t top;
-        int32_t right;
-        int32_t bottom;
-    };
-
-    struct Region {
-        inline Region() : count(0) { }
-        typedef Rect const* const_iterator;
-        const_iterator begin() const {
-            return storage;
-        }
-        const_iterator end() const {
-            return storage+count;
-        }
-        static Region subtract(const Rect& lhs, const Rect& rhs) {
-            Region reg;
-            Rect* storage = reg.storage;
-            if (!lhs.isEmpty()) {
-                if (lhs.top < rhs.top) { // top rect
-                    storage->left   = lhs.left;
-                    storage->top    = lhs.top;
-                    storage->right  = lhs.right;
-                    storage->bottom = rhs.top;
-                    storage++;
-                }
-                const int32_t top = max(lhs.top, rhs.top);
-                const int32_t bot = min(lhs.bottom, rhs.bottom);
-                if (top < bot) {
-                    if (lhs.left < rhs.left) { // left-side rect
-                        storage->left   = lhs.left;
-                        storage->top    = top;
-                        storage->right  = rhs.left;
-                        storage->bottom = bot;
-                        storage++;
-                    }
-                    if (lhs.right > rhs.right) { // right-side rect
-                        storage->left   = rhs.right;
-                        storage->top    = top;
-                        storage->right  = lhs.right;
-                        storage->bottom = bot;
-                        storage++;
-                    }
-                }
-                if (lhs.bottom > rhs.bottom) { // bottom rect
-                    storage->left   = lhs.left;
-                    storage->top    = rhs.bottom;
-                    storage->right  = lhs.right;
-                    storage->bottom = lhs.bottom;
-                    storage++;
-                }
-                reg.count = storage - reg.storage;
-            }
-            return reg;
-        }
-        bool isEmpty() const {
-            return count<=0;
-        }
-    private:
-        Rect storage[4];
-        ssize_t count;
-    };
-
-    void copyBlt(
-            ANativeWindowBuffer* dst, void* dst_vaddr,
-            ANativeWindowBuffer* src, void const* src_vaddr,
-            const Region& clip);
-
-    Rect dirtyRegion;
-    Rect oldDirtyRegion;
-};
-
-egl_window_surface_v2_t::egl_window_surface_v2_t(EGLDisplay dpy,
-        EGLConfig config,
-        int32_t depthFormat,
-        ANativeWindow* window)
-: egl_surface_t(dpy, config, depthFormat),
-  nativeWindow(window), buffer(0), previousBuffer(0), module(0),
-  bits(NULL)
-{
-    pixelFormatTable = gglGetPixelFormatTable();
-
-    // keep a reference on the window
-    nativeWindow->common.incRef(&nativeWindow->common);
-    nativeWindow->query(nativeWindow, NATIVE_WINDOW_WIDTH, &width);
-    nativeWindow->query(nativeWindow, NATIVE_WINDOW_HEIGHT, &height);
-    int format = 0;
-    nativeWindow->query(nativeWindow, NATIVE_WINDOW_FORMAT, &format);
-    LOGD("agl2: egl_window_surface_v2_t format=0x%.4X", format);
-    //   assert(0);
-}
-
-egl_window_surface_v2_t::~egl_window_surface_v2_t()
-{
-    if (buffer) {
-        buffer->common.decRef(&buffer->common);
-    }
-    if (previousBuffer) {
-        previousBuffer->common.decRef(&previousBuffer->common);
-    }
-    nativeWindow->common.decRef(&nativeWindow->common);
-}
-
-EGLBoolean egl_window_surface_v2_t::connect()
-{
-    // we're intending to do software rendering
-    native_window_set_usage(nativeWindow,
-            GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
-
-    // dequeue a buffer
-    if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) != NO_ERROR) {
-        return setError(EGL_BAD_ALLOC, EGL_FALSE);
-    }
-
-    // allocate a corresponding depth-buffer
-    width = buffer->width;
-    height = buffer->height;
-    if (depth.format) {
-        depth.width   = width;
-        depth.height  = height;
-        depth.stride  = depth.width; // use the width here
-        assert(GGL_PIXEL_FORMAT_Z_32 == depth.format);
-        depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*4);
-        if (depth.data == 0) {
-            return setError(EGL_BAD_ALLOC, EGL_FALSE);
-        }
-    }
-
-    // keep a reference on the buffer
-    buffer->common.incRef(&buffer->common);
-
-    // Lock the buffer
-    nativeWindow->lockBuffer(nativeWindow, buffer);
-    // pin the buffer down
-    if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
-            GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
-        LOGE("connect() failed to lock buffer %p (%ux%u)",
-                buffer, buffer->width, buffer->height);
-        return setError(EGL_BAD_ACCESS, EGL_FALSE);
-        // FIXME: we should make sure we're not accessing the buffer anymore
-    }
-    return EGL_TRUE;
-}
-
-void egl_window_surface_v2_t::disconnect()
-{
-    if (buffer && bits) {
-        bits = NULL;
-        unlock(buffer);
-    }
-    // enqueue the last frame
-    if (buffer)
-        nativeWindow->queueBuffer(nativeWindow, buffer);
-    if (buffer) {
-        buffer->common.decRef(&buffer->common);
-        buffer = 0;
-    }
-    if (previousBuffer) {
-        previousBuffer->common.decRef(&previousBuffer->common);
-        previousBuffer = 0;
-    }
-}
-
-status_t egl_window_surface_v2_t::lock(
-        ANativeWindowBuffer* buf, int usage, void** vaddr)
-{
-    int err;
-
-    err = module->lock(module, buf->handle,
-            usage, 0, 0, buf->width, buf->height, vaddr);
-
-    return err;
-}
-
-status_t egl_window_surface_v2_t::unlock(ANativeWindowBuffer* buf)
-{
-    if (!buf) return BAD_VALUE;
-    int err = NO_ERROR;
-
-    err = module->unlock(module, buf->handle);
-
-    return err;
-}
-
-void egl_window_surface_v2_t::copyBlt(
-        ANativeWindowBuffer* dst, void* dst_vaddr,
-        ANativeWindowBuffer* src, void const* src_vaddr,
-        const Region& clip)
-{
-    // NOTE: dst and src must be the same format
-
-    Region::const_iterator cur = clip.begin();
-    Region::const_iterator end = clip.end();
-
-    const size_t bpp = pixelFormatTable[src->format].size;
-    const size_t dbpr = dst->stride * bpp;
-    const size_t sbpr = src->stride * bpp;
-
-    uint8_t const * const src_bits = (uint8_t const *)src_vaddr;
-    uint8_t       * const dst_bits = (uint8_t       *)dst_vaddr;
-
-    while (cur != end) {
-        const Rect& r(*cur++);
-        ssize_t w = r.right - r.left;
-        ssize_t h = r.bottom - r.top;
-        if (w <= 0 || h<=0) continue;
-        size_t size = w * bpp;
-        uint8_t const * s = src_bits + (r.left + src->stride * r.top) * bpp;
-        uint8_t       * d = dst_bits + (r.left + dst->stride * r.top) * bpp;
-        if (dbpr==sbpr && size==sbpr) {
-            size *= h;
-            h = 1;
-        }
-        do {
-            memcpy(d, s, size);
-            d += dbpr;
-            s += sbpr;
-        } while (--h > 0);
-    }
-}
-
-EGLBoolean egl_window_surface_v2_t::swapBuffers()
-{
-    if (!buffer) {
-        return setError(EGL_BAD_ACCESS, EGL_FALSE);
-    }
-
-    /*
-     * Handle eglSetSwapRectangleANDROID()
-     * We copyback from the front buffer
-     */
-    if (!dirtyRegion.isEmpty()) {
-        dirtyRegion.andSelf(Rect(buffer->width, buffer->height));
-        if (previousBuffer) {
-            // This was const Region copyBack, but that causes an
-            // internal compile error on simulator builds
-            /*const*/
-            Region copyBack(Region::subtract(oldDirtyRegion, dirtyRegion));
-            if (!copyBack.isEmpty()) {
-                void* prevBits;
-                if (lock(previousBuffer,
-                        GRALLOC_USAGE_SW_READ_OFTEN, &prevBits) == NO_ERROR) {
-                    // copy from previousBuffer to buffer
-                    copyBlt(buffer, bits, previousBuffer, prevBits, copyBack);
-                    unlock(previousBuffer);
-                }
-            }
-        }
-        oldDirtyRegion = dirtyRegion;
-    }
-
-    if (previousBuffer) {
-        previousBuffer->common.decRef(&previousBuffer->common);
-        previousBuffer = 0;
-    }
-
-    unlock(buffer);
-    previousBuffer = buffer;
-    nativeWindow->queueBuffer(nativeWindow, buffer);
-    buffer = 0;
-
-    // dequeue a new buffer
-    if (nativeWindow->dequeueBuffer(nativeWindow, &buffer) == NO_ERROR) {
-
-        // TODO: lockBuffer should rather be executed when the very first
-        // direct rendering occurs.
-        nativeWindow->lockBuffer(nativeWindow, buffer);
-
-        // reallocate the depth-buffer if needed
-        if ((width != buffer->width) || (height != buffer->height)) {
-            // TODO: we probably should reset the swap rect here
-            // if the window size has changed
-            width = buffer->width;
-            height = buffer->height;
-            if (depth.data) {
-                free(depth.data);
-                depth.width   = width;
-                depth.height  = height;
-                depth.stride  = buffer->stride;
-                depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
-                if (depth.data == 0) {
-                    setError(EGL_BAD_ALLOC, EGL_FALSE);
-                    return EGL_FALSE;
-                }
-            }
-        }
-
-        // keep a reference on the buffer
-        buffer->common.incRef(&buffer->common);
-
-        // finally pin the buffer down
-        if (lock(buffer, GRALLOC_USAGE_SW_READ_OFTEN |
-                GRALLOC_USAGE_SW_WRITE_OFTEN, &bits) != NO_ERROR) {
-            LOGE("eglSwapBuffers() failed to lock buffer %p (%ux%u)",
-                    buffer, buffer->width, buffer->height);
-            return setError(EGL_BAD_ACCESS, EGL_FALSE);
-            // FIXME: we should make sure we're not accessing the buffer anymore
-        }
-    } else {
-        return setError(EGL_BAD_CURRENT_SURFACE, EGL_FALSE);
-    }
-
-    return EGL_TRUE;
-}
-
-EGLBoolean egl_window_surface_v2_t::setSwapRectangle(
-        EGLint l, EGLint t, EGLint w, EGLint h)
-{
-    dirtyRegion = Rect(l, t, l+w, t+h);
-    return EGL_TRUE;
-}
-
-EGLBoolean egl_window_surface_v2_t::bindDrawSurface(GLES2Context* gl)
-{
-    GGLSurface buffer;
-    buffer.version = sizeof(GGLSurface);
-    buffer.width   = this->buffer->width;
-    buffer.height  = this->buffer->height;
-    buffer.stride  = this->buffer->stride;
-    buffer.data    = (GGLubyte*)bits;
-    buffer.format  = (GGLPixelFormat)this->buffer->format;
-    gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_COLOR_BUFFER_BIT, &buffer);
-    if (depth.data != gl->rasterizer.depthSurface.data)
-        gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_DEPTH_BUFFER_BIT, &depth);
-
-    return EGL_TRUE;
-}
-EGLBoolean egl_window_surface_v2_t::bindReadSurface(GLES2Context* gl)
-{
-    GGLSurface buffer;
-    buffer.version = sizeof(GGLSurface);
-    buffer.width   = this->buffer->width;
-    buffer.height  = this->buffer->height;
-    buffer.stride  = this->buffer->stride;
-    buffer.data    = (GGLubyte*)bits; // FIXME: hopefully is is LOCKED!!!
-    buffer.format  = (GGLPixelFormat)this->buffer->format;
-    puts("agl2: readBuffer not implemented");
-    //gl->rasterizer.interface.readBuffer(gl, &buffer);
-    return EGL_TRUE;
-}
-EGLint egl_window_surface_v2_t::getHorizontalResolution() const
-{
-    return (nativeWindow->xdpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
-}
-EGLint egl_window_surface_v2_t::getVerticalResolution() const
-{
-    return (nativeWindow->ydpi * EGL_DISPLAY_SCALING) * (1.0f / 25.4f);
-}
-EGLint egl_window_surface_v2_t::getRefreshRate() const
-{
-    return (60 * EGL_DISPLAY_SCALING); // FIXME
-}
-EGLint egl_window_surface_v2_t::getSwapBehavior() const
-{
-    /*
-     * EGL_BUFFER_PRESERVED means that eglSwapBuffers() completely preserves
-     * the content of the swapped buffer.
-     *
-     * EGL_BUFFER_DESTROYED means that the content of the buffer is lost.
-     *
-     * However when ANDROID_swap_retcangle is supported, EGL_BUFFER_DESTROYED
-     * only applies to the area specified by eglSetSwapRectangleANDROID(), that
-     * is, everything outside of this area is preserved.
-     *
-     * This implementation of EGL assumes the later case.
-     *
-     */
-
-    return EGL_BUFFER_DESTROYED;
-}
-
-// ----------------------------------------------------------------------------
-
-struct egl_pixmap_surface_t : public egl_surface_t {
-    egl_pixmap_surface_t(
-            EGLDisplay dpy, EGLConfig config,
-            int32_t depthFormat,
-            egl_native_pixmap_t const * pixmap);
-
-    virtual ~egl_pixmap_surface_t() { }
-
-    virtual     bool        initCheck() const {
-        return !depth.format || depth.data!=0;
-    }
-    virtual     EGLBoolean  bindDrawSurface(GLES2Context* gl);
-    virtual     EGLBoolean  bindReadSurface(GLES2Context* gl);
-    virtual     EGLint      getWidth() const    {
-        return nativePixmap.width;
-    }
-    virtual     EGLint      getHeight() const   {
-        return nativePixmap.height;
-    }
-private:
-    egl_native_pixmap_t     nativePixmap;
-};
-
-egl_pixmap_surface_t::egl_pixmap_surface_t(EGLDisplay dpy,
-        EGLConfig config,
-        int32_t depthFormat,
-        egl_native_pixmap_t const * pixmap)
-: egl_surface_t(dpy, config, depthFormat), nativePixmap(*pixmap)
-{
-    if (depthFormat) {
-        depth.width   = pixmap->width;
-        depth.height  = pixmap->height;
-        depth.stride  = depth.width; // use the width here
-        depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
-        if (depth.data == 0) {
-            setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
-        }
-    }
-}
-EGLBoolean egl_pixmap_surface_t::bindDrawSurface(GLES2Context* gl)
-{
-    GGLSurface buffer;
-    buffer.version = sizeof(GGLSurface);
-    buffer.width   = nativePixmap.width;
-    buffer.height  = nativePixmap.height;
-    buffer.stride  = nativePixmap.stride;
-    buffer.data    = nativePixmap.data;
-    buffer.format  = (GGLPixelFormat)nativePixmap.format;
-
-    gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_COLOR_BUFFER_BIT, &buffer);
-    if (depth.data != gl->rasterizer.depthSurface.data)
-        gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_DEPTH_BUFFER_BIT, &depth);
-    return EGL_TRUE;
-}
-EGLBoolean egl_pixmap_surface_t::bindReadSurface(GLES2Context* gl)
-{
-    GGLSurface buffer;
-    buffer.version = sizeof(GGLSurface);
-    buffer.width   = nativePixmap.width;
-    buffer.height  = nativePixmap.height;
-    buffer.stride  = nativePixmap.stride;
-    buffer.data    = nativePixmap.data;
-    buffer.format  = (GGLPixelFormat)nativePixmap.format;
-    puts("agl2: readBuffer not implemented");
-    //gl->rasterizer.interface.readBuffer(gl, &buffer);
-    return EGL_TRUE;
-}
-
-// ----------------------------------------------------------------------------
-
-struct egl_pbuffer_surface_t : public egl_surface_t {
-    egl_pbuffer_surface_t(
-            EGLDisplay dpy, EGLConfig config, int32_t depthFormat,
-            int32_t w, int32_t h, int32_t f);
-
-    virtual ~egl_pbuffer_surface_t();
-
-    virtual     bool        initCheck() const   {
-        return pbuffer.data != 0;
-    }
-    virtual     EGLBoolean  bindDrawSurface(GLES2Context* gl);
-    virtual     EGLBoolean  bindReadSurface(GLES2Context* gl);
-    virtual     EGLint      getWidth() const    {
-        return pbuffer.width;
-    }
-    virtual     EGLint      getHeight() const   {
-        return pbuffer.height;
-    }
-private:
-    GGLSurface  pbuffer;
-};
-
-egl_pbuffer_surface_t::egl_pbuffer_surface_t(EGLDisplay dpy,
-        EGLConfig config, int32_t depthFormat,
-        int32_t w, int32_t h, int32_t f)
-: egl_surface_t(dpy, config, depthFormat)
-{
-    size_t size = w*h;
-    switch (f) {
-        case GGL_PIXEL_FORMAT_A_8:
-            size *= 1;
-            break;
-        case GGL_PIXEL_FORMAT_RGB_565:
-            size *= 2;
-            break;
-        case GGL_PIXEL_FORMAT_RGBA_8888:
-            size *= 4;
-            break;
-        case GGL_PIXEL_FORMAT_RGBX_8888:
-            size *= 4;
-            break;
-        default:
-            LOGE("incompatible pixel format for pbuffer (format=%d)", f);
-            pbuffer.data = 0;
-            break;
-    }
-    pbuffer.version = sizeof(GGLSurface);
-    pbuffer.width   = w;
-    pbuffer.height  = h;
-    pbuffer.stride  = w;
-    pbuffer.data    = (GGLubyte*)malloc(size);
-    pbuffer.format  = (GGLPixelFormat)f;
-
-    if (depthFormat) {
-        depth.width   = pbuffer.width;
-        depth.height  = pbuffer.height;
-        depth.stride  = depth.width; // use the width here
-        depth.data    = (GGLubyte*)malloc(depth.stride*depth.height*2);
-        if (depth.data == 0) {
-            setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
-            return;
-        }
-    }
-}
-egl_pbuffer_surface_t::~egl_pbuffer_surface_t()
-{
-    free(pbuffer.data);
-}
-EGLBoolean egl_pbuffer_surface_t::bindDrawSurface(GLES2Context* gl)
-{
-    gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_COLOR_BUFFER_BIT, &pbuffer);
-    if (depth.data != gl->rasterizer.depthSurface.data)
-        gl->rasterizer.interface.SetBuffer(&gl->rasterizer.interface, GL_DEPTH_BUFFER_BIT, &depth);
-    return EGL_TRUE;
-}
-EGLBoolean egl_pbuffer_surface_t::bindReadSurface(GLES2Context* gl)
-{
-    puts("agl2: readBuffer not implemented");
-    //gl->rasterizer.interface.readBuffer(gl, &pbuffer);
-    return EGL_TRUE;
-}
-
-// ----------------------------------------------------------------------------
-
-struct config_pair_t {
-    GLint key;
-    GLint value;
-};
-
-struct configs_t {
-    const config_pair_t* array;
-    int                  size;
-};
-
-struct config_management_t {
-    GLint key;
-    bool (*match)(GLint reqValue, GLint confValue);
-    static bool atLeast(GLint reqValue, GLint confValue) {
-        return (reqValue == EGL_DONT_CARE) || (confValue >= reqValue);
-    }
-    static bool exact(GLint reqValue, GLint confValue) {
-        return (reqValue == EGL_DONT_CARE) || (confValue == reqValue);
-    }
-    static bool mask(GLint reqValue, GLint confValue) {
-        return (confValue & reqValue) == reqValue;
-    }
-    static bool ignore(GLint reqValue, GLint confValue) {
-        return true;
-    }
-};
-
-// ----------------------------------------------------------------------------
-
-#define VERSION_MAJOR 1
-#define VERSION_MINOR 2
-static char const * const gVendorString     = "Google Inc.";
-static char const * const gVersionString    = "0.0 Android Driver 0.0.0";
-static char const * const gClientApiString  = "OpenGL ES2";
-static char const * const gExtensionsString =
-        //"EGL_KHR_image_base "
-        // "KHR_image_pixmap "
-        //"EGL_ANDROID_image_native_buffer "
-        //"EGL_ANDROID_swap_rectangle "
-        "";
-
-// ----------------------------------------------------------------------------
-
-struct extention_map_t {
-    const char * const name;
-    __eglMustCastToProperFunctionPointerType address;
-};
-
-static const extention_map_t gExtentionMap[] = {
-        //    { "glDrawTexsOES",
-        //            (__eglMustCastToProperFunctionPointerType)&glDrawTexsOES },
-        //    { "glDrawTexiOES",
-        //            (__eglMustCastToProperFunctionPointerType)&glDrawTexiOES },
-        //    { "glDrawTexfOES",
-        //            (__eglMustCastToProperFunctionPointerType)&glDrawTexfOES },
-        //    { "glDrawTexxOES",
-        //            (__eglMustCastToProperFunctionPointerType)&glDrawTexxOES },
-        //    { "glDrawTexsvOES",
-        //            (__eglMustCastToProperFunctionPointerType)&glDrawTexsvOES },
-        //    { "glDrawTexivOES",
-        //            (__eglMustCastToProperFunctionPointerType)&glDrawTexivOES },
-        //    { "glDrawTexfvOES",
-        //            (__eglMustCastToProperFunctionPointerType)&glDrawTexfvOES },
-        //    { "glDrawTexxvOES",
-        //            (__eglMustCastToProperFunctionPointerType)&glDrawTexxvOES },
-        //    { "glQueryMatrixxOES",
-        //            (__eglMustCastToProperFunctionPointerType)&glQueryMatrixxOES },
-        //    { "glEGLImageTargetTexture2DOES",
-        //            (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetTexture2DOES },
-        //    { "glEGLImageTargetRenderbufferStorageOES",
-        //            (__eglMustCastToProperFunctionPointerType)&glEGLImageTargetRenderbufferStorageOES },
-        //    { "glClipPlanef",
-        //            (__eglMustCastToProperFunctionPointerType)&glClipPlanef },
-        //    { "glClipPlanex",
-        //            (__eglMustCastToProperFunctionPointerType)&glClipPlanex },
-        //    { "glBindBuffer",
-        //            (__eglMustCastToProperFunctionPointerType)&glBindBuffer },
-        //    { "glBufferData",
-        //            (__eglMustCastToProperFunctionPointerType)&glBufferData },
-        //    { "glBufferSubData",
-        //            (__eglMustCastToProperFunctionPointerType)&glBufferSubData },
-        //    { "glDeleteBuffers",
-        //            (__eglMustCastToProperFunctionPointerType)&glDeleteBuffers },
-        //    { "glGenBuffers",
-        //            (__eglMustCastToProperFunctionPointerType)&glGenBuffers },
-        //    { "eglCreateImageKHR",
-        //            (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
-        //    { "eglDestroyImageKHR",
-        //            (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
-        //    { "eglSetSwapRectangleANDROID",
-        //            (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
-};
-
-/*
- * In the lists below, attributes names MUST be sorted.
- * Additionally, all configs must be sorted according to
- * the EGL specification.
- */
-
-static config_pair_t const config_base_attribute_list[] = {
-        { EGL_STENCIL_SIZE,               0                                 },
-        { EGL_CONFIG_CAVEAT,              EGL_SLOW_CONFIG                   },
-        { EGL_LEVEL,                      0                                 },
-        { EGL_MAX_PBUFFER_HEIGHT,         GGL_MAX_VIEWPORT_DIMS             },
-        { EGL_MAX_PBUFFER_PIXELS,
-                GGL_MAX_VIEWPORT_DIMS*GGL_MAX_VIEWPORT_DIMS                 },
-                { EGL_MAX_PBUFFER_WIDTH,          GGL_MAX_VIEWPORT_DIMS             },
-                { EGL_NATIVE_RENDERABLE,          EGL_TRUE                          },
-                { EGL_NATIVE_VISUAL_ID,           0                                 },
-                { EGL_NATIVE_VISUAL_TYPE,         GGL_PIXEL_FORMAT_RGBA_8888        },
-                { EGL_SAMPLES,                    0                                 },
-                { EGL_SAMPLE_BUFFERS,             0                                 },
-                { EGL_TRANSPARENT_TYPE,           EGL_NONE                          },
-                { EGL_TRANSPARENT_BLUE_VALUE,     0                                 },
-                { EGL_TRANSPARENT_GREEN_VALUE,    0                                 },
-                { EGL_TRANSPARENT_RED_VALUE,      0                                 },
-                { EGL_BIND_TO_TEXTURE_RGBA,       EGL_FALSE                         },
-                { EGL_BIND_TO_TEXTURE_RGB,        EGL_FALSE                         },
-                { EGL_MIN_SWAP_INTERVAL,          1                                 },
-                { EGL_MAX_SWAP_INTERVAL,          1                                 },
-                { EGL_LUMINANCE_SIZE,             0                                 },
-                { EGL_ALPHA_MASK_SIZE,            0                                 },
-                { EGL_COLOR_BUFFER_TYPE,          EGL_RGB_BUFFER                    },
-                { EGL_RENDERABLE_TYPE,            EGL_OPENGL_ES2_BIT                },
-                { EGL_CONFORMANT,                 0                                 }
-};
-
-// These configs can override the base attribute list
-// NOTE: when adding a config here, don't forget to update eglCreate*Surface()
-
-// 565 configs
-static config_pair_t const config_0_attribute_list[] = {
-        { EGL_BUFFER_SIZE,     16 },
-        { EGL_ALPHA_SIZE,       0 },
-        { EGL_BLUE_SIZE,        5 },
-        { EGL_GREEN_SIZE,       6 },
-        { EGL_RED_SIZE,         5 },
-        { EGL_DEPTH_SIZE,       0 },
-        { EGL_CONFIG_ID,        0 },
-        { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGB_565 },
-        { EGL_SURFACE_TYPE,     EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-static config_pair_t const config_1_attribute_list[] = {
-        { EGL_BUFFER_SIZE,     16 },
-        { EGL_ALPHA_SIZE,       0 },
-        { EGL_BLUE_SIZE,        5 },
-        { EGL_GREEN_SIZE,       6 },
-        { EGL_RED_SIZE,         5 },
-        { EGL_DEPTH_SIZE,      16 },
-        { EGL_CONFIG_ID,        1 },
-        { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGB_565 },
-        { EGL_SURFACE_TYPE,     EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-// RGB 888 configs
-static config_pair_t const config_2_attribute_list[] = {
-        { EGL_BUFFER_SIZE,     32 },
-        { EGL_ALPHA_SIZE,       0 },
-        { EGL_BLUE_SIZE,        8 },
-        { EGL_GREEN_SIZE,       8 },
-        { EGL_RED_SIZE,         8 },
-        { EGL_DEPTH_SIZE,       0 },
-        { EGL_CONFIG_ID,        6 },
-        { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBX_8888 },
-        { EGL_SURFACE_TYPE,     EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-static config_pair_t const config_3_attribute_list[] = {
-        { EGL_BUFFER_SIZE,     32 },
-        { EGL_ALPHA_SIZE,       0 },
-        { EGL_BLUE_SIZE,        8 },
-        { EGL_GREEN_SIZE,       8 },
-        { EGL_RED_SIZE,         8 },
-        { EGL_DEPTH_SIZE,      16 },
-        { EGL_CONFIG_ID,        7 },
-        { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBX_8888 },
-        { EGL_SURFACE_TYPE,     EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-// 8888 configs
-static config_pair_t const config_4_attribute_list[] = {
-        { EGL_BUFFER_SIZE,     32 },
-        { EGL_ALPHA_SIZE,       8 },
-        { EGL_BLUE_SIZE,        8 },
-        { EGL_GREEN_SIZE,       8 },
-        { EGL_RED_SIZE,         8 },
-        { EGL_DEPTH_SIZE,       0 },
-        { EGL_CONFIG_ID,        2 },
-        { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBA_8888 },
-        { EGL_SURFACE_TYPE,     EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-static config_pair_t const config_5_attribute_list[] = {
-        { EGL_BUFFER_SIZE,     32 },
-        { EGL_ALPHA_SIZE,       8 },
-        { EGL_BLUE_SIZE,        8 },
-        { EGL_GREEN_SIZE,       8 },
-        { EGL_RED_SIZE,         8 },
-        { EGL_DEPTH_SIZE,      16 },
-        { EGL_CONFIG_ID,        3 },
-        { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_RGBA_8888 },
-        { EGL_SURFACE_TYPE,     EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-// A8 configs
-static config_pair_t const config_6_attribute_list[] = {
-        { EGL_BUFFER_SIZE,      8 },
-        { EGL_ALPHA_SIZE,       8 },
-        { EGL_BLUE_SIZE,        0 },
-        { EGL_GREEN_SIZE,       0 },
-        { EGL_RED_SIZE,         0 },
-        { EGL_DEPTH_SIZE,       0 },
-        { EGL_CONFIG_ID,        4 },
-        { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_A_8 },
-        { EGL_SURFACE_TYPE,     EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-static config_pair_t const config_7_attribute_list[] = {
-        { EGL_BUFFER_SIZE,      8 },
-        { EGL_ALPHA_SIZE,       8 },
-        { EGL_BLUE_SIZE,        0 },
-        { EGL_GREEN_SIZE,       0 },
-        { EGL_RED_SIZE,         0 },
-        { EGL_DEPTH_SIZE,      16 },
-        { EGL_CONFIG_ID,        5 },
-        { EGL_NATIVE_VISUAL_ID, GGL_PIXEL_FORMAT_A_8 },
-        { EGL_SURFACE_TYPE,     EGL_SWAP_BEHAVIOR_PRESERVED_BIT|EGL_WINDOW_BIT|EGL_PBUFFER_BIT|EGL_PIXMAP_BIT },
-};
-
-static configs_t const gConfigs[] = {
-        { config_0_attribute_list, NELEM(config_0_attribute_list) },
-        { config_1_attribute_list, NELEM(config_1_attribute_list) },
-        { config_2_attribute_list, NELEM(config_2_attribute_list) },
-        { config_3_attribute_list, NELEM(config_3_attribute_list) },
-        { config_4_attribute_list, NELEM(config_4_attribute_list) },
-        { config_5_attribute_list, NELEM(config_5_attribute_list) },
-        //   { config_6_attribute_list, NELEM(config_6_attribute_list) },
-        //   { config_7_attribute_list, NELEM(config_7_attribute_list) },
-};
-
-static config_management_t const gConfigManagement[] = {
-        { EGL_BUFFER_SIZE,                config_management_t::atLeast },
-        { EGL_ALPHA_SIZE,                 config_management_t::atLeast },
-        { EGL_BLUE_SIZE,                  config_management_t::atLeast },
-        { EGL_GREEN_SIZE,                 config_management_t::atLeast },
-        { EGL_RED_SIZE,                   config_management_t::atLeast },
-        { EGL_DEPTH_SIZE,                 config_management_t::atLeast },
-        { EGL_STENCIL_SIZE,               config_management_t::atLeast },
-        { EGL_CONFIG_CAVEAT,              config_management_t::exact   },
-        { EGL_CONFIG_ID,                  config_management_t::exact   },
-        { EGL_LEVEL,                      config_management_t::exact   },
-        { EGL_MAX_PBUFFER_HEIGHT,         config_management_t::ignore   },
-        { EGL_MAX_PBUFFER_PIXELS,         config_management_t::ignore   },
-        { EGL_MAX_PBUFFER_WIDTH,          config_management_t::ignore   },
-        { EGL_NATIVE_RENDERABLE,          config_management_t::exact   },
-        { EGL_NATIVE_VISUAL_ID,           config_management_t::ignore   },
-        { EGL_NATIVE_VISUAL_TYPE,         config_management_t::exact   },
-        { EGL_SAMPLES,                    config_management_t::exact   },
-        { EGL_SAMPLE_BUFFERS,             config_management_t::exact   },
-        { EGL_SURFACE_TYPE,               config_management_t::mask    },
-        { EGL_TRANSPARENT_TYPE,           config_management_t::exact   },
-        { EGL_TRANSPARENT_BLUE_VALUE,     config_management_t::exact   },
-        { EGL_TRANSPARENT_GREEN_VALUE,    config_management_t::exact   },
-        { EGL_TRANSPARENT_RED_VALUE,      config_management_t::exact   },
-        { EGL_BIND_TO_TEXTURE_RGBA,       config_management_t::exact   },
-        { EGL_BIND_TO_TEXTURE_RGB,        config_management_t::exact   },
-        { EGL_MIN_SWAP_INTERVAL,          config_management_t::exact   },
-        { EGL_MAX_SWAP_INTERVAL,          config_management_t::exact   },
-        { EGL_LUMINANCE_SIZE,             config_management_t::atLeast },
-        { EGL_ALPHA_MASK_SIZE,            config_management_t::atLeast },
-        { EGL_COLOR_BUFFER_TYPE,          config_management_t::exact   },
-        { EGL_RENDERABLE_TYPE,            config_management_t::mask    },
-        { EGL_CONFORMANT,                 config_management_t::mask    }
-};
-
-
-static config_pair_t const config_defaults[] = {
-        // attributes that are not specified are simply ignored, if a particular
-        // one needs not be ignored, it must be specified here, eg:
-        // { EGL_SURFACE_TYPE, EGL_WINDOW_BIT },
-};
-
-// ----------------------------------------------------------------------------
-
-static status_t getConfigFormatInfo(EGLint configID,
-        int32_t& pixelFormat, int32_t& depthFormat)
-{
-    switch (configID) {
-        case 0:
-            pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
-            depthFormat = 0;
-            break;
-        case 1:
-            pixelFormat = GGL_PIXEL_FORMAT_RGB_565;
-            depthFormat = GGL_PIXEL_FORMAT_Z_32;
-            break;
-        case 2:
-            pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
-            depthFormat = 0;
-            break;
-        case 3:
-            pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
-            depthFormat = GGL_PIXEL_FORMAT_Z_32;
-            break;
-        case 4:
-            pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
-            depthFormat = 0;
-            break;
-        case 5:
-            pixelFormat = GGL_PIXEL_FORMAT_RGBA_8888;
-            depthFormat = GGL_PIXEL_FORMAT_Z_32;
-            break;
-        case 6:
-            pixelFormat = GGL_PIXEL_FORMAT_A_8;
-            depthFormat = 0;
-            break;
-        case 7:
-            pixelFormat = GGL_PIXEL_FORMAT_A_8;
-            depthFormat = GGL_PIXEL_FORMAT_Z_32;
-            break;
-        default:
-            return NAME_NOT_FOUND;
-    }
-    return NO_ERROR;
-}
-
-// ----------------------------------------------------------------------------
-
-template<typename T>
-static int binarySearch(T const sortedArray[], int first, int last, EGLint key)
-{
-    while (first <= last) {
-        int mid = (first + last) / 2;
-        if (key > sortedArray[mid].key) {
-            first = mid + 1;
-        } else if (key < sortedArray[mid].key) {
-            last = mid - 1;
-        } else {
-            return mid;
-        }
-    }
-    return -1;
-}
-
-static int isAttributeMatching(int i, EGLint attr, EGLint val)
-{
-    // look for the attribute in all of our configs
-    config_pair_t const* configFound = gConfigs[i].array;
-    int index = binarySearch<config_pair_t>(
-            gConfigs[i].array,
-            0, gConfigs[i].size-1,
-            attr);
-    if (index < 0) {
-        configFound = config_base_attribute_list;
-        index = binarySearch<config_pair_t>(
-                config_base_attribute_list,
-                0, NELEM(config_base_attribute_list)-1,
-                attr);
-    }
-    if (index >= 0) {
-        // attribute found, check if this config could match
-        int cfgMgtIndex = binarySearch<config_management_t>(
-                gConfigManagement,
-                0, NELEM(gConfigManagement)-1,
-                attr);
-        if (cfgMgtIndex >= 0) {
-            bool match = gConfigManagement[cfgMgtIndex].match(
-                    val, configFound[index].value);
-            if (match) {
-                // this config matches
-                return 1;
-            }
-        } else {
-            // attribute not found. this should NEVER happen.
-        }
-    } else {
-        // error, this attribute doesn't exist
-    }
-    return 0;
-}
-
-static int makeCurrent(GLES2Context* gl)
-{
-    GLES2Context* current = (GLES2Context*)getGlThreadSpecific();
-    if (gl) {
-        egl_context_t* c = egl_context_t::context(gl);
-        if (c->flags & egl_context_t::IS_CURRENT) {
-            if (current != gl) {
-                // it is an error to set a context current, if it's already
-                // current to another thread
-                return -1;
-            }
-        } else {
-            if (current) {
-                // mark the current context as not current, and flush
-                glFlush();
-                egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
-            }
-        }
-        if (!(c->flags & egl_context_t::IS_CURRENT)) {
-            // The context is not current, make it current!
-            setGlThreadSpecific(gl);
-            c->flags |= egl_context_t::IS_CURRENT;
-        }
-    } else {
-        if (current) {
-            // mark the current context as not current, and flush
-            glFlush();
-            egl_context_t::context(current)->flags &= ~egl_context_t::IS_CURRENT;
-        }
-        // this thread has no context attached to it
-        setGlThreadSpecific(0);
-    }
-    return 0;
-}
-
-static EGLBoolean getConfigAttrib(EGLDisplay dpy, EGLConfig config,
-        EGLint attribute, EGLint *value)
-{
-    size_t numConfigs =  NELEM(gConfigs);
-    int index = (int)config;
-    if (uint32_t(index) >= numConfigs)
-        return setError(EGL_BAD_CONFIG, EGL_FALSE);
-
-    int attrIndex;
-    attrIndex = binarySearch<config_pair_t>(
-            gConfigs[index].array,
-            0, gConfigs[index].size-1,
-            attribute);
-    if (attrIndex>=0) {
-        *value = gConfigs[index].array[attrIndex].value;
-        return EGL_TRUE;
-    }
-
-    attrIndex = binarySearch<config_pair_t>(
-            config_base_attribute_list,
-            0, NELEM(config_base_attribute_list)-1,
-            attribute);
-    if (attrIndex>=0) {
-        *value = config_base_attribute_list[attrIndex].value;
-        return EGL_TRUE;
-    }
-    return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
-}
-
-static EGLSurface createWindowSurface(EGLDisplay dpy, EGLConfig config,
-        NativeWindowType window, const EGLint *attrib_list)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
-    if (window == 0)
-        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-
-    EGLint surfaceType;
-    if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
-        return EGL_FALSE;
-
-    if (!(surfaceType & EGL_WINDOW_BIT))
-        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-
-    if (reinterpret_cast<ANativeWindow*>(window)->common.magic !=
-            ANDROID_NATIVE_WINDOW_MAGIC) {
-        return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
-    }
-
-    EGLint configID;
-    if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
-        return EGL_FALSE;
-
-    int32_t depthFormat;
-    int32_t pixelFormat;
-    if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
-        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-    }
-
-    // FIXME: we don't have access to the pixelFormat here just yet.
-    // (it's possible that the surface is not fully initialized)
-    // maybe this should be done after the page-flip
-    //if (EGLint(info.format) != pixelFormat)
-    //    return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-
-    egl_surface_t* surface;
-    surface = new egl_window_surface_v2_t(dpy, config, depthFormat,
-            reinterpret_cast<ANativeWindow*>(window));
-
-    if (!surface->initCheck()) {
-        // there was a problem in the ctor, the error
-        // flag has been set.
-        delete surface;
-        surface = 0;
-    }
-    return surface;
-}
-
-static EGLSurface createPixmapSurface(EGLDisplay dpy, EGLConfig config,
-        NativePixmapType pixmap, const EGLint *attrib_list)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
-    if (pixmap == 0)
-        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-
-    EGLint surfaceType;
-    if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
-        return EGL_FALSE;
-
-    if (!(surfaceType & EGL_PIXMAP_BIT))
-        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-
-    if (reinterpret_cast<egl_native_pixmap_t*>(pixmap)->version !=
-            sizeof(egl_native_pixmap_t)) {
-        return setError(EGL_BAD_NATIVE_PIXMAP, EGL_NO_SURFACE);
-    }
-
-    EGLint configID;
-    if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
-        return EGL_FALSE;
-
-    int32_t depthFormat;
-    int32_t pixelFormat;
-    if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
-        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-    }
-
-    if (reinterpret_cast<egl_native_pixmap_t *>(pixmap)->format != pixelFormat)
-        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-
-    egl_surface_t* surface =
-            new egl_pixmap_surface_t(dpy, config, depthFormat,
-                    reinterpret_cast<egl_native_pixmap_t*>(pixmap));
-
-    if (!surface->initCheck()) {
-        // there was a problem in the ctor, the error
-        // flag has been set.
-        delete surface;
-        surface = 0;
-    }
-    return surface;
-}
-
-static EGLSurface createPbufferSurface(EGLDisplay dpy, EGLConfig config,
-        const EGLint *attrib_list)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
-
-    EGLint surfaceType;
-    if (getConfigAttrib(dpy, config, EGL_SURFACE_TYPE, &surfaceType) == EGL_FALSE)
-        return EGL_FALSE;
-
-    if (!(surfaceType & EGL_PBUFFER_BIT))
-        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-
-    EGLint configID;
-    if (getConfigAttrib(dpy, config, EGL_CONFIG_ID, &configID) == EGL_FALSE)
-        return EGL_FALSE;
-
-    int32_t depthFormat;
-    int32_t pixelFormat;
-    if (getConfigFormatInfo(configID, pixelFormat, depthFormat) != NO_ERROR) {
-        return setError(EGL_BAD_MATCH, EGL_NO_SURFACE);
-    }
-
-    int32_t w = 0;
-    int32_t h = 0;
-    while (attrib_list[0]) {
-        if (attrib_list[0] == EGL_WIDTH)  w = attrib_list[1];
-        if (attrib_list[0] == EGL_HEIGHT) h = attrib_list[1];
-        attrib_list+=2;
-    }
-
-    egl_surface_t* surface =
-            new egl_pbuffer_surface_t(dpy, config, depthFormat, w, h, pixelFormat);
-
-    if (!surface->initCheck()) {
-        // there was a problem in the ctor, the error
-        // flag has been set.
-        delete surface;
-        surface = 0;
-    }
-    return surface;
-}
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-// ----------------------------------------------------------------------------
-
-using namespace android;
-
-// ----------------------------------------------------------------------------
-// Initialization
-// ----------------------------------------------------------------------------
-
-EGLDisplay eglGetDisplay(NativeDisplayType display)
-{
-    puts("agl2:eglGetDisplay");
-#ifndef HAVE_ANDROID_OS
-    // this just needs to be done once
-    if (gGLKey == -1) {
-        pthread_mutex_lock(&gInitMutex);
-        if (gGLKey == -1)
-            pthread_key_create(&gGLKey, NULL);
-        pthread_mutex_unlock(&gInitMutex);
-    }
-#endif
-    if (display == EGL_DEFAULT_DISPLAY) {
-        EGLDisplay dpy = (EGLDisplay)1;
-        egl_display_t& d = egl_display_t::get_display(dpy);
-        d.type = display;
-        return dpy;
-    }
-    return EGL_NO_DISPLAY;
-}
-
-EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
-{
-    puts("agl2:eglInitialize");
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
-    EGLBoolean res = EGL_TRUE;
-    egl_display_t& d = egl_display_t::get_display(dpy);
-
-    if (android_atomic_inc(&d.initialized) == 0) {
-        // initialize stuff here if needed
-        //pthread_mutex_lock(&gInitMutex);
-        //pthread_mutex_unlock(&gInitMutex);
-    }
-
-    if (res == EGL_TRUE) {
-        if (major != NULL) *major = VERSION_MAJOR;
-        if (minor != NULL) *minor = VERSION_MINOR;
-    }
-    return res;
-}
-
-EGLBoolean eglTerminate(EGLDisplay dpy)
-{
-    puts("agl2:eglTerminate");
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
-    EGLBoolean res = EGL_TRUE;
-    egl_display_t& d = egl_display_t::get_display(dpy);
-    if (android_atomic_dec(&d.initialized) == 1) {
-        // TODO: destroy all resources (surfaces, contexts, etc...)
-        //pthread_mutex_lock(&gInitMutex);
-        //pthread_mutex_unlock(&gInitMutex);
-    }
-    return res;
-}
-
-// ----------------------------------------------------------------------------
-// configuration
-// ----------------------------------------------------------------------------
-
-EGLBoolean eglGetConfigs(   EGLDisplay dpy,
-        EGLConfig *configs,
-        EGLint config_size, EGLint *num_config)
-{
-    puts("agl2:eglGetConfigs");
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
-    GLint numConfigs = NELEM(gConfigs);
-    if (!configs) {
-        *num_config = numConfigs;
-        return EGL_TRUE;
-    }
-    GLint i;
-    for (i=0 ; i<numConfigs && i<config_size ; i++) {
-        *configs++ = (EGLConfig)i;
-    }
-    *num_config = i;
-    return EGL_TRUE;
-}
-
-static const char * ATTRIBUTE_NAMES [] = {
-        "EGL_BUFFER_SIZE",
-        "EGL_ALPHA_SIZE",
-        "EGL_BLUE_SIZE",
-        "EGL_GREEN_SIZE",
-        "EGL_RED_SIZE",
-        "EGL_DEPTH_SIZE",
-        "EGL_STENCIL_SIZE",
-        "EGL_CONFIG_CAVEAT",
-        "EGL_CONFIG_ID",
-        "EGL_LEVEL",
-        "EGL_MAX_PBUFFER_HEIGHT",
-        "EGL_MAX_PBUFFER_PIXELS",
-        "EGL_MAX_PBUFFER_WIDTH",
-        "EGL_NATIVE_RENDERABLE",
-        "EGL_NATIVE_VISUAL_ID",
-        "EGL_NATIVE_VISUAL_TYPE",
-        "EGL_PRESERVED_RESOURCES",
-        "EGL_SAMPLES",
-        "EGL_SAMPLE_BUFFERS",
-        "EGL_SURFACE_TYPE",
-        "EGL_TRANSPARENT_TYPE",
-        "EGL_TRANSPARENT_BLUE_VALUE",
-        "EGL_TRANSPARENT_GREEN_VALUE",
-        "EGL_TRANSPARENT_RED_VALUE",
-        "EGL_NONE",   /* Attrib list terminator */
-        "EGL_BIND_TO_TEXTURE_RGB",
-        "EGL_BIND_TO_TEXTURE_RGBA",
-        "EGL_MIN_SWAP_INTERVAL",
-        "EGL_MAX_SWAP_INTERVAL",
-        "EGL_LUMINANCE_SIZE",
-        "EGL_ALPHA_MASK_SIZE",
-        "EGL_COLOR_BUFFER_TYPE",
-        "EGL_RENDERABLE_TYPE",
-        "EGL_MATCH_NATIVE_PIXMAP",   /* Pseudo-attribute (not queryable) */
-        "EGL_CONFORMANT",
-};
-
-EGLBoolean eglChooseConfig( EGLDisplay dpy, const EGLint *attrib_list,
-        EGLConfig *configs, EGLint config_size,
-        EGLint *num_config)
-{
-    puts("agl2:eglChooseConfig");
-    LOGD("\n***\n***\n agl2:LOGD eglChooseConfig \n***\n***\n");
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
-    if (ggl_unlikely(num_config==0)) {
-        LOGD("\n***\n***\n num_config==0 \n***\n***\n");
-        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
-    }
-
-    if (ggl_unlikely(attrib_list==0)) {
-        /*
-         * A NULL attrib_list should be treated as though it was an empty
-         * one (terminated with EGL_NONE) as defined in
-         * section 3.4.1 "Querying Configurations" in the EGL specification.
-         */
-        LOGD("\n***\n***\n attrib_list==0 \n***\n***\n");
-        static const EGLint dummy = EGL_NONE;
-        attrib_list = &dummy;
-    }
-
-    for (const EGLint * attrib = attrib_list; *attrib != EGL_NONE; attrib += 2) {
-        LOGD("eglChooseConfig %s(%.4X): %d \n", ATTRIBUTE_NAMES[attrib[0] - EGL_BUFFER_SIZE], attrib[0], attrib[1]);
-        if (EGL_BUFFER_SIZE > attrib[0] || EGL_CONFORMANT < attrib[0])
-            LOGD("eglChooseConfig invalid config attrib: 0x%.4X=%d \n", attrib[0], attrib[1]);
-    }
-
-    int numAttributes = 0;
-    int numConfigs =  NELEM(gConfigs);
-    uint32_t possibleMatch = (1<<numConfigs)-1;
-    while (possibleMatch && *attrib_list != EGL_NONE) {
-        numAttributes++;
-        EGLint attr = *attrib_list++;
-        EGLint val  = *attrib_list++;
-        for (int i=0 ; possibleMatch && i<numConfigs ; i++) {
-            if (!(possibleMatch & (1<<i)))
-                continue;
-            if (isAttributeMatching(i, attr, val) == 0) {
-                LOGD("!isAttributeMatching config(%d) %s=%d \n", i, ATTRIBUTE_NAMES[attr - EGL_BUFFER_SIZE], val);
-                possibleMatch &= ~(1<<i);
-            }
-        }
-    }
-
-    LOGD("eglChooseConfig possibleMatch=%.4X \n", possibleMatch);
-
-    // now, handle the attributes which have a useful default value
-    for (size_t j=0 ; possibleMatch && j<NELEM(config_defaults) ; j++) {
-        // see if this attribute was specified, if not, apply its
-        // default value
-        if (binarySearch<config_pair_t>(
-                (config_pair_t const*)attrib_list,
-                0, numAttributes-1,
-                config_defaults[j].key) < 0) {
-            for (int i=0 ; possibleMatch && i<numConfigs ; i++) {
-                if (!(possibleMatch & (1<<i)))
-                    continue;
-                if (isAttributeMatching(i,
-                        config_defaults[j].key,
-                        config_defaults[j].value) == 0) {
-                    possibleMatch &= ~(1<<i);
-                }
-            }
-        }
-    }
-
-    // return the configurations found
-    int n=0;
-    if (possibleMatch) {
-        if (configs) {
-            for (int i=0 ; config_size && i<numConfigs ; i++) {
-                if (possibleMatch & (1<<i)) {
-                    *configs++ = (EGLConfig)i;
-                    config_size--;
-                    n++;
-                }
-            }
-        } else {
-            for (int i=0 ; i<numConfigs ; i++) {
-                if (possibleMatch & (1<<i)) {
-                    n++;
-                }
-            }
-        }
-    }
-    *num_config = n;
-    LOGD("\n***\n***\n num_config==%d \n***\n***\n", *num_config);
-    return EGL_TRUE;
-}
-
-EGLBoolean eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
-        EGLint attribute, EGLint *value)
-{
-    puts("agl2:eglGetConfigAttrib");
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
-    return getConfigAttrib(dpy, config, attribute, value);
-}
-
-// ----------------------------------------------------------------------------
-// surfaces
-// ----------------------------------------------------------------------------
-
-EGLSurface eglCreateWindowSurface(  EGLDisplay dpy, EGLConfig config,
-        NativeWindowType window,
-        const EGLint *attrib_list)
-{
-    puts("agl2:eglCreateWindowSurface");
-    return createWindowSurface(dpy, config, window, attrib_list);
-}
-
-EGLSurface eglCreatePixmapSurface(  EGLDisplay dpy, EGLConfig config,
-        NativePixmapType pixmap,
-        const EGLint *attrib_list)
-{
-    puts("agl2:eglCreatePixmapSurface");
-    return createPixmapSurface(dpy, config, pixmap, attrib_list);
-}
-
-EGLSurface eglCreatePbufferSurface( EGLDisplay dpy, EGLConfig config,
-        const EGLint *attrib_list)
-{
-    puts("agl2:eglCreatePbufferSurface");
-    return createPbufferSurface(dpy, config, attrib_list);
-}
-
-EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface eglSurface)
-{
-    puts("agl2:eglDestroySurface");
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    if (eglSurface != EGL_NO_SURFACE) {
-        egl_surface_t* surface( static_cast<egl_surface_t*>(eglSurface) );
-        if (!surface->isValid())
-            return setError(EGL_BAD_SURFACE, EGL_FALSE);
-        if (surface->dpy != dpy)
-            return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-        if (surface->ctx) {
-            // FIXME: this surface is current check what the spec says
-            surface->disconnect();
-            surface->ctx = 0;
-        }
-        delete surface;
-    }
-    return EGL_TRUE;
-}
-
-EGLBoolean eglQuerySurface( EGLDisplay dpy, EGLSurface eglSurface,
-        EGLint attribute, EGLint *value)
-{
-    puts("agl2:eglQuerySurface");
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    egl_surface_t* surface = static_cast<egl_surface_t*>(eglSurface);
-    if (!surface->isValid())
-        return setError(EGL_BAD_SURFACE, EGL_FALSE);
-    if (surface->dpy != dpy)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
-    EGLBoolean ret = EGL_TRUE;
-    switch (attribute) {
-        case EGL_CONFIG_ID:
-            ret = getConfigAttrib(dpy, surface->config, EGL_CONFIG_ID, value);
-            break;
-        case EGL_WIDTH:
-            *value = surface->getWidth();
-            break;
-        case EGL_HEIGHT:
-            *value = surface->getHeight();
-            break;
-        case EGL_LARGEST_PBUFFER:
-            // not modified for a window or pixmap surface
-            break;
-        case EGL_TEXTURE_FORMAT:
-            *value = EGL_NO_TEXTURE;
-            break;
-        case EGL_TEXTURE_TARGET:
-            *value = EGL_NO_TEXTURE;
-            break;
-        case EGL_MIPMAP_TEXTURE:
-            *value = EGL_FALSE;
-            break;
-        case EGL_MIPMAP_LEVEL:
-            *value = 0;
-            break;
-        case EGL_RENDER_BUFFER:
-            // TODO: return the real RENDER_BUFFER here
-            *value = EGL_BACK_BUFFER;
-            break;
-        case EGL_HORIZONTAL_RESOLUTION:
-            // pixel/mm * EGL_DISPLAY_SCALING
-            *value = surface->getHorizontalResolution();
-            break;
-        case EGL_VERTICAL_RESOLUTION:
-            // pixel/mm * EGL_DISPLAY_SCALING
-            *value = surface->getVerticalResolution();
-            break;
-        case EGL_PIXEL_ASPECT_RATIO: {
-            // w/h * EGL_DISPLAY_SCALING
-            int wr = surface->getHorizontalResolution();
-            int hr = surface->getVerticalResolution();
-            *value = (wr * EGL_DISPLAY_SCALING) / hr;
-        }
-        break;
-        case EGL_SWAP_BEHAVIOR:
-            *value = surface->getSwapBehavior();
-            break;
-        default:
-            ret = setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
-    }
-    return ret;
-}
-
-EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
-        EGLContext share_list, const EGLint *attrib_list)
-{
-    puts("agl2:eglCreateContext");
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
-
-    GLES2Context* gl = new GLES2Context();//ogles_init(sizeof(egl_context_t));
-    if (!gl) return setError(EGL_BAD_ALLOC, EGL_NO_CONTEXT);
-
-    //egl_context_t* c = static_cast<egl_context_t*>(gl->rasterizer.base);
-    egl_context_t * c = &gl->egl;
-    c->flags = egl_context_t::NEVER_CURRENT;
-    c->dpy = dpy;
-    c->config = config;
-    c->read = 0;
-    c->draw = 0;
-
-    c->frame = 0;
-    c->lastSwapTime = clock();
-    c->accumulateSeconds = 0;
-    return (EGLContext)gl;
-}
-
-EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
-{
-    puts("agl2:eglDestroyContext");
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    egl_context_t* c = egl_context_t::context(ctx);
-    if (c->flags & egl_context_t::IS_CURRENT)
-        setGlThreadSpecific(0);
-    //ogles_uninit((GLES2Context*)ctx);
-    delete (GLES2Context*)ctx;
-    return EGL_TRUE;
-}
-
-EGLBoolean eglMakeCurrent(  EGLDisplay dpy, EGLSurface draw,
-        EGLSurface read, EGLContext ctx)
-{
-    puts("agl2:eglMakeCurrent");
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    if (draw) {
-        egl_surface_t* s = (egl_surface_t*)draw;
-        if (!s->isValid())
-            return setError(EGL_BAD_SURFACE, EGL_FALSE);
-        if (s->dpy != dpy)
-            return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-        // TODO: check that draw is compatible with the context
-    }
-    if (read && read!=draw) {
-        egl_surface_t* s = (egl_surface_t*)read;
-        if (!s->isValid())
-            return setError(EGL_BAD_SURFACE, EGL_FALSE);
-        if (s->dpy != dpy)
-            return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-        // TODO: check that read is compatible with the context
-    }
-
-    EGLContext current_ctx = EGL_NO_CONTEXT;
-
-    if ((read == EGL_NO_SURFACE && draw == EGL_NO_SURFACE) && (ctx != EGL_NO_CONTEXT))
-        return setError(EGL_BAD_MATCH, EGL_FALSE);
-
-    if ((read != EGL_NO_SURFACE || draw != EGL_NO_SURFACE) && (ctx == EGL_NO_CONTEXT))
-        return setError(EGL_BAD_MATCH, EGL_FALSE);
-
-    if (ctx == EGL_NO_CONTEXT) {
-        // if we're detaching, we need the current context
-        current_ctx = (EGLContext)getGlThreadSpecific();
-    } else {
-        egl_context_t* c = egl_context_t::context(ctx);
-        egl_surface_t* d = (egl_surface_t*)draw;
-        egl_surface_t* r = (egl_surface_t*)read;
-        if ((d && d->ctx && d->ctx != ctx) ||
-                (r && r->ctx && r->ctx != ctx)) {
-            // one of the surface is bound to a context in another thread
-            return setError(EGL_BAD_ACCESS, EGL_FALSE);
-        }
-    }
-
-    GLES2Context* gl = (GLES2Context*)ctx;
-    if (makeCurrent(gl) == 0) {
-        if (ctx) {
-            egl_context_t* c = egl_context_t::context(ctx);
-            egl_surface_t* d = (egl_surface_t*)draw;
-            egl_surface_t* r = (egl_surface_t*)read;
-
-            if (c->draw) {
-                egl_surface_t* s = reinterpret_cast<egl_surface_t*>(c->draw);
-                s->disconnect();
-            }
-            if (c->read) {
-                // FIXME: unlock/disconnect the read surface too
-            }
-
-            c->draw = draw;
-            c->read = read;
-
-            if (c->flags & egl_context_t::NEVER_CURRENT) {
-                c->flags &= ~egl_context_t::NEVER_CURRENT;
-                GLint w = 0;
-                GLint h = 0;
-                if (draw) {
-                    w = d->getWidth();
-                    h = d->getHeight();
-                }
-                gl->rasterizer.interface.Viewport(&gl->rasterizer.interface, 0, 0, w, h);
-                //ogles_surfaceport(gl, 0, 0);
-                //ogles_viewport(gl, 0, 0, w, h);
-                //ogles_scissor(gl, 0, 0, w, h);
-            }
-            if (d) {
-                if (d->connect() == EGL_FALSE) {
-                    return EGL_FALSE;
-                }
-                d->ctx = ctx;
-                d->bindDrawSurface(gl);
-            }
-            if (r) {
-                // FIXME: lock/connect the read surface too
-                r->ctx = ctx;
-                r->bindReadSurface(gl);
-            }
-        } else {
-            // if surfaces were bound to the context bound to this thread
-            // mark then as unbound.
-            if (current_ctx) {
-                egl_context_t* c = egl_context_t::context(current_ctx);
-                egl_surface_t* d = (egl_surface_t*)c->draw;
-                egl_surface_t* r = (egl_surface_t*)c->read;
-                if (d) {
-                    c->draw = 0;
-                    d->ctx = EGL_NO_CONTEXT;
-                    d->disconnect();
-                }
-                if (r) {
-                    c->read = 0;
-                    r->ctx = EGL_NO_CONTEXT;
-                    // FIXME: unlock/disconnect the read surface too
-                }
-            }
-        }
-        return EGL_TRUE;
-    }
-    return setError(EGL_BAD_ACCESS, EGL_FALSE);
-}
-
-EGLContext eglGetCurrentContext(void)
-{
-    // eglGetCurrentContext returns the current EGL rendering context,
-    // as specified by eglMakeCurrent. If no context is current,
-    // EGL_NO_CONTEXT is returned.
-    return (EGLContext)getGlThreadSpecific();
-}
-
-EGLSurface eglGetCurrentSurface(EGLint readdraw)
-{
-    // eglGetCurrentSurface returns the read or draw surface attached
-    // to the current EGL rendering context, as specified by eglMakeCurrent.
-    // If no context is current, EGL_NO_SURFACE is returned.
-    EGLContext ctx = (EGLContext)getGlThreadSpecific();
-    if (ctx == EGL_NO_CONTEXT) return EGL_NO_SURFACE;
-    egl_context_t* c = egl_context_t::context(ctx);
-    if (readdraw == EGL_READ) {
-        return c->read;
-    } else if (readdraw == EGL_DRAW) {
-        return c->draw;
-    }
-    return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
-}
-
-EGLDisplay eglGetCurrentDisplay(void)
-{
-    // eglGetCurrentDisplay returns the current EGL display connection
-    // for the current EGL rendering context, as specified by eglMakeCurrent.
-    // If no context is current, EGL_NO_DISPLAY is returned.
-    EGLContext ctx = (EGLContext)getGlThreadSpecific();
-    if (ctx == EGL_NO_CONTEXT) return EGL_NO_DISPLAY;
-    egl_context_t* c = egl_context_t::context(ctx);
-    return c->dpy;
-}
-
-EGLBoolean eglQueryContext( EGLDisplay dpy, EGLContext ctx,
-        EGLint attribute, EGLint *value)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    egl_context_t* c = egl_context_t::context(ctx);
-    switch (attribute) {
-        case EGL_CONFIG_ID:
-            // Returns the ID of the EGL frame buffer configuration with
-            // respect to which the context was created
-            return getConfigAttrib(dpy, c->config, EGL_CONFIG_ID, value);
-    }
-    return setError(EGL_BAD_ATTRIBUTE, EGL_FALSE);
-}
-
-EGLBoolean eglWaitGL(void)
-{
-    return EGL_TRUE;
-}
-
-EGLBoolean eglWaitNative(EGLint engine)
-{
-    return EGL_TRUE;
-}
-
-EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
-    egl_surface_t* d = static_cast<egl_surface_t*>(draw);
-    if (!d->isValid())
-        return setError(EGL_BAD_SURFACE, EGL_FALSE);
-    if (d->dpy != dpy)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
-    // post the surface
-    d->swapBuffers();
-
-    // if it's bound to a context, update the buffer
-    if (d->ctx != EGL_NO_CONTEXT) {
-        d->bindDrawSurface((GLES2Context*)d->ctx);
-        // if this surface is also the read surface of the context
-        // it is bound to, make sure to update the read buffer as well.
-        // The EGL spec is a little unclear about this.
-        egl_context_t* c = egl_context_t::context(d->ctx);
-        if (c->read == draw) {
-            d->bindReadSurface((GLES2Context*)d->ctx);
-        }
-        clock_t time = clock();
-        float elapsed = (float)(time - c->lastSwapTime) / CLOCKS_PER_SEC;
-        c->accumulateSeconds += elapsed;
-        c->frame++;
-        //      LOGD("agl2: eglSwapBuffers elapsed=%.2fms \n*", elapsed * 1000);
-        if (20 == c->frame) {
-            float avg = c->accumulateSeconds / c->frame;
-            LOGD("\n*\n* agl2: eglSwapBuffers %u frame avg fps=%.1f elapsed=%.2fms \n*",
-                    c->frame, 1 / avg, avg * 1000);
-            c->frame = 0;
-            c->accumulateSeconds = 0;
-        }
-        c->lastSwapTime = time;
-    }
-
-    return EGL_TRUE;
-}
-
-EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
-        NativePixmapType target)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    // TODO: eglCopyBuffers()
-    return EGL_FALSE;
-}
-
-EGLint eglGetError(void)
-{
-    return getError();
-}
-
-const char* eglQueryString(EGLDisplay dpy, EGLint name)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, (const char*)0);
-
-    switch (name) {
-        case EGL_VENDOR:
-            return gVendorString;
-        case EGL_VERSION:
-            return gVersionString;
-        case EGL_EXTENSIONS:
-            return gExtensionsString;
-        case EGL_CLIENT_APIS:
-            return gClientApiString;
-    }
-    return setError(EGL_BAD_PARAMETER, (const char *)0);
-}
-
-// ----------------------------------------------------------------------------
-// EGL 1.1
-// ----------------------------------------------------------------------------
-
-EGLBoolean eglSurfaceAttrib(
-        EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    // TODO: eglSurfaceAttrib()
-    return setError(EGL_BAD_PARAMETER, EGL_FALSE);
-}
-
-EGLBoolean eglBindTexImage(
-        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    // TODO: eglBindTexImage()
-    return setError(EGL_BAD_PARAMETER, EGL_FALSE);
-}
-
-EGLBoolean eglReleaseTexImage(
-        EGLDisplay dpy, EGLSurface surface, EGLint buffer)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    // TODO: eglReleaseTexImage()
-    return setError(EGL_BAD_PARAMETER, EGL_FALSE);
-}
-
-EGLBoolean eglSwapInterval(EGLDisplay dpy, EGLint interval)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    // TODO: eglSwapInterval()
-    return EGL_TRUE;
-}
-
-// ----------------------------------------------------------------------------
-// EGL 1.2
-// ----------------------------------------------------------------------------
-
-EGLBoolean eglBindAPI(EGLenum api)
-{
-    if (api != EGL_OPENGL_ES_API)
-        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
-    return EGL_TRUE;
-}
-
-EGLenum eglQueryAPI(void)
-{
-    return EGL_OPENGL_ES_API;
-}
-
-EGLBoolean eglWaitClient(void)
-{
-    glFinish();
-    return EGL_TRUE;
-}
-
-EGLBoolean eglReleaseThread(void)
-{
-    // TODO: eglReleaseThread()
-    return EGL_TRUE;
-}
-
-EGLSurface eglCreatePbufferFromClientBuffer(
-        EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
-        EGLConfig config, const EGLint *attrib_list)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_NO_SURFACE);
-    // TODO: eglCreatePbufferFromClientBuffer()
-    return setError(EGL_BAD_PARAMETER, EGL_NO_SURFACE);
-}
-
-// ----------------------------------------------------------------------------
-// EGL_EGLEXT_VERSION 3
-// ----------------------------------------------------------------------------
-
-void (*eglGetProcAddress (const char *procname))()
-        {
-    extention_map_t const * const map = gExtentionMap;
-    for (uint32_t i=0 ; i<NELEM(gExtentionMap) ; i++) {
-        if (!strcmp(procname, map[i].name)) {
-            return map[i].address;
-        }
-    }
-    return NULL;
-        }
-
-EGLBoolean eglLockSurfaceKHR(EGLDisplay dpy, EGLSurface surface,
-        const EGLint *attrib_list)
-{
-    EGLBoolean result = EGL_FALSE;
-    return result;
-}
-
-EGLBoolean eglUnlockSurfaceKHR(EGLDisplay dpy, EGLSurface surface)
-{
-    EGLBoolean result = EGL_FALSE;
-    return result;
-}
-
-EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
-        EGLClientBuffer buffer, const EGLint *attrib_list)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
-        return setError(EGL_BAD_DISPLAY, EGL_NO_IMAGE_KHR);
-    }
-    if (ctx != EGL_NO_CONTEXT) {
-        return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
-    }
-    if (target != EGL_NATIVE_BUFFER_ANDROID) {
-        return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
-    }
-
-    ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)buffer;
-
-    if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
-        return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
-
-    if (native_buffer->common.version != sizeof(ANativeWindowBuffer))
-        return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
-
-    switch (native_buffer->format) {
-        case HAL_PIXEL_FORMAT_RGBA_8888:
-        case HAL_PIXEL_FORMAT_RGBX_8888:
-        case HAL_PIXEL_FORMAT_RGB_888:
-        case HAL_PIXEL_FORMAT_RGB_565:
-        case HAL_PIXEL_FORMAT_BGRA_8888:
-        case HAL_PIXEL_FORMAT_RGBA_5551:
-        case HAL_PIXEL_FORMAT_RGBA_4444:
-            break;
-        default:
-            return setError(EGL_BAD_PARAMETER, EGL_NO_IMAGE_KHR);
-    }
-
-    native_buffer->common.incRef(&native_buffer->common);
-    return (EGLImageKHR)native_buffer;
-}
-
-EGLBoolean eglDestroyImageKHR(EGLDisplay dpy, EGLImageKHR img)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE) {
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    }
-
-    ANativeWindowBuffer* native_buffer = (ANativeWindowBuffer*)img;
-
-    if (native_buffer->common.magic != ANDROID_NATIVE_BUFFER_MAGIC)
-        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
-
-    if (native_buffer->common.version != sizeof(ANativeWindowBuffer))
-        return setError(EGL_BAD_PARAMETER, EGL_FALSE);
-
-    native_buffer->common.decRef(&native_buffer->common);
-
-    return EGL_TRUE;
-}
-
-// ----------------------------------------------------------------------------
-// ANDROID extensions
-// ----------------------------------------------------------------------------
-
-EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
-        EGLint left, EGLint top, EGLint width, EGLint height)
-{
-    if (egl_display_t::is_valid(dpy) == EGL_FALSE)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
-    egl_surface_t* d = static_cast<egl_surface_t*>(draw);
-    if (!d->isValid())
-        return setError(EGL_BAD_SURFACE, EGL_FALSE);
-    if (d->dpy != dpy)
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-
-    // post the surface
-    d->setSwapRectangle(left, top, width, height);
-
-    return EGL_TRUE;
-}
diff --git a/opengl/libagl2/src/get.cpp b/opengl/libagl2/src/get.cpp
deleted file mode 100644
index 13c28ce..0000000
--- a/opengl/libagl2/src/get.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-#include "gles2context.h"
-
-static char const * const gVendorString     = "Android";
-static char const * const gRendererString   = "Android PixelFlinger2 0.0";
-static char const * const gVersionString    = "OpenGL ES 2.0";
-static char const * const gExtensionsString =
-//   "GL_OES_byte_coordinates "              // OK
-//   "GL_OES_fixed_point "                   // OK
-//   "GL_OES_single_precision "              // OK
-//   "GL_OES_read_format "                   // OK
-//   "GL_OES_compressed_paletted_texture "   // OK
-//   "GL_OES_draw_texture "                  // OK
-//   "GL_OES_matrix_get "                    // OK
-//   "GL_OES_query_matrix "                  // OK
-//   //        "GL_OES_point_size_array "              // TODO
-//   //        "GL_OES_point_sprite "                  // TODO
-//   "GL_OES_EGL_image "                     // OK
-//#ifdef GL_OES_compressed_ETC1_RGB8_texture
-//   "GL_OES_compressed_ETC1_RGB8_texture "  // OK
-//#endif
-//   "GL_ARB_texture_compression "           // OK
-//   "GL_ARB_texture_non_power_of_two "      // OK
-//   "GL_ANDROID_user_clip_plane "           // OK
-//   "GL_ANDROID_vertex_buffer_object "      // OK
-//   "GL_ANDROID_generate_mipmap "           // OK
-   ""
-   ;
-
-void glGetIntegerv(GLenum pname, GLint* params)
-{
-   switch (pname) {
-   case GL_MAX_TEXTURE_SIZE :
-      *params = 4096; // limit is in precision of texcoord calculation, which uses 16.16
-      break;
-   case GL_MAX_VERTEX_ATTRIBS:
-      *params = GGL_MAXVERTEXATTRIBS;
-      break;
-   case GL_MAX_VERTEX_UNIFORM_VECTORS:
-      *params = GGL_MAXVERTEXUNIFORMVECTORS;
-      break;
-   case GL_MAX_VARYING_VECTORS:
-      *params = GGL_MAXVARYINGVECTORS;
-      break;
-   case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
-      *params = GGL_MAXCOMBINEDTEXTUREIMAGEUNITS;
-      break;
-   case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
-      *params = GGL_MAXVERTEXTEXTUREIMAGEUNITS;
-      break;
-   case GL_MAX_TEXTURE_IMAGE_UNITS:
-      *params = GGL_MAXTEXTUREIMAGEUNITS;
-      break;
-   case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
-      *params = GGL_MAXFRAGMENTUNIFORMVECTORS;
-      break;
-   case GL_ALIASED_LINE_WIDTH_RANGE:
-      *params = 1; // TODO: not implemented
-      break;
-   default:
-      LOGD("agl2: glGetIntegerv 0x%.4X", pname);
-      assert(0);
-   }
-}
-
-const GLubyte* glGetString(GLenum name)
-{
-   switch (name) {
-   case GL_VENDOR:
-      return (const GLubyte*)gVendorString;
-   case GL_RENDERER:
-      return (const GLubyte*)gRendererString;
-   case GL_VERSION:
-      return (const GLubyte*)gVersionString;
-   case GL_EXTENSIONS:
-      return (const GLubyte*)gExtensionsString;
-   }
-   assert(0); //(c, GL_INVALID_ENUM);
-   return 0;
-}
diff --git a/opengl/libagl2/src/gles2context.h b/opengl/libagl2/src/gles2context.h
deleted file mode 100644
index cec0340..0000000
--- a/opengl/libagl2/src/gles2context.h
+++ /dev/null
@@ -1,166 +0,0 @@
-#define _SIZE_T_DEFINED_
-typedef unsigned int size_t;
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#include <GLES/gl.h>
-#include <GLES/glext.h>
-
-#include <utils/threads.h>
-#include <pthread.h>
-
-#include <cutils/log.h>
-
-#include <assert.h>
-
-#ifdef __arm__
-#ifndef __location__
-#define __HIERALLOC_STRING_0__(s)   #s
-#define __HIERALLOC_STRING_1__(s)   __HIERALLOC_STRING_0__(s)
-#define __HIERALLOC_STRING_2__      __HIERALLOC_STRING_1__(__LINE__)
-#define __location__                __FILE__ ":" __HIERALLOC_STRING_2__
-#endif
-#undef assert
-#define assert(EXPR) { do { if (!(EXPR)) {LOGD("\n*\n*\n*\n* assert fail: '"#EXPR"' at "__location__"\n*\n*\n*\n*"); exit(EXIT_FAILURE); } } while (false); }
-//#define printf LOGD
-#else // #ifdef __arm__
-//#define LOGD printf
-#endif // #ifdef __arm__
-
-
-#include <pixelflinger2/pixelflinger2_format.h>
-#include <pixelflinger2/pixelflinger2.h>
-
-#include <map>
-
-typedef uint8_t                 GGLubyte;               // ub
-
-#define ggl_likely(x)   __builtin_expect(!!(x), 1)
-#define ggl_unlikely(x) __builtin_expect(!!(x), 0)
-
-#undef NELEM
-#define NELEM(x) (sizeof(x)/sizeof(*(x)))
-
-template<typename T>
-inline T max(T a, T b)
-{
-   return a<b ? b : a;
-}
-
-template<typename T>
-inline T min(T a, T b)
-{
-   return a<b ? a : b;
-}
-
-struct egl_context_t {
-   enum {
-      IS_CURRENT      =   0x00010000,
-      NEVER_CURRENT   =   0x00020000
-   };
-   uint32_t            flags;
-   EGLDisplay          dpy;
-   EGLConfig           config;
-   EGLSurface          read;
-   EGLSurface          draw;
-
-   unsigned frame;
-   clock_t lastSwapTime;
-   float accumulateSeconds;
-   
-   static inline egl_context_t* context(EGLContext ctx);
-};
-
-struct GLES2Context;
-
-#ifdef HAVE_ANDROID_OS
-#include <bionic_tls.h>
-// We have a dedicated TLS slot in bionic
-inline void setGlThreadSpecific(GLES2Context *value)
-{
-   ((uint32_t *)__get_tls())[TLS_SLOT_OPENGL] = (uint32_t)value;
-}
-inline GLES2Context* getGlThreadSpecific()
-{
-   return (GLES2Context *)(((unsigned *)__get_tls())[TLS_SLOT_OPENGL]);
-}
-#else
-extern pthread_key_t gGLKey;
-inline void setGlThreadSpecific(GLES2Context *value)
-{
-   pthread_setspecific(gGLKey, value);
-}
-inline GLES2Context* getGlThreadSpecific()
-{
-   return static_cast<GLES2Context*>(pthread_getspecific(gGLKey));
-}
-#endif
-
-struct VBO {
-   unsigned size;
-   GLenum usage;
-   void * data;
-};
-
-struct GLES2Context {
-   GGLContext rasterizer;
-   egl_context_t egl;
-   GGLInterface * iface; // shortcut to &rasterizer.interface
-
-   struct VertexState {
-      struct VertAttribPointer {
-         unsigned size; // number of values per vertex
-         GLenum type;  // data type
-         unsigned stride; // bytes
-         const void * ptr;
-bool normalized :
-         1;
-bool enabled :
-         1;
-      } attribs [GGL_MAXVERTEXATTRIBS];
-
-      VBO * vbo, * indices;
-      std::map<GLuint, VBO *> vbos;
-      GLuint free;
-
-      Vector4 defaultAttribs [GGL_MAXVERTEXATTRIBS];
-   } vert;
-
-   struct TextureState {
-      GGLTexture * tmus[GGL_MAXCOMBINEDTEXTUREIMAGEUNITS];
-      int sampler2tmu[GGL_MAXCOMBINEDTEXTUREIMAGEUNITS]; // sampler2tmu[sampler] is index of tmu, -1 means not used
-      unsigned active;
-      std::map<GLuint, GGLTexture *> textures;
-      GLuint free; // first possible free name
-      GGLTexture * tex2D, * texCube; // default textures
-      unsigned unpack;
-      
-      void UpdateSampler(GGLInterface * iface, unsigned tmu);
-   } tex;
-
-   GLES2Context();
-   void InitializeTextures();
-   void InitializeVertices();
-
-   ~GLES2Context();
-   void UninitializeTextures();
-   void UninitializeVertices();
-
-   static inline GLES2Context* get() {
-      return getGlThreadSpecific();
-   }
-};
-
-inline egl_context_t* egl_context_t::context(EGLContext ctx)
-{
-   GLES2Context* const gl = static_cast<GLES2Context*>(ctx);
-   return static_cast<egl_context_t*>(&gl->egl);
-}
-
-#define GLES2_GET_CONTEXT(ctx) GLES2Context * ctx = GLES2Context::get(); \
-                                 /*puts(__FUNCTION__);*/
-#define GLES2_GET_CONST_CONTEXT(ctx) GLES2Context * ctx = GLES2Context::get(); \
-                                       /*puts(__FUNCTION__);*/
diff --git a/opengl/libagl2/src/shader.cpp b/opengl/libagl2/src/shader.cpp
deleted file mode 100644
index 076e388..0000000
--- a/opengl/libagl2/src/shader.cpp
+++ /dev/null
@@ -1,191 +0,0 @@
-#include "gles2context.h"
-
-//#undef LOGD
-//#define LOGD(...)
-
-static inline GLuint s2n(gl_shader * s)
-{
-   return (GLuint)s ^ 0xaf3c532d;
-}
-
-static inline gl_shader * n2s(GLuint n)
-{
-   return (gl_shader *)(n ^ 0xaf3c532d);
-}
-
-static inline GLuint p2n(gl_shader_program * p)
-{
-   return (GLuint)p ^ 0x04dc18f9;
-}
-
-static inline gl_shader_program * n2p(GLuint n)
-{
-   return (gl_shader_program *)(n ^ 0x04dc18f9);
-}
-
-void glAttachShader(GLuint program, GLuint shader)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ShaderAttach(ctx->iface, n2p(program), n2s(shader));
-}
-
-void glBindAttribLocation(GLuint program, GLuint index, const GLchar* name)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ShaderAttributeBind(n2p(program), index, name);
-//   assert(0);
-}
-
-GLuint glCreateShader(GLenum type)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   return s2n(ctx->iface->ShaderCreate(ctx->iface, type));
-}
-
-GLuint glCreateProgram(void)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   return  p2n(ctx->iface->ShaderProgramCreate(ctx->iface));
-}
-
-void glCompileShader(GLuint shader)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ShaderCompile(ctx->iface, n2s(shader), NULL, NULL);
-}
-
-void glDeleteProgram(GLuint program)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ShaderProgramDelete(ctx->iface, n2p(program));
-}
-
-void glDeleteShader(GLuint shader)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ShaderDelete(ctx->iface, n2s(shader));
-}
-
-void glDetachShader(GLuint program, GLuint shader)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ShaderDetach(ctx->iface, n2p(program), n2s(shader));
-}
-
-GLint glGetAttribLocation(GLuint program, const GLchar* name)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   GLint location = ctx->iface->ShaderAttributeLocation(n2p(program), name);
-//   LOGD("\n*\n*\n* agl2: glGetAttribLocation program=%u name=%s location=%d \n*\n*",
-//        program, name, location);
-   return location;
-}
-
-void glGetProgramiv(GLuint program, GLenum pname, GLint* params)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ShaderProgramGetiv(n2p(program), pname, params);
-   LOGD("agl2: glGetProgramiv 0x%.4X=%d \n", pname, *params);
-}
-
-void glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ShaderProgramGetInfoLog(n2p(program), bufsize, length, infolog);
-}
-
-void glGetShaderiv(GLuint shader, GLenum pname, GLint* params)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ShaderGetiv(n2s(shader), pname, params);
-   LOGD("agl2: glGetShaderiv 0x%.4X=%d \n", pname, *params);
-}
-
-void glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ShaderGetInfoLog(n2s(shader), bufsize, length, infolog);
-}
-
-int glGetUniformLocation(GLuint program, const GLchar* name)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   return ctx->iface->ShaderUniformLocation(n2p(program), name);
-}
-
-void glLinkProgram(GLuint program)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   GLboolean linked = ctx->iface->ShaderProgramLink(n2p(program), NULL);
-   assert(linked);
-}
-
-void glShaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint* length)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ShaderSource(n2s(shader), count, string, length);
-}
-
-void glUniform1f(GLint location, GLfloat x)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   int sampler = ctx->iface->ShaderUniform(ctx->rasterizer.CurrentProgram, location, 1, &x, GL_FLOAT);
-   assert(0 > sampler); // should be assigning to sampler
-}
-
-void glUniform1i(GLint location, GLint x)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   const float params[1] = {x};
-   int sampler = ctx->iface->ShaderUniform(ctx->rasterizer.CurrentProgram, location, 1, params, GL_INT);
-   if (0 <= sampler) {
-//      LOGD("\n*\n* agl2: glUniform1i updated sampler=%d tmu=%d location=%d\n*", sampler, x, location);
-      assert(0 <= x && GGL_MAXCOMBINEDTEXTUREIMAGEUNITS > x);
-//      LOGD("tmu%u: format=0x%.2X w=%u h=%u levels=%p", x, ctx->tex.tmus[x]->format, 
-//         ctx->tex.tmus[x]->width, ctx->tex.tmus[x]->height, ctx->tex.tmus[x]->format);
-      ctx->tex.sampler2tmu[sampler] = x;
-      ctx->tex.UpdateSampler(ctx->iface, x);
-   }
-}
-
-void glUniform2f(GLint location, GLfloat x, GLfloat y)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   const float params[4] = {x, y};
-   ctx->iface->ShaderUniform(ctx->rasterizer.CurrentProgram, location, 1, params, GL_FLOAT_VEC2);
-}
-
-void glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   const float params[4] = {x, y, z, w};
-//   LOGD("agl2: glUniform4f location=%d %f,%f,%f,%f", location, x, y, z, w);
-   ctx->iface->ShaderUniform(ctx->rasterizer.CurrentProgram, location, 1, params, GL_FLOAT_VEC4);
-}
-
-void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-//   const gl_shader_program * program = ctx->rasterizer.CurrentProgram;
-//   if (strstr(program->Shaders[MESA_SHADER_FRAGMENT]->Source, ").a;")) {
-//   LOGD("agl2: glUniformMatrix4fv location=%d count=%d transpose=%d", location, count, transpose);
-//   for (unsigned i = 0; i < 4; i++)
-//      LOGD("agl2: glUniformMatrix4fv %.2f \t %.2f \t %.2f \t %.2f", value[i * 4 + 0],
-//           value[i * 4 + 1], value[i * 4 + 2], value[i * 4 + 3]);
-//   }
-   ctx->iface->ShaderUniformMatrix(ctx->rasterizer.CurrentProgram, 4, 4, location, count, transpose, value);
-//   while (true)
-//      ;
-//   assert(0);
-}
-
-void glUseProgram(GLuint program)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-//   LOGD("\n*\n*\n* agl2: glUseProgram %d \n*\n*\n*", program);
-   ctx->iface->ShaderUse(ctx->iface, n2p(program));
-   ctx->iface->ShaderUniformGetSamplers(n2p(program), ctx->tex.sampler2tmu);
-   for (unsigned i = 0; i < GGL_MAXCOMBINEDTEXTUREIMAGEUNITS; i++)
-      if (0 <= ctx->tex.sampler2tmu[i])
-         ctx->iface->SetSampler(ctx->iface, i, ctx->tex.tmus[ctx->tex.sampler2tmu[i]]);
-}
diff --git a/opengl/libagl2/src/state.cpp b/opengl/libagl2/src/state.cpp
deleted file mode 100644
index 22e73fa..0000000
--- a/opengl/libagl2/src/state.cpp
+++ /dev/null
@@ -1,129 +0,0 @@
-#include "gles2context.h"
-
-GLES2Context::GLES2Context()
-{
-   memset(this, 0, sizeof *this);
-
-   assert((void *)&rasterizer == &rasterizer.interface);
-   InitializeGGLState(&rasterizer.interface);
-   iface = &rasterizer.interface;
-   printf("gl->rasterizer.PickScanLine(%p) = %p \n", &rasterizer.PickScanLine, rasterizer.PickScanLine);
-   assert(rasterizer.PickRaster);
-   assert(rasterizer.PickScanLine);
-
-   InitializeTextures();
-   InitializeVertices();
-}
-
-GLES2Context::~GLES2Context()
-{
-   UninitializeTextures();
-   UninitializeVertices();
-   UninitializeGGLState(&rasterizer.interface);
-}
-
-void glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->BlendColor(ctx->iface, red, green, blue, alpha);
-}
-
-void glBlendEquation( GLenum mode )
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->BlendEquationSeparate(ctx->iface, mode, mode);
-}
-
-void glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->BlendEquationSeparate(ctx->iface, modeRGB, modeAlpha);
-}
-
-void glBlendFunc(GLenum sfactor, GLenum dfactor)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->BlendFuncSeparate(ctx->iface, sfactor, dfactor, sfactor, dfactor);
-}
-
-void glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->BlendFuncSeparate(ctx->iface, srcRGB, dstRGB, srcAlpha, dstAlpha);
-}
-
-void glClear(GLbitfield mask)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->Clear(ctx->iface, mask);
-}
-
-void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ClearColor(ctx->iface, red, green, blue, alpha);
-}
-
-void glClearDepthf(GLclampf depth)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ClearDepthf(ctx->iface, depth);
-}
-
-void glClearStencil(GLint s)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->ClearStencil(ctx->iface, s);
-}
-
-void glCullFace(GLenum mode)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->CullFace(ctx->iface, mode);
-}
-
-void glDisable(GLenum cap)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->EnableDisable(ctx->iface, cap, false);
-}
-
-void glEnable(GLenum cap)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->EnableDisable(ctx->iface, cap, true);
-}
-
-void glFinish(void)
-{
-   // do nothing
-}
-
-void glFrontFace(GLenum mode)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->iface->FrontFace(ctx->iface, mode);
-}
-
-void glFlush(void)
-{
-   // do nothing
-}
-
-void glHint(GLenum target, GLenum mode)
-{
-   // do nothing
-}
-
-void glScissor(GLint x, GLint y, GLsizei width, GLsizei height)
-{
-//   LOGD("agl2: glScissor not implemented x=%d y=%d width=%d height=%d", x, y, width, height);
-   //CALL_GL_API(glScissor, x, y, width, height);
-}
-
-void glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-//   LOGD("agl2: glViewport x=%d y=%d width=%d height=%d", x, y, width, height);
-   ctx->iface->Viewport(ctx->iface, x, y, width, height);
-}
diff --git a/opengl/libagl2/src/texture.cpp b/opengl/libagl2/src/texture.cpp
deleted file mode 100644
index 4de1f16..0000000
--- a/opengl/libagl2/src/texture.cpp
+++ /dev/null
@@ -1,534 +0,0 @@
-#include "gles2context.h"
-
-//#undef LOGD
-//#define LOGD(...) 
-
-#define API_ENTRY
-#define CALL_GL_API(NAME,...) LOGD("?"#NAME); assert(0);
-#define CALL_GL_API_RETURN(NAME,...) LOGD("?"#NAME); assert(0); return 0;
-
-static inline GGLTexture * AllocTexture()
-{
-   GGLTexture * tex = (GGLTexture *)calloc(1, sizeof(GGLTexture));
-   tex->minFilter = GGLTexture::GGL_LINEAR; // should be NEAREST_ MIPMAP_LINEAR
-   tex->magFilter = GGLTexture::GGL_LINEAR;
-   return tex;
-}
-
-void GLES2Context::InitializeTextures()
-{
-   tex.textures = std::map<GLuint, GGLTexture *>(); // the entire struct has been zeroed in constructor
-   tex.tex2D = AllocTexture();
-   tex.textures[GL_TEXTURE_2D] = tex.tex2D;
-   tex.texCube = AllocTexture();
-   tex.textures[GL_TEXTURE_CUBE_MAP] = tex.texCube;
-   for (unsigned i = 0; i < GGL_MAXCOMBINEDTEXTUREIMAGEUNITS; i++) {
-      tex.tmus[i] = NULL;
-      tex.sampler2tmu[i] = NULL;
-   }
-
-   tex.active = 0;
-
-   tex.free = max(GL_TEXTURE_2D, GL_TEXTURE_CUBE_MAP) + 1;
-
-   tex.tex2D->format = GGL_PIXEL_FORMAT_RGBA_8888;
-   tex.tex2D->type = GL_TEXTURE_2D;
-   tex.tex2D->levelCount = 1;
-   tex.tex2D->wrapS = tex.tex2D->wrapT = GGLTexture::GGL_REPEAT;
-   tex.tex2D->minFilter = tex.tex2D->magFilter = GGLTexture::GGL_NEAREST;
-   tex.tex2D->width = tex.tex2D->height = 1;
-   tex.tex2D->levels = malloc(4);
-   *(unsigned *)tex.tex2D->levels = 0xff000000;
-
-
-   tex.texCube->format = GGL_PIXEL_FORMAT_RGBA_8888;
-   tex.texCube->type = GL_TEXTURE_CUBE_MAP;
-   tex.texCube->levelCount = 1;
-   tex.texCube->wrapS = tex.texCube->wrapT = GGLTexture::GGL_REPEAT;
-   tex.texCube->minFilter = tex.texCube->magFilter = GGLTexture::GGL_NEAREST;
-   tex.texCube->width = tex.texCube->height = 1;
-   tex.texCube->levels = malloc(4 * 6);
-   static unsigned texels [6] = {0xff0000ff, 0xff00ff00, 0xffff0000,
-                                 0xff00ffff, 0xffffff00, 0xffff00ff
-                                };
-   memcpy(tex.texCube->levels, texels, sizeof texels);
-
-   //texture.levelCount = GenerateMipmaps(texture.levels, texture.width, texture.height);
-
-   //    static unsigned texels [6] = {0xff0000ff, 0xff00ff00, 0xffff0000,
-   //    0xff00ffff, 0xffffff00, 0xffff00ff};
-   //    memcpy(texture.levels[0], texels, sizeof texels);
-   //    texture.format = GGL_PIXEL_FORMAT_RGBA_8888;
-   //    texture.width = texture.height = 1;
-   //texture.height /= 6;
-   //texture.type = GL_TEXTURE_CUBE_MAP;
-   
-   tex.unpack = 4;
-}
-
-void GLES2Context::TextureState::UpdateSampler(GGLInterface * iface, unsigned tmu)
-{
-   for (unsigned i = 0; i < GGL_MAXCOMBINEDTEXTUREIMAGEUNITS; i++)
-      if (tmu == sampler2tmu[i])
-         iface->SetSampler(iface, i, tmus[tmu]);
-}
-
-void GLES2Context::UninitializeTextures()
-{
-   for (std::map<GLuint, GGLTexture *>::iterator it = tex.textures.begin(); it != tex.textures.end(); it++) {
-      if (!it->second)
-         continue;
-      free(it->second->levels);
-      free(it->second);
-   }
-}
-
-static inline void GetFormatAndBytesPerPixel(const GLenum format, unsigned * bytesPerPixel,
-      GGLPixelFormat * texFormat)
-{
-   switch (format) {
-   case GL_ALPHA:
-      *texFormat = GGL_PIXEL_FORMAT_A_8;
-      *bytesPerPixel = 1;
-      break;
-   case GL_LUMINANCE:
-      *texFormat = GGL_PIXEL_FORMAT_L_8;
-      *bytesPerPixel = 1;
-      break;
-   case GL_LUMINANCE_ALPHA:
-      *texFormat = GGL_PIXEL_FORMAT_LA_88;
-      *bytesPerPixel = 2;
-      break;
-   case GL_RGB:
-      *texFormat = GGL_PIXEL_FORMAT_RGB_888;
-      *bytesPerPixel = 3;
-      break;
-   case GL_RGBA:
-      *texFormat = GGL_PIXEL_FORMAT_RGBA_8888;
-      *bytesPerPixel = 4;
-      break;
-
-      // internal formats to avoid conversion
-   case GL_UNSIGNED_SHORT_5_6_5:
-      *texFormat = GGL_PIXEL_FORMAT_RGB_565;
-      *bytesPerPixel = 2;
-      break;
-
-   default:
-      assert(0);
-      return;
-   }
-}
-
-static inline void CopyTexture(char * dst, const char * src, const unsigned bytesPerPixel,
-                               const unsigned sx, const unsigned sy,  const unsigned sw,
-                               const unsigned dx, const unsigned dy, const unsigned dw,
-                               const unsigned w, const unsigned h)
-{
-   const unsigned bpp = bytesPerPixel;
-   if (dw == sw && dw == w && sx == 0 && dx == 0)
-      memcpy(dst + dy * dw * bpp, src + sy * sw * bpp, w * h * bpp);
-   else
-      for (unsigned y = 0; y < h; y++)
-         memcpy(dst + ((dy + y) * dw + dx) * bpp, src + ((sy + y) * sw + sx) * bpp, w * bpp); 
-}
-
-void glActiveTexture(GLenum texture)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   unsigned index = texture - GL_TEXTURE0;
-   assert(NELEM(ctx->tex.tmus) > index);
-//   LOGD("agl2: glActiveTexture %u", index);
-   ctx->tex.active = index;
-}
-
-void glBindTexture(GLenum target, GLuint texture)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-//   LOGD("agl2: glBindTexture target=0x%.4X texture=%u active=%u", target, texture, ctx->tex.active);
-   std::map<GLuint, GGLTexture *>::iterator it = ctx->tex.textures.find(texture);
-   GGLTexture * tex = NULL;
-   if (it != ctx->tex.textures.end()) {
-      tex = it->second;
-      if (!tex) {
-         tex = AllocTexture();
-         tex->type = target;
-         it->second = tex;
-//         LOGD("agl2: glBindTexture allocTexture");
-      }
-//      else
-//         LOGD("agl2: glBindTexture bind existing texture");
-      assert(target == tex->type);
-   } else if (0 == texture) {
-      if (GL_TEXTURE_2D == target)
-      {
-         tex = ctx->tex.tex2D;
-//         LOGD("agl2: glBindTexture bind default tex2D");
-      }
-      else if (GL_TEXTURE_CUBE_MAP == target)
-      {
-         tex = ctx->tex.texCube;
-//         LOGD("agl2: glBindTexture bind default texCube");
-      }
-      else
-         assert(0);
-   } else {
-      if (texture <= ctx->tex.free)
-         ctx->tex.free = texture + 1;
-      tex = AllocTexture();
-      tex->type = target;
-      ctx->tex.textures[texture] = tex;
-//      LOGD("agl2: glBindTexture new texture=%u", texture);
-   }
-   ctx->tex.tmus[ctx->tex.active] = tex;
-//   LOGD("agl2: glBindTexture format=0x%.2X w=%u h=%u levels=%p", tex->format,
-//      tex->width, tex->height, tex->levels);
-   ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active);
-}
-
-void API_ENTRY(glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data)
-{
-   CALL_GL_API(glCompressedTexImage2D, target, level, internalformat, width, height, border, imageSize, data);
-}
-
-void API_ENTRY(glCompressedTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data)
-{
-   CALL_GL_API(glCompressedTexSubImage2D, target, level, xoffset, yoffset, width, height, format, imageSize, data);
-}
-
-void glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat,
-                      GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-//   LOGD("agl2: glCopyTexImage2D target=0x%.4X internalformat=0x%.4X", target, internalformat);
-//   LOGD("x=%d y=%d width=%d height=%d border=%d level=%d ", x, y, width, height, border, level);
-   assert(0 == border);
-   assert(0 == level);
-   unsigned bytesPerPixel = 0;
-   GGLPixelFormat texFormat = GGL_PIXEL_FORMAT_UNKNOWN;
-   GetFormatAndBytesPerPixel(internalformat, &bytesPerPixel, &texFormat);
-
-   assert(texFormat == ctx->rasterizer.frameSurface.format);
-//   LOGD("texFormat=0x%.2X bytesPerPixel=%d \n", texFormat, bytesPerPixel);
-   unsigned offset = 0, size = width * height * bytesPerPixel, totalSize = size;
-
-   assert(ctx->tex.tmus[ctx->tex.active]);
-   assert(y + height <= ctx->rasterizer.frameSurface.height);
-   assert(x + width <= ctx->rasterizer.frameSurface.width);
-   GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active];
-   tex.width = width;
-   tex.height = height;
-   tex.levelCount = 1;
-   tex.format = texFormat;
-   switch (target) {
-   case GL_TEXTURE_2D:
-      tex.levels = realloc(tex.levels, totalSize);
-      CopyTexture((char *)tex.levels, (const char *)ctx->rasterizer.frameSurface.data, bytesPerPixel,
-                  x, y, ctx->rasterizer.frameSurface.width, 0, 0, width, width, height);
-      break;
-   default:
-      assert(0);
-      return;
-   }
-   ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active);
-}
-
-void glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
-{
-   // x, y are src offset
-   // xoffset and yoffset are dst offset
-   GLES2_GET_CONST_CONTEXT(ctx);
-//   LOGD("agl2: glCopyTexSubImage2D target=0x%.4X level=%d", target, level);
-//   LOGD("xoffset=%d yoffset=%d x=%d y=%d width=%d height=%d", xoffset, yoffset, x, y, width, height);
-   assert(0 == level);
-
-   unsigned bytesPerPixel = 4;
-   unsigned offset = 0, size = width * height * bytesPerPixel, totalSize = size;
-
-   assert(ctx->tex.tmus[ctx->tex.active]);
-   GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active];
-
-   assert(tex.format == ctx->rasterizer.frameSurface.format);
-   assert(GGL_PIXEL_FORMAT_RGBA_8888 == tex.format);
-
-   const unsigned srcWidth = ctx->rasterizer.frameSurface.width;
-   const unsigned srcHeight = ctx->rasterizer.frameSurface.height;
-
-   assert(x >= 0 && y >= 0);
-   assert(xoffset >= 0 && yoffset >= 0);
-   assert(x + width <= srcWidth);
-   assert(y + height <= srcHeight);
-   assert(xoffset + width <= tex.width);
-   assert(yoffset + height <= tex.height);
-
-   switch (target) {
-   case GL_TEXTURE_2D:
-      CopyTexture((char *)tex.levels, (const char *)ctx->rasterizer.frameSurface.data, bytesPerPixel,
-                  x, y, srcWidth, xoffset, yoffset, tex.width, width, height);
-      break;
-   default:
-      assert(0);
-      return;
-   }
-   ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active);
-}
-
-void glDeleteTextures(GLsizei n, const GLuint* textures)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   for (unsigned i = 0; i < n; i++) {
-      std::map<GLuint, GGLTexture *>::iterator it = ctx->tex.textures.find(textures[i]);
-      if (it == ctx->tex.textures.end())
-         continue;
-      ctx->tex.free = min(ctx->tex.free, textures[i]);
-      for (unsigned i = 0; i <  GGL_MAXCOMBINEDTEXTUREIMAGEUNITS; i++)
-         if (ctx->tex.tmus[i] == it->second) {
-            if (GL_TEXTURE_2D == it->second->type)
-               ctx->tex.tmus[i] = ctx->tex.tex2D;
-            else if (GL_TEXTURE_CUBE_MAP == it->second->type)
-               ctx->tex.tmus[i] = ctx->tex.texCube;
-            else
-               assert(0);
-            ctx->tex.UpdateSampler(ctx->iface, i);
-         }
-      if (it->second) {
-         free(it->second->levels);
-         free(it->second);
-      }
-      ctx->tex.textures.erase(it);
-   }
-}
-
-void glGenTextures(GLsizei n, GLuint* textures)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   for (unsigned i = 0; i < n; i++) {
-      textures[i] = 0;
-      for (ctx->tex.free; ctx->tex.free < 0xffffffffu; ctx->tex.free++)
-         if (ctx->tex.textures.find(ctx->tex.free) == ctx->tex.textures.end()) {
-            ctx->tex.textures[ctx->tex.free] = NULL;
-            textures[i] = ctx->tex.free;
-            ctx->tex.free++;
-            break;
-         }
-      assert(textures[i]);
-   }
-}
-
-void API_ENTRY(glGetTexParameterfv)(GLenum target, GLenum pname, GLfloat* params)
-{
-   CALL_GL_API(glGetTexParameterfv, target, pname, params);
-}
-void API_ENTRY(glGetTexParameteriv)(GLenum target, GLenum pname, GLint* params)
-{
-   CALL_GL_API(glGetTexParameteriv, target, pname, params);
-}
-
-GLboolean glIsTexture(GLuint texture)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   if (ctx->tex.textures.find(texture) == ctx->tex.textures.end())
-      return GL_FALSE;
-   else
-      return GL_TRUE;
-}
-
-void glPixelStorei(GLenum pname, GLint param)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   assert(GL_UNPACK_ALIGNMENT == pname);
-   assert(1 == param || 2 == param || 4 == param || 8 == param);
-//   LOGD("\n*\n* agl2: glPixelStorei not implemented pname=0x%.4X param=%d \n*", pname, param);
-   ctx->tex.unpack = param;
-//   CALL_GL_API(glPixelStorei, pname, param);
-}
-void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width,
-                  GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-//   LOGD("agl2: glTexImage2D internalformat=0x%.4X format=0x%.4X type=0x%.4X \n", internalformat, format, type);
-//   LOGD("width=%d height=%d border=%d level=%d pixels=%p \n", width, height, border, level, pixels);
-   switch (type) {
-   case GL_UNSIGNED_BYTE:
-      break;
-   case GL_UNSIGNED_SHORT_5_6_5:
-      internalformat = format = GL_UNSIGNED_SHORT_5_6_5;
-      assert(4 == ctx->tex.unpack);
-      break;
-   default:
-      assert(0);
-   }
-   assert(internalformat == format);
-   assert(0 == border);
-   if (0 != level) {
-      LOGD("agl2: glTexImage2D level=%d", level);
-      return;
-   }
-   unsigned bytesPerPixel = 0;
-   GGLPixelFormat texFormat = GGL_PIXEL_FORMAT_UNKNOWN;
-   GetFormatAndBytesPerPixel(format, &bytesPerPixel, &texFormat);
-
-   assert(texFormat && bytesPerPixel);
-//   LOGD("texFormat=0x%.2X bytesPerPixel=%d active=%u", texFormat, bytesPerPixel, ctx->tex.active);
-   unsigned offset = 0, size = width * height * bytesPerPixel, totalSize = size;
-
-   assert(ctx->tex.tmus[ctx->tex.active]);
-
-   GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active];
-   tex.width = width;
-   tex.height = height;
-   tex.levelCount = 1;
-   tex.format = texFormat;
-
-   switch (target) {
-   case GL_TEXTURE_2D:
-      assert(GL_TEXTURE_2D == ctx->tex.tmus[ctx->tex.active]->type);
-      offset = 0;
-      break;
-      break;
-   case GL_TEXTURE_CUBE_MAP_POSITIVE_X:
-   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X:
-   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y:
-   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y:
-   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z:
-   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z:
-      assert(GL_TEXTURE_CUBE_MAP == ctx->tex.tmus[ctx->tex.active]->type);
-      assert(width == height);
-      offset = (target - GL_TEXTURE_CUBE_MAP_POSITIVE_X) * size;
-      totalSize = 6 * size;
-      break;
-   default:
-      assert(0);
-      return;
-   }
-
-   tex.levels = realloc(tex.levels, totalSize);
-   if (pixels)
-      CopyTexture((char *)tex.levels, (const char *)pixels, bytesPerPixel, 0, 0, width, 0, 0, width, width, height);
-   ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active);
-}
-
-void glTexParameterf(GLenum target, GLenum pname, GLfloat param)
-{
-//   LOGD("agl2: glTexParameterf target=0x%.4X pname=0x%.4X param=%f", target, pname, param);
-   glTexParameteri(target, pname, param);
-}
-void API_ENTRY(glTexParameterfv)(GLenum target, GLenum pname, const GLfloat* params)
-{
-   CALL_GL_API(glTexParameterfv, target, pname, params);
-}
-void glTexParameteri(GLenum target, GLenum pname, GLint param)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-//   LOGD("alg2: glTexParameteri target=0x%.0X pname=0x%.4X param=0x%.4X",
-//        target, pname, param);
-   assert(ctx->tex.tmus[ctx->tex.active]);
-   assert(target == ctx->tex.tmus[ctx->tex.active]->type);
-   GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active];
-   switch (pname) {
-   case GL_TEXTURE_WRAP_S:
-   case GL_TEXTURE_WRAP_T:
-      GGLTexture::GGLTextureWrap wrap;
-      switch (param) {
-      case GL_REPEAT:
-         wrap = GGLTexture::GGL_REPEAT;
-         break;
-      case GL_CLAMP_TO_EDGE:
-         wrap = GGLTexture::GGL_CLAMP_TO_EDGE;
-         break;
-      case GL_MIRRORED_REPEAT:
-         wrap = GGLTexture::GGL_MIRRORED_REPEAT;
-         break;
-      default:
-         assert(0);
-         return;
-      }
-      if (GL_TEXTURE_WRAP_S == pname)
-         tex.wrapS = wrap;
-      else
-         tex.wrapT = wrap;
-      break;
-   case GL_TEXTURE_MIN_FILTER:
-      switch (param) {
-      case GL_NEAREST:
-         tex.minFilter = GGLTexture::GGL_NEAREST;
-         break;
-      case GL_LINEAR:
-         tex.minFilter = GGLTexture::GGL_LINEAR;
-         break;
-      case GL_NEAREST_MIPMAP_NEAREST:
-//         tex.minFilter = GGLTexture::GGL_NEAREST_MIPMAP_NEAREST;
-         break;
-      case GL_NEAREST_MIPMAP_LINEAR:
-//         tex.minFilter = GGLTexture::GGL_NEAREST_MIPMAP_LINEAR;
-         break;
-      case GL_LINEAR_MIPMAP_NEAREST:
-//         tex.minFilter = GGLTexture::GGL_LINEAR_MIPMAP_NEAREST;
-         break;
-      case GL_LINEAR_MIPMAP_LINEAR:
-//         tex.minFilter = GGLTexture::GGL_LINEAR_MIPMAP_LINEAR;
-         break;
-      default:
-         assert(0);
-         return;
-      }
-      break;
-   case GL_TEXTURE_MAG_FILTER:
-      switch (param) {
-      case GL_NEAREST:
-         tex.minFilter = GGLTexture::GGL_NEAREST;
-         break;
-      case GL_LINEAR:
-         tex.minFilter = GGLTexture::GGL_LINEAR;
-         break;
-      default:
-         assert(0);
-         return;
-      }
-      break;
-   default:
-      assert(0);
-      return;
-   }
-   // implementation restriction
-   if (tex.magFilter != tex.minFilter)
-      tex.magFilter = tex.minFilter = GGLTexture::GGL_LINEAR;
-   ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active);
-}
-void API_ENTRY(glTexParameteriv)(GLenum target, GLenum pname, const GLint* params)
-{
-   CALL_GL_API(glTexParameteriv, target, pname, params);
-}
-void glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-//   LOGD("agl2: glTexSubImage2D target=0x%.4X level=%d xoffset=%d yoffset=%d width=%d height=%d format=0x%.4X type=0x%.4X pixels=%p",
-//        target, level, xoffset, yoffset, width, height, format, type, pixels);
-   assert(0 == level);
-   assert(target == ctx->tex.tmus[ctx->tex.active]->type);
-   switch (type) {
-   case GL_UNSIGNED_BYTE:
-      break;
-   case GL_UNSIGNED_SHORT_5_6_5:
-      format = GL_UNSIGNED_SHORT_5_6_5;
-      assert(4 == ctx->tex.unpack);
-      break;
-   default:
-      assert(0);
-   }
-   GGLTexture & tex = *ctx->tex.tmus[ctx->tex.active];
-   GGLPixelFormat texFormat = GGL_PIXEL_FORMAT_UNKNOWN;
-   unsigned bytesPerPixel = 0;
-   GetFormatAndBytesPerPixel(format, &bytesPerPixel, &texFormat);
-   assert(texFormat == tex.format);
-   assert(GL_UNSIGNED_BYTE == type);
-   switch (target) {
-   case GL_TEXTURE_2D:
-      CopyTexture((char *)tex.levels, (const char *)pixels, bytesPerPixel, 0, 0, width, xoffset,
-                  yoffset, tex.width, width, height);
-      break;
-   default:
-      assert(0);
-   }
-   ctx->tex.UpdateSampler(ctx->iface, ctx->tex.active);
-}
diff --git a/opengl/libagl2/src/vertex.cpp b/opengl/libagl2/src/vertex.cpp
deleted file mode 100644
index 021b82b..0000000
--- a/opengl/libagl2/src/vertex.cpp
+++ /dev/null
@@ -1,373 +0,0 @@
-#include "gles2context.h"
-
-//#undef LOGD
-//#define LOGD(...)
-
-void GLES2Context::InitializeVertices()
-{
-   vert.vbos = std::map<GLuint, VBO *>(); // the entire struct has been zeroed in constructor
-   vert.free = 1;
-   vert.vbo = NULL;
-   vert.indices = NULL;
-   for (unsigned i = 0; i < GGL_MAXVERTEXATTRIBS; i++)
-      vert.defaultAttribs[i] = Vector4(0,0,0,1);
-}
-
-void GLES2Context::UninitializeVertices()
-{
-   for (std::map<GLuint, VBO *>::iterator it = vert.vbos.begin(); it != vert.vbos.end(); it++) {
-      if (!it->second)
-         continue;
-      free(it->second->data);
-      free(it->second);
-   }
-}
-
-static inline void FetchElement(const GLES2Context * ctx, const unsigned index,
-                                const unsigned maxAttrib, VertexInput * elem)
-{
-   for (unsigned i = 0; i < maxAttrib; i++) {
-      {
-         unsigned size = 0;
-         if (ctx->vert.attribs[i].enabled) {
-            const char * ptr = (const char *)ctx->vert.attribs[i].ptr;
-            ptr += ctx->vert.attribs[i].stride * index;
-            memcpy(elem->attributes + i, ptr, ctx->vert.attribs[i].size * sizeof(float));
-            size = ctx->vert.attribs[i].size;
-//            LOGD("agl2: FetchElement %d attribs size=%d %.2f,%.2f,%.2f,%.2f", i, size, elem->attributes[i].x,
-//                 elem->attributes[i].y, elem->attributes[i].z, elem->attributes[i].w);
-         } else {
-//            LOGD("agl2: FetchElement %d default %.2f,%.2f,%.2f,%.2f", i, ctx->vert.defaultAttribs[i].x,
-//                 ctx->vert.defaultAttribs[i].y, ctx->vert.defaultAttribs[i].z, ctx->vert.defaultAttribs[i].w);
-         }
-
-         switch (size) {
-         case 0: // fall through
-            elem->attributes[i].x = ctx->vert.defaultAttribs[i].x;
-         case 1: // fall through
-            elem->attributes[i].y = ctx->vert.defaultAttribs[i].y;
-         case 2: // fall through
-            elem->attributes[i].z = ctx->vert.defaultAttribs[i].z;
-         case 3: // fall through
-            elem->attributes[i].w = ctx->vert.defaultAttribs[i].w;
-         case 4:
-            break;
-         default:
-            assert(0);
-            break;
-         }
-//         LOGD("agl2: FetchElement %d size=%d %.2f,%.2f,%.2f,%.2f", i, size, elem->attributes[i].x,
-//              elem->attributes[i].y, elem->attributes[i].z, elem->attributes[i].w);
-      }
-   }
-}
-
-template<typename IndexT> static void DrawElementsTriangles(const GLES2Context * ctx,
-      const unsigned count, const IndexT * indices, const unsigned maxAttrib)
-{
-   VertexInput v[3];
-   if (ctx->vert.indices)
-      indices = (IndexT *)((char *)ctx->vert.indices->data + (long)indices);
-   for (unsigned i = 0; i < count; i += 3) {
-      for (unsigned j = 0; j < 3; j++)
-         FetchElement(ctx, indices[i + j], maxAttrib, v + j);
-      ctx->iface->DrawTriangle(ctx->iface, v, v + 1, v + 2);
-   }
-}
-
-static void DrawArraysTriangles(const GLES2Context * ctx, const unsigned first,
-                                const unsigned count, const unsigned maxAttrib)
-{
-//   LOGD("agl: DrawArraysTriangles=%p", DrawArraysTriangles);
-   VertexInput v[3];
-   for (unsigned i = 2; i < count; i+=3) {
-      // TODO: fix order
-      FetchElement(ctx, first + i - 2, maxAttrib, v + 0);
-      FetchElement(ctx, first + i - 1, maxAttrib, v + 1);
-      FetchElement(ctx, first + i - 0, maxAttrib, v + 2);
-      ctx->iface->DrawTriangle(ctx->iface, v + 0, v + 1, v + 2);
-   }
-//   LOGD("agl: DrawArraysTriangles end");
-}
-
-template<typename IndexT> static void DrawElementsTriangleStrip(const GLES2Context * ctx,
-      const unsigned count, const IndexT * indices, const unsigned maxAttrib)
-{
-   VertexInput v[3];
-   if (ctx->vert.indices)
-      indices = (IndexT *)((char *)ctx->vert.indices->data + (long)indices);
-      
-//   LOGD("agl2: DrawElementsTriangleStrip");
-//   for (unsigned i = 0; i < count; i++)
-//      LOGD("indices[%d] = %d", i, indices[i]);
-
-   FetchElement(ctx, indices[0], maxAttrib, v + 0);
-   FetchElement(ctx, indices[1], maxAttrib, v + 1);
-   for (unsigned i = 2; i < count; i ++) {
-      FetchElement(ctx, indices[i], maxAttrib, v + i % 3);
-      ctx->iface->DrawTriangle(ctx->iface, v + (i - 2) % 3, v + (i - 1) % 3 , v + (i + 0) % 3);
-   }
-
-//   for (unsigned i = 2; i < count; i++) {
-//      FetchElement(ctx, indices[i - 2], maxAttrib, v + 0);
-//      FetchElement(ctx, indices[i - 1], maxAttrib, v + 1);
-//      FetchElement(ctx, indices[i - 0], maxAttrib, v + 2);
-//      ctx->iface->DrawTriangle(ctx->iface, v + 0, v + 1, v + 2);
-//   }
-}
-
-static void DrawArraysTriangleStrip(const GLES2Context * ctx, const unsigned first,
-                                    const unsigned count, const unsigned maxAttrib)
-{
-   VertexInput v[3];
-   FetchElement(ctx, first, maxAttrib, v + 0);
-   FetchElement(ctx, first + 1, maxAttrib, v + 1);
-   for (unsigned i = 2; i < count; i++) {
-      // TODO: fix order
-      FetchElement(ctx, first + i, maxAttrib, v + i % 3);
-      ctx->iface->DrawTriangle(ctx->iface, v + (i - 2) % 3, v + (i - 1) % 3 , v + (i + 0) % 3);
-   }
-}
-
-void glBindBuffer(GLenum target, GLuint buffer)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   VBO * vbo = NULL;
-   if (0 != buffer) {
-      std::map<GLuint, VBO *>::iterator it = ctx->vert.vbos.find(buffer);
-      if (it != ctx->vert.vbos.end()) {
-         vbo = it->second;
-         if (!vbo)
-            vbo = (VBO *)calloc(1, sizeof(VBO));
-         it->second = vbo;
-      } else
-         assert(0);
-   }
-   if (GL_ARRAY_BUFFER == target)
-      ctx->vert.vbo = vbo;
-   else if (GL_ELEMENT_ARRAY_BUFFER == target)
-      ctx->vert.indices = vbo;
-   else
-      assert(0);
-   assert(vbo || buffer == 0);
-//   LOGD("\n*\n glBindBuffer 0x%.4X=%d ", target, buffer);
-}
-
-void glBufferData(GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   if (GL_ARRAY_BUFFER == target) {
-      assert(ctx->vert.vbo);
-      ctx->vert.vbo->data = realloc(ctx->vert.vbo->data, size);
-      ctx->vert.vbo->size = size;
-      ctx->vert.vbo->usage = usage;
-      if (data)
-         memcpy(ctx->vert.vbo->data, data, size);
-   } else if (GL_ELEMENT_ARRAY_BUFFER == target) {
-      assert(ctx->vert.indices);
-      ctx->vert.indices->data = realloc(ctx->vert.indices->data, size);
-      ctx->vert.indices->size = size;
-      ctx->vert.indices->usage = usage;
-      if (data)
-         memcpy(ctx->vert.indices->data, data, size);
-   } else
-      assert(0);
-//   LOGD("\n*\n glBufferData target=0x%.4X size=%u data=%p usage=0x%.4X \n",
-//        target, size, data, usage);
-}
-
-void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   if (GL_ARRAY_BUFFER == target)
-   {
-      assert(ctx->vert.vbo);
-      assert(0 <= offset);
-      assert(0 <= size);
-      assert(offset + size <= ctx->vert.vbo->size);
-      memcpy((char *)ctx->vert.vbo->data + offset, data, size);
-   }
-   else
-      assert(0);
-}
-
-void glDeleteBuffers(GLsizei n, const GLuint* buffers)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   for (unsigned i = 0; i < n; i++) {
-      std::map<GLuint, VBO*>::iterator it = ctx->vert.vbos.find(buffers[i]);
-      if (it == ctx->vert.vbos.end())
-         continue;
-      ctx->vert.free = min(ctx->vert.free, buffers[i]);
-      if (it->second == ctx->vert.vbo)
-         ctx->vert.vbo = NULL;
-      else if (it->second == ctx->vert.indices)
-         ctx->vert.indices = NULL;
-      if (it->second) {
-         free(it->second->data);
-         free(it->second);
-      }
-   }
-}
-
-void glDisableVertexAttribArray(GLuint index)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   assert(GGL_MAXVERTEXATTRIBS > index);
-   ctx->vert.attribs[index].enabled = false;
-}
-
-void glDrawArrays(GLenum mode, GLint first, GLsizei count)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-//   LOGD("agl2: glDrawArrays=%p", glDrawArrays);
-   assert(ctx->rasterizer.CurrentProgram);
-   assert(0 <= first);
-   int maxAttrib = -1;
-   ctx->iface->ShaderProgramGetiv(ctx->rasterizer.CurrentProgram, GL_ACTIVE_ATTRIBUTES, &maxAttrib);
-   assert(0 <= maxAttrib && GGL_MAXVERTEXATTRIBS >= maxAttrib);
-   switch (mode) {
-   case GL_TRIANGLE_STRIP:
-      DrawArraysTriangleStrip(ctx, first, count, maxAttrib);
-      break;
-   case GL_TRIANGLES:
-      DrawArraysTriangles(ctx, first, count, maxAttrib);
-      break;
-   default:
-      LOGE("agl2: glDrawArrays unsupported mode: 0x%.4X \n", mode);
-      assert(0);
-      break;
-   }
-//   LOGD("agl2: glDrawArrays end");
-}
-
-void glDrawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid* indices)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-//   LOGD("agl2: glDrawElements=%p mode=0x%.4X count=%d type=0x%.4X indices=%p",
-//        glDrawElements, mode, count, type, indices);
-   if (!ctx->rasterizer.CurrentProgram)
-      return;
-
-   int maxAttrib = -1;
-   ctx->iface->ShaderProgramGetiv(ctx->rasterizer.CurrentProgram, GL_ACTIVE_ATTRIBUTES, &maxAttrib);
-   assert(0 <= maxAttrib && GGL_MAXVERTEXATTRIBS >= maxAttrib);
-//   LOGD("agl2: glDrawElements mode=0x%.4X type=0x%.4X count=%d program=%p indices=%p \n",
-//        mode, type, count, ctx->rasterizer.CurrentProgram, indices);
-   switch (mode) {
-   case GL_TRIANGLES:
-      if (GL_UNSIGNED_SHORT == type)
-         DrawElementsTriangles<unsigned short>(ctx, count, (unsigned short *)indices, maxAttrib);
-      else
-         assert(0);
-      break;
-   case GL_TRIANGLE_STRIP:
-      if (GL_UNSIGNED_SHORT == type)
-         DrawElementsTriangleStrip<unsigned short>(ctx, count, (unsigned short *)indices, maxAttrib);
-      else
-         assert(0);
-      break;
-   default:
-      assert(0);
-   }
-//   LOGD("agl2: glDrawElements end");
-}
-
-void glEnableVertexAttribArray(GLuint index)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   ctx->vert.attribs[index].enabled = true;
-//   LOGD("agl2: glEnableVertexAttribArray %d \n", index);
-}
-
-void glGenBuffers(GLsizei n, GLuint* buffers)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   for (unsigned i = 0; i < n; i++) {
-      buffers[i] = 0;
-      for (ctx->vert.free; ctx->vert.free < 0xffffffffu; ctx->vert.free++) {
-         if (ctx->vert.vbos.find(ctx->vert.free) == ctx->vert.vbos.end()) {
-            ctx->vert.vbos[ctx->vert.free] = NULL;
-            buffers[i] = ctx->vert.free;
-//            LOGD("glGenBuffers %d \n", buffers[i]);
-            ctx->vert.free++;
-            break;
-         }
-      }
-      assert(buffers[i]);
-   }
-}
-
-void glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized,
-                           GLsizei stride, const GLvoid* ptr)
-{
-   GLES2_GET_CONST_CONTEXT(ctx);
-   assert(GL_FLOAT == type);
-   assert(0 < size && 4 >= size);
-   ctx->vert.attribs[index].size = size;
-   ctx->vert.attribs[index].type = type;
-   ctx->vert.attribs[index].normalized = normalized;
-   if (0 == stride)
-      ctx->vert.attribs[index].stride = size * sizeof(float);
-   else if (stride > 0)
-      ctx->vert.attribs[index].stride = stride;
-   else
-      assert(0);
-//   LOGD("\n*\n*\n* agl2: glVertexAttribPointer program=%u index=%d size=%d stride=%d ptr=%p \n*\n*",
-//        unsigned(ctx->rasterizer.CurrentProgram) ^ 0x04dc18f9, index, size, stride, ptr);
-   if (ctx->vert.vbo)
-      ctx->vert.attribs[index].ptr = (char *)ctx->vert.vbo->data + (long)ptr;
-   else
-      ctx->vert.attribs[index].ptr = ptr;
-//   const float * attrib = (const float *)ctx->vert.attribs[index].ptr;
-//   for (unsigned i = 0; i < 3; i++)
-//      if (3 == size)
-//         LOGD("%.2f %.2f %.2f", attrib[i * 3 + 0], attrib[i * 3 + 1], attrib[i * 3 + 2]);
-//      else if (2 == size)
-//         LOGD("%.2f %.2f", attrib[i * 3 + 0], attrib[i * 3 + 1]);
-   
-}
-
-void glVertexAttrib1f(GLuint indx, GLfloat x)
-{
-   glVertexAttrib4f(indx, x,0,0,1);
-}
-
-void glVertexAttrib1fv(GLuint indx, const GLfloat* values)
-{
-   glVertexAttrib4f(indx, values[0],0,0,1);
-}
-
-void glVertexAttrib2f(GLuint indx, GLfloat x, GLfloat y)
-{
-   glVertexAttrib4f(indx, x,y,0,1);
-}
-
-void glVertexAttrib2fv(GLuint indx, const GLfloat* values)
-{
-   glVertexAttrib4f(indx, values[0],values[1],0,1);
-}
-
-void glVertexAttrib3f(GLuint indx, GLfloat x, GLfloat y, GLfloat z)
-{
-   glVertexAttrib4f(indx, x,y,z,1);
-}
-
-void glVertexAttrib3fv(GLuint indx, const GLfloat* values)
-{
-   glVertexAttrib4f(indx, values[0],values[1],values[2],1);
-}
-
-void glVertexAttrib4f(GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
-{
-   assert(GGL_MAXVERTEXATTRIBS > indx);
-   GLES2_GET_CONST_CONTEXT(ctx);
-//   LOGD("\n*\n*\n agl2: glVertexAttrib4f %d %.2f,%.2f,%.2f,%.2f \n*\n*", indx, x, y, z, w);
-   ctx->vert.defaultAttribs[indx] = Vector4(x,y,z,w);
-   assert(0);
-}
-
-void glVertexAttrib4fv(GLuint indx, const GLfloat* values)
-{
-   glVertexAttrib4f(indx, values[0], values[1], values[2], values[3]);
-}
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 3e66a13..9c1a10e 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -8,6 +8,7 @@
 
 LOCAL_SRC_FILES:= 	       \
 	EGL/egl_tls.cpp        \
+	EGL/egl_cache.cpp      \
 	EGL/egl_display.cpp    \
 	EGL/egl_object.cpp     \
 	EGL/egl.cpp 	       \
@@ -43,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),)
 
@@ -157,4 +165,3 @@
 include $(BUILD_SHARED_LIBRARY)
 
 include $(call all-makefiles-under,$(LOCAL_PATH))
-
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 1e43195..6ad06af 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -212,16 +212,20 @@
 
 EGLImageKHR egl_get_image_for_current_context(EGLImageKHR image)
 {
-    ImageRef _i(image);
-    if (!_i.get())
-        return EGL_NO_IMAGE_KHR;
-
     EGLContext context = egl_tls_t::getContext();
     if (context == EGL_NO_CONTEXT || image == EGL_NO_IMAGE_KHR)
         return EGL_NO_IMAGE_KHR;
 
     egl_context_t const * const c = get_context(context);
-    if (c == NULL) // this should never happen
+    if (c == NULL) // this should never happen, by construction
+        return EGL_NO_IMAGE_KHR;
+
+    egl_display_t* display = egl_display_t::get(c->dpy);
+    if (display == NULL) // this should never happen, by construction
+        return EGL_NO_IMAGE_KHR;
+
+    ImageRef _i(display, image);
+    if (!_i.get())
         return EGL_NO_IMAGE_KHR;
 
     // here we don't validate the context because if it's been marked for
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 1f9ce68..2b0ed5d 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -49,21 +49,7 @@
 
 // ----------------------------------------------------------------------------
 
-static char const * const sVendorString     = "Android";
-static char const * const sVersionString    = "1.4 Android META-EGL";
-static char const * const sClientApiString  = "OpenGL ES";
-static char const * const sExtensionString  =
-        "EGL_KHR_image "
-        "EGL_KHR_image_base "
-        "EGL_KHR_image_pixmap "
-        "EGL_KHR_gl_texture_2D_image "
-        "EGL_KHR_gl_texture_cubemap_image "
-        "EGL_KHR_gl_renderbuffer_image "
-        "EGL_KHR_fence_sync "
-        "EGL_ANDROID_image_native_buffer "
-        "EGL_ANDROID_swap_rectangle "
-        "EGL_NV_system_time "
-        ;
+#define EGL_VERSION_HW_ANDROID  0x3143
 
 struct extention_map_t {
     const char* name;
@@ -79,8 +65,6 @@
             (__eglMustCastToProperFunctionPointerType)&eglCreateImageKHR },
     { "eglDestroyImageKHR",
             (__eglMustCastToProperFunctionPointerType)&eglDestroyImageKHR },
-    { "eglSetSwapRectangleANDROID",
-            (__eglMustCastToProperFunctionPointerType)&eglSetSwapRectangleANDROID },
     { "eglGetSystemTimeFrequencyNV",
             (__eglMustCastToProperFunctionPointerType)&eglGetSystemTimeFrequencyNV },
     { "eglGetSystemTimeNV",
@@ -388,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) {
@@ -451,7 +440,7 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    SurfaceRef _s(surface);
+    SurfaceRef _s(dp, surface);
     if (!_s.get())
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
@@ -472,7 +461,7 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    SurfaceRef _s(surface);
+    SurfaceRef _s(dp, surface);
     if (!_s.get())
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
@@ -541,7 +530,7 @@
     if (!dp)
         return EGL_FALSE;
 
-    ContextRef _c(ctx);
+    ContextRef _c(dp, ctx);
     if (!_c.get())
         return setError(EGL_BAD_CONTEXT, EGL_FALSE);
     
@@ -592,9 +581,9 @@
     }
 
     // get a reference to the object passed in
-    ContextRef _c(ctx);
-    SurfaceRef _d(draw);
-    SurfaceRef _r(read);
+    ContextRef _c(dp, ctx);
+    SurfaceRef _d(dp, draw);
+    SurfaceRef _r(dp, read);
 
     // validate the context (if not EGL_NO_CONTEXT)
     if ((ctx != EGL_NO_CONTEXT) && !_c.get()) {
@@ -696,7 +685,7 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    ContextRef _c(ctx);
+    ContextRef _c(dp, ctx);
     if (!_c.get()) return setError(EGL_BAD_CONTEXT, EGL_FALSE);
 
     egl_context_t * const c = get_context(ctx);
@@ -858,10 +847,17 @@
         return  NULL;
     }
 
+    // The EGL_ANDROID_blob_cache extension should not be exposed to
+    // applications.  It is used internally by the Android EGL layer.
+    if (!strcmp(procname, "eglSetBlobCacheFuncsANDROID")) {
+        return NULL;
+    }
+
     __eglMustCastToProperFunctionPointerType addr;
     addr = findProcAddress(procname, sExtentionMap, NELEM(sExtentionMap));
     if (addr) return addr;
 
+
     // this protects accesses to sGLExtentionMap and sGLExtentionSlot
     pthread_mutex_lock(&sExtensionMapMutex);
 
@@ -937,7 +933,7 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    SurfaceRef _s(draw);
+    SurfaceRef _s(dp, draw);
     if (!_s.get())
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
@@ -953,7 +949,7 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    SurfaceRef _s(surface);
+    SurfaceRef _s(dp, surface);
     if (!_s.get())
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
@@ -971,13 +967,19 @@
 
     switch (name) {
         case EGL_VENDOR:
-            return sVendorString;
+            return dp->getVendorString();
         case EGL_VERSION:
-            return sVersionString;
+            return dp->getVersionString();
         case EGL_EXTENSIONS:
-            return sExtensionString;
+            return dp->getExtensionString();
         case EGL_CLIENT_APIS:
-            return sClientApiString;
+            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);
 }
@@ -995,7 +997,7 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    SurfaceRef _s(surface);
+    SurfaceRef _s(dp, surface);
     if (!_s.get())
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
@@ -1015,7 +1017,7 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    SurfaceRef _s(surface);
+    SurfaceRef _s(dp, surface);
     if (!_s.get())
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
@@ -1035,7 +1037,7 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    SurfaceRef _s(surface);
+    SurfaceRef _s(dp, surface);
     if (!_s.get())
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
@@ -1194,7 +1196,7 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    SurfaceRef _s(surface);
+    SurfaceRef _s(dp, surface);
     if (!_s.get())
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
@@ -1213,7 +1215,7 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    SurfaceRef _s(surface);
+    SurfaceRef _s(dp, surface);
     if (!_s.get())
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
@@ -1234,7 +1236,7 @@
     if (!dp) return EGL_NO_IMAGE_KHR;
 
     if (ctx != EGL_NO_CONTEXT) {
-        ContextRef _c(ctx);
+        ContextRef _c(dp, ctx);
         if (!_c.get())
             return setError(EGL_BAD_CONTEXT, EGL_NO_IMAGE_KHR);
         egl_context_t * const c = get_context(ctx);
@@ -1303,7 +1305,7 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    ImageRef _i(img);
+    ImageRef _i(dp, img);
     if (!_i.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
 
     egl_image_t* image = get_image(img);
@@ -1342,7 +1344,7 @@
     if (!dp) return EGL_NO_SYNC_KHR;
 
     EGLContext ctx = eglGetCurrentContext();
-    ContextRef _c(ctx);
+    ContextRef _c(dp, ctx);
     if (!_c.get())
         return setError(EGL_BAD_CONTEXT, EGL_NO_SYNC_KHR);
 
@@ -1365,12 +1367,12 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    SyncRef _s(sync);
+    SyncRef _s(dp, sync);
     if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
     egl_sync_t* syncObject = get_sync(sync);
 
     EGLContext ctx = syncObject->context;
-    ContextRef _c(ctx);
+    ContextRef _c(dp, ctx);
     if (!_c.get())
         return setError(EGL_BAD_CONTEXT, EGL_FALSE);
 
@@ -1392,12 +1394,12 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    SyncRef _s(sync);
+    SyncRef _s(dp, sync);
     if (!_s.get()) return setError(EGL_BAD_PARAMETER, EGL_FALSE);
     egl_sync_t* syncObject = get_sync(sync);
 
     EGLContext ctx = syncObject->context;
-    ContextRef _c(ctx);
+    ContextRef _c(dp, ctx);
     if (!_c.get())
         return setError(EGL_BAD_CONTEXT, EGL_FALSE);
 
@@ -1417,13 +1419,13 @@
     egl_display_t const * const dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    SyncRef _s(sync);
+    SyncRef _s(dp, sync);
     if (!_s.get())
         return setError(EGL_BAD_PARAMETER, EGL_FALSE);
 
     egl_sync_t* syncObject = get_sync(sync);
     EGLContext ctx = syncObject->context;
-    ContextRef _c(ctx);
+    ContextRef _c(dp, ctx);
     if (!_c.get())
         return setError(EGL_BAD_CONTEXT, EGL_FALSE);
 
@@ -1440,25 +1442,7 @@
 // ANDROID extensions
 // ----------------------------------------------------------------------------
 
-EGLBoolean eglSetSwapRectangleANDROID(EGLDisplay dpy, EGLSurface draw,
-        EGLint left, EGLint top, EGLint width, EGLint height)
-{
-    clearError();
-
-    egl_display_t const * const dp = validate_display(dpy);
-    if (!dp) return EGL_FALSE;
-
-    SurfaceRef _s(draw);
-    if (!_s.get())
-        return setError(EGL_BAD_SURFACE, EGL_FALSE);
-
-    egl_surface_t const * const s = get_surface(draw);
-    if (s->cnx->egl.eglSetSwapRectangleANDROID) {
-        return s->cnx->egl.eglSetSwapRectangleANDROID(
-                dp->disp[s->impl].dpy, s->surface, left, top, width, height);
-    }
-    return setError(EGL_BAD_DISPLAY, NULL);
-}
+/* ANDROID extensions entry-point go here */
 
 // ----------------------------------------------------------------------------
 // NVIDIA extensions
diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp
new file mode 100644
index 0000000..c4a7466
--- /dev/null
+++ b/opengl/libs/EGL/egl_cache.cpp
@@ -0,0 +1,352 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#include "egl_cache.h"
+#include "egl_display.h"
+#include "egl_impl.h"
+#include "egldefs.h"
+
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#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 = MAX_EGL_CACHE_ENTRY_SIZE;
+static const size_t maxTotalSize = MAX_EGL_CACHE_SIZE;
+
+// Cache file header
+static const char* cacheFileMagic = "EGL$";
+static const size_t cacheFileHeaderSize = 8;
+
+// The time in seconds to wait before saving newly inserted cache entries.
+static const unsigned int deferredSaveDelay = 4;
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+#define BC_EXT_STR "EGL_ANDROID_blob_cache"
+
+//
+// Callback functions passed to EGL.
+//
+static void setBlob(const void* key, EGLsizeiANDROID keySize,
+        const void* value, EGLsizeiANDROID valueSize) {
+    egl_cache_t::get()->setBlob(key, keySize, value, valueSize);
+}
+
+static EGLsizeiANDROID getBlob(const void* key, EGLsizeiANDROID keySize,
+        void* value, EGLsizeiANDROID valueSize) {
+    return egl_cache_t::get()->getBlob(key, keySize, value, valueSize);
+}
+
+//
+// egl_cache_t definition
+//
+egl_cache_t::egl_cache_t() :
+        mInitialized(false),
+        mBlobCache(NULL) {
+}
+
+egl_cache_t::~egl_cache_t() {
+}
+
+egl_cache_t egl_cache_t::sCache;
+
+egl_cache_t* egl_cache_t::get() {
+    return &sCache;
+}
+
+void egl_cache_t::initialize(egl_display_t *display) {
+    Mutex::Autolock lock(mMutex);
+    for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
+        egl_connection_t* const cnx = &gEGLImpl[i];
+        if (cnx->dso && cnx->major >= 0 && cnx->minor >= 0) {
+            const char* exts = display->disp[i].queryString.extensions;
+            size_t bcExtLen = strlen(BC_EXT_STR);
+            size_t extsLen = strlen(exts);
+            bool equal = !strcmp(BC_EXT_STR, exts);
+            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(exts, " " BC_EXT_STR " ");
+            if (equal || atStart || atEnd || inMiddle) {
+                PFNEGLSETBLOBCACHEFUNCSANDROIDPROC eglSetBlobCacheFuncsANDROID;
+                eglSetBlobCacheFuncsANDROID =
+                        reinterpret_cast<PFNEGLSETBLOBCACHEFUNCSANDROIDPROC>(
+                            cnx->egl.eglGetProcAddress(
+                                    "eglSetBlobCacheFuncsANDROID"));
+                if (eglSetBlobCacheFuncsANDROID == NULL) {
+                    LOGE("EGL_ANDROID_blob_cache advertised by display %d, "
+                            "but unable to get eglSetBlobCacheFuncsANDROID", i);
+                    continue;
+                }
+
+                eglSetBlobCacheFuncsANDROID(display->disp[i].dpy,
+                        android::setBlob, android::getBlob);
+                EGLint err = cnx->egl.eglGetError();
+                if (err != EGL_SUCCESS) {
+                    LOGE("eglSetBlobCacheFuncsANDROID resulted in an error: "
+                            "%#x", err);
+                }
+            }
+        }
+    }
+    mInitialized = true;
+}
+
+void egl_cache_t::terminate() {
+    Mutex::Autolock lock(mMutex);
+    if (mBlobCache != NULL) {
+        saveBlobCacheLocked();
+        mBlobCache = NULL;
+    }
+    mInitialized = false;
+}
+
+void egl_cache_t::setBlob(const void* key, EGLsizeiANDROID keySize,
+        const void* value, EGLsizeiANDROID valueSize) {
+    Mutex::Autolock lock(mMutex);
+
+    if (keySize < 0 || valueSize < 0) {
+        LOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed");
+        return;
+    }
+
+    if (mInitialized) {
+        sp<BlobCache> bc = getBlobCacheLocked();
+        bc->set(key, keySize, value, valueSize);
+
+        if (!mSavePending) {
+            class DeferredSaveThread : public Thread {
+            public:
+                DeferredSaveThread() : Thread(false) {}
+
+                virtual bool threadLoop() {
+                    sleep(deferredSaveDelay);
+                    egl_cache_t* c = egl_cache_t::get();
+                    Mutex::Autolock lock(c->mMutex);
+                    if (c->mInitialized) {
+                        c->saveBlobCacheLocked();
+                    }
+                    c->mSavePending = false;
+                    return false;
+                }
+            };
+
+            // The thread will hold a strong ref to itself until it has finished
+            // running, so there's no need to keep a ref around.
+            sp<Thread> deferredSaveThread(new DeferredSaveThread());
+            mSavePending = true;
+            deferredSaveThread->run();
+        }
+    }
+}
+
+EGLsizeiANDROID egl_cache_t::getBlob(const void* key, EGLsizeiANDROID keySize,
+        void* value, EGLsizeiANDROID valueSize) {
+    Mutex::Autolock lock(mMutex);
+
+    if (keySize < 0 || valueSize < 0) {
+        LOGW("EGL_ANDROID_blob_cache set: negative sizes are not allowed");
+        return 0;
+    }
+
+    if (mInitialized) {
+        sp<BlobCache> bc = getBlobCacheLocked();
+        return bc->get(key, keySize, value, valueSize);
+    }
+    return 0;
+}
+
+void egl_cache_t::setCacheFilename(const char* filename) {
+    Mutex::Autolock lock(mMutex);
+    mFilename = filename;
+}
+
+sp<BlobCache> egl_cache_t::getBlobCacheLocked() {
+    if (mBlobCache == NULL) {
+        mBlobCache = new BlobCache(maxKeySize, maxValueSize, maxTotalSize);
+        loadBlobCacheLocked();
+    }
+    return mBlobCache;
+}
+
+static uint32_t crc32c(const uint8_t* buf, size_t len) {
+    const uint32_t polyBits = 0x82F63B78;
+    uint32_t r = 0;
+    for (size_t i = 0; i < len; i++) {
+        r ^= buf[i];
+        for (int j = 0; j < 8; j++) {
+            if (r & 1) {
+                r = (r >> 1) ^ polyBits;
+            } else {
+                r >>= 1;
+            }
+        }
+    }
+    return r;
+}
+
+void egl_cache_t::saveBlobCacheLocked() {
+    if (mFilename.length() > 0) {
+        size_t cacheSize = mBlobCache->getFlattenedSize();
+        size_t headerSize = cacheFileHeaderSize;
+        const char* fname = mFilename.string();
+
+        // Try to create the file with no permissions so we can write it
+        // without anyone trying to read it.
+        int fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0);
+        if (fd == -1) {
+            if (errno == EEXIST) {
+                // The file exists, delete it and try again.
+                if (unlink(fname) == -1) {
+                    // No point in retrying if the unlink failed.
+                    LOGE("error unlinking cache file %s: %s (%d)", fname,
+                            strerror(errno), errno);
+                    return;
+                }
+                // Retry now that we've unlinked the file.
+                fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0);
+            }
+            if (fd == -1) {
+                LOGE("error creating cache file %s: %s (%d)", fname,
+                        strerror(errno), errno);
+                return;
+            }
+        }
+
+        size_t fileSize = headerSize + cacheSize;
+        if (ftruncate(fd, fileSize) == -1) {
+            LOGE("error setting cache file size: %s (%d)", strerror(errno),
+                    errno);
+            close(fd);
+            unlink(fname);
+            return;
+        }
+
+        uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(NULL, fileSize,
+                PROT_WRITE, MAP_SHARED, fd, 0));
+        if (buf == MAP_FAILED) {
+            LOGE("error mmaping cache file: %s (%d)", strerror(errno),
+                    errno);
+            close(fd);
+            unlink(fname);
+            return;
+        }
+
+        status_t err = mBlobCache->flatten(buf + headerSize, cacheSize, NULL,
+                0);
+        if (err != OK) {
+            LOGE("error writing cache contents: %s (%d)", strerror(-err),
+                    -err);
+            munmap(buf, fileSize);
+            close(fd);
+            unlink(fname);
+            return;
+        }
+
+        // Write the file magic and CRC
+        memcpy(buf, cacheFileMagic, 4);
+        uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4);
+        *crc = crc32c(buf + headerSize, cacheSize);
+
+        munmap(buf, fileSize);
+        fchmod(fd, S_IRUSR);
+        close(fd);
+    }
+}
+
+void egl_cache_t::loadBlobCacheLocked() {
+    if (mFilename.length() > 0) {
+        size_t headerSize = cacheFileHeaderSize;
+
+        int fd = open(mFilename.string(), O_RDONLY, 0);
+        if (fd == -1) {
+            if (errno != ENOENT) {
+                LOGE("error opening cache file %s: %s (%d)", mFilename.string(),
+                        strerror(errno), errno);
+            }
+            return;
+        }
+
+        struct stat statBuf;
+        if (fstat(fd, &statBuf) == -1) {
+            LOGE("error stat'ing cache file: %s (%d)", strerror(errno), errno);
+            close(fd);
+            return;
+        }
+
+        // Sanity check the size before trying to mmap it.
+        size_t fileSize = statBuf.st_size;
+        if (fileSize > maxTotalSize * 2) {
+            LOGE("cache file is too large: %#llx", statBuf.st_size);
+            close(fd);
+            return;
+        }
+
+        uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(NULL, fileSize,
+                PROT_READ, MAP_PRIVATE, fd, 0));
+        if (buf == MAP_FAILED) {
+            LOGE("error mmaping cache file: %s (%d)", strerror(errno),
+                    errno);
+            close(fd);
+            return;
+        }
+
+        // Check the file magic and CRC
+        size_t cacheSize = fileSize - headerSize;
+        if (memcmp(buf, cacheFileMagic, 4) != 0) {
+            LOGE("cache file has bad mojo");
+            close(fd);
+            return;
+        }
+        uint32_t* crc = reinterpret_cast<uint32_t*>(buf + 4);
+        if (crc32c(buf + headerSize, cacheSize) != *crc) {
+            LOGE("cache file failed CRC check");
+            close(fd);
+            return;
+        }
+
+        status_t err = mBlobCache->unflatten(buf + headerSize, cacheSize, NULL,
+                0);
+        if (err != OK) {
+            LOGE("error reading cache contents: %s (%d)", strerror(-err),
+                    -err);
+            munmap(buf, fileSize);
+            close(fd);
+            return;
+        }
+
+        munmap(buf, fileSize);
+        close(fd);
+    }
+}
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_cache.h b/opengl/libs/EGL/egl_cache.h
new file mode 100644
index 0000000..8760009
--- /dev/null
+++ b/opengl/libs/EGL/egl_cache.h
@@ -0,0 +1,130 @@
+/*
+ ** Copyright 2011, The Android Open Source Project
+ **
+ ** Licensed under the Apache License, Version 2.0 (the "License");
+ ** you may not use this file except in compliance with the License.
+ ** You may obtain a copy of the License at
+ **
+ **     http://www.apache.org/licenses/LICENSE-2.0
+ **
+ ** Unless required by applicable law or agreed to in writing, software
+ ** distributed under the License is distributed on an "AS IS" BASIS,
+ ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ** See the License for the specific language governing permissions and
+ ** limitations under the License.
+ */
+
+#ifndef ANDROID_EGL_CACHE_H
+#define ANDROID_EGL_CACHE_H
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include <utils/BlobCache.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+
+// ----------------------------------------------------------------------------
+namespace android {
+// ----------------------------------------------------------------------------
+
+class egl_display_t;
+
+class EGLAPI egl_cache_t {
+public:
+
+    // get returns a pointer to the singleton egl_cache_t object.  This
+    // singleton object will never be destroyed.
+    static egl_cache_t* get();
+
+    // initialize puts the egl_cache_t into an initialized state, such that it
+    // is able to insert and retrieve entries from the cache.  This should be
+    // called when EGL is initialized.  When not in the initialized state the
+    // getBlob and setBlob methods will return without performing any cache
+    // operations.
+    void initialize(egl_display_t* display);
+
+    // terminate puts the egl_cache_t back into the uninitialized state.  When
+    // in this state the getBlob and setBlob methods will return without
+    // performing any cache operations.
+    void terminate();
+
+    // setBlob attempts to insert a new key/value blob pair into the cache.
+    // This will be called by the hardware vendor's EGL implementation via the
+    // EGL_ANDROID_blob_cache extension.
+    void setBlob(const void* key, EGLsizeiANDROID keySize, const void* value,
+        EGLsizeiANDROID valueSize);
+
+    // getBlob attempts to retrieve the value blob associated with a given key
+    // blob from cache.  This will be called by the hardware vendor's EGL
+    // implementation via the EGL_ANDROID_blob_cache extension.
+    EGLsizeiANDROID getBlob(const void* key, EGLsizeiANDROID keySize,
+        void* value, EGLsizeiANDROID valueSize);
+
+    // setCacheFilename sets the name of the file that should be used to store
+    // cache contents from one program invocation to another.
+    void setCacheFilename(const char* filename);
+
+private:
+    // Creation and (the lack of) destruction is handled internally.
+    egl_cache_t();
+    ~egl_cache_t();
+
+    // Copying is disallowed.
+    egl_cache_t(const egl_cache_t&); // not implemented
+    void operator=(const egl_cache_t&); // not implemented
+
+    // getBlobCacheLocked returns the BlobCache object being used to store the
+    // key/value blob pairs.  If the BlobCache object has not yet been created,
+    // this will do so, loading the serialized cache contents from disk if
+    // possible.
+    sp<BlobCache> getBlobCacheLocked();
+
+    // saveBlobCache attempts to save the current contents of mBlobCache to
+    // disk.
+    void saveBlobCacheLocked();
+
+    // loadBlobCache attempts to load the saved cache contents from disk into
+    // mBlobCache.
+    void loadBlobCacheLocked();
+
+    // mInitialized indicates whether the egl_cache_t is in the initialized
+    // state.  It is initialized to false at construction time, and gets set to
+    // true when initialize is called.  It is set back to false when terminate
+    // is called.  When in this state, the cache behaves as normal.  When not,
+    // the getBlob and setBlob methods will return without performing any cache
+    // operations.
+    bool mInitialized;
+
+    // mBlobCache is the cache in which the key/value blob pairs are stored.  It
+    // is initially NULL, and will be initialized by getBlobCacheLocked the
+    // first time it's needed.
+    sp<BlobCache> mBlobCache;
+
+    // mFilename is the name of the file for storing cache contents in between
+    // program invocations.  It is initialized to an empty string at
+    // construction time, and can be set with the setCacheFilename method.  An
+    // empty string indicates that the cache should not be saved to or restored
+    // from disk.
+    String8 mFilename;
+
+    // mSavePending indicates whether or not a deferred save operation is
+    // pending.  Each time a key/value pair is inserted into the cache via
+    // setBlob, a deferred save is initiated if one is not already pending.
+    // This will wait some amount of time and then trigger a save of the cache
+    // contents to disk.
+    bool mSavePending;
+
+    // mMutex is the mutex used to prevent concurrent access to the member
+    // variables. It must be locked whenever the member variables are accessed.
+    mutable Mutex mMutex;
+
+    // sCache is the singleton egl_cache_t object.
+    static egl_cache_t sCache;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+// ----------------------------------------------------------------------------
+
+#endif // ANDROID_EGL_CACHE_H
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 83aafa6..31119f9 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -14,6 +14,9 @@
  ** limitations under the License.
  */
 
+#include <string.h>
+
+#include "egl_cache.h"
 #include "egl_display.h"
 #include "egl_object.h"
 #include "egl_tls.h"
@@ -24,6 +27,36 @@
 namespace android {
 // ----------------------------------------------------------------------------
 
+static char const * const sVendorString     = "Android";
+static char const * const sVersionString    = "1.4 Android META-EGL";
+static char const * const sClientApiString  = "OpenGL ES";
+
+// this is the list of EGL extensions that are exposed to applications
+// some of them are mandatory because used by the ANDROID system.
+//
+// mandatory extensions are required per the CDD and not explicitly
+// checked during EGL initialization. the system *assumes* these extensions
+// are present. the system may not function properly if some mandatory
+// extensions are missing.
+//
+// NOTE: sExtensionString MUST be have a single space as the last character.
+//
+static char const * const sExtensionString  =
+        "EGL_KHR_image "                        // mandatory
+        "EGL_KHR_image_base "                   // mandatory
+        "EGL_KHR_image_pixmap "
+        "EGL_KHR_gl_texture_2D_image "
+        "EGL_KHR_gl_texture_cubemap_image "
+        "EGL_KHR_gl_renderbuffer_image "
+        "EGL_KHR_fence_sync "
+        "EGL_NV_system_time "
+        "EGL_ANDROID_image_native_buffer "      // mandatory
+        ;
+
+// extensions not exposed to applications but used by the ANDROID system
+//      "EGL_ANDROID_recordable "               // mandatory
+//      "EGL_ANDROID_blob_cache "               // strongly recommended
+
 extern void initEglTraceLevel();
 extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
 
@@ -43,6 +76,7 @@
 
 egl_display_t::~egl_display_t() {
     magic = 0;
+    egl_cache_t::get()->terminate();
 }
 
 egl_display_t* egl_display_t::get(EGLDisplay dpy) {
@@ -60,11 +94,13 @@
     objects.remove(object);
 }
 
-bool egl_display_t::getObject(egl_object_t* object) {
+bool egl_display_t::getObject(egl_object_t* object) const {
     Mutex::Autolock _l(lock);
     if (objects.indexOf(object) >= 0) {
-        object->incRef();
-        return true;
+        if (object->getDisplay() == this) {
+            object->incRef();
+            return true;
+        }
     }
     return false;
 }
@@ -170,6 +206,42 @@
         }
     }
 
+    // the query strings are per-display
+    mVendorString.setTo(sVendorString);
+    mVersionString.setTo(sVersionString);
+    mClientApiString.setTo(sClientApiString);
+
+    // we only add extensions that exist in at least one implementation
+    char const* start = sExtensionString;
+    char const* end;
+    do {
+        // find the space separating this extension for the next one
+        end = strchr(start, ' ');
+        if (end) {
+            // length of the extension string
+            const size_t len = end - start;
+            if (len) {
+                // NOTE: we could avoid the copy if we had strnstr.
+                const String8 ext(start, len);
+                // now go through all implementations and look for this extension
+                for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
+                    if (disp[i].queryString.extensions) {
+                        // if we find it, add this extension string to our list
+                        // (and don't forget the space)
+                        const char* match = strstr(disp[i].queryString.extensions, ext.string());
+                        if (match && (match[len] == ' ' || match[len] == 0)) {
+                            mExtensionString.append(start, len+1);
+                        }
+                    }
+                }
+            }
+            // process the next extension string, and skip the space.
+            start = end + 1;
+        }
+    } while (end);
+
+    egl_cache_t::get()->initialize(this);
+
     EGLBoolean res = EGL_FALSE;
     for (int i = 0; i < IMPL_NUM_IMPLEMENTATIONS; i++) {
         egl_connection_t* const cnx = &gEGLImpl[i];
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index 113595f..042ae07 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -29,6 +29,7 @@
 
 #include <utils/SortedVector.h>
 #include <utils/threads.h>
+#include <utils/String8.h>
 
 #include "egldefs.h"
 #include "hooks.h"
@@ -59,7 +60,7 @@
 
 // ----------------------------------------------------------------------------
 
-class egl_display_t {
+class EGLAPI egl_display_t { // marked as EGLAPI for testing purposes
     static egl_display_t sDisplay[NUM_DISPLAYS];
     EGLDisplay getDisplay(EGLNativeDisplayType display);
 
@@ -81,7 +82,7 @@
     // remove object from this display's list
     void removeObject(egl_object_t* object);
     // add reference to this object. returns true if this is a valid object.
-    bool getObject(egl_object_t* object);
+    bool getObject(egl_object_t* object) const;
 
 
     static egl_display_t* get(EGLDisplay dpy);
@@ -91,6 +92,13 @@
     inline bool isValid() const { return magic == '_dpy'; }
     inline bool isAlive() const { return isValid(); }
 
+    char const * getVendorString() const { return mVendorString.string(); }
+    char const * getVersionString() const { return mVersionString.string(); }
+    char const * getClientApiString() const { return mClientApiString.string(); }
+    char const * getExtensionString() const { return mExtensionString.string(); }
+
+    inline uint32_t getRefsCount() const { return refs; }
+
     struct strings_t {
         char const * vendor;
         char const * version;
@@ -117,9 +125,13 @@
     egl_config_t*   configs;
 
 private:
-    uint32_t        refs;
-    Mutex           lock;
-    SortedVector<egl_object_t*> objects;
+            uint32_t                    refs;
+    mutable Mutex                       lock;
+            SortedVector<egl_object_t*> objects;
+            String8 mVendorString;
+            String8 mVersionString;
+            String8 mClientApiString;
+            String8 mExtensionString;
 };
 
 // ----------------------------------------------------------------------------
@@ -141,4 +153,3 @@
 // ----------------------------------------------------------------------------
 
 #endif // ANDROID_EGL_DISPLAY_H
-
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index dbf9a01..20cdc7e 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -55,10 +55,10 @@
     }
 }
 
-bool egl_object_t::get() {
+bool egl_object_t::get(egl_display_t const* display, egl_object_t* object) {
     // used by LocalRef, this does an incRef() atomically with
     // checking that the object is valid.
-    return display->getObject(this);
+    return display->getObject(object);
 }
 
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index 46f7139..df1b261 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -52,10 +52,11 @@
 
     inline int32_t incRef() { return android_atomic_inc(&count); }
     inline int32_t decRef() { return android_atomic_dec(&count); }
+    inline egl_display_t* getDisplay() const { return display; }
 
 private:
     void terminate();
-    bool get();
+    static bool get(egl_display_t const* display, egl_object_t* object);
 
 public:
     template <typename N, typename T>
@@ -66,9 +67,9 @@
     public:
         ~LocalRef();
         explicit LocalRef(egl_object_t* rhs);
-        explicit LocalRef(T o) : ref(0) {
+        explicit LocalRef(egl_display_t const* display, T o) : ref(0) {
             egl_object_t* native = reinterpret_cast<N*>(o);
-            if (o && native->get()) {
+            if (o && egl_object_t::get(display, native)) {
                 ref = native;
             }
         }
diff --git a/opengl/specs/EGL_ANDROID_blob_cache.txt b/opengl/specs/EGL_ANDROID_blob_cache.txt
index 55dc900..61f45d3 100644
--- a/opengl/specs/EGL_ANDROID_blob_cache.txt
+++ b/opengl/specs/EGL_ANDROID_blob_cache.txt
@@ -63,33 +63,33 @@
 New Types
 
     /*
-     * EGLsizei is a signed integer type for representing the size of a memory
-     * buffer.
+     * EGLsizeiANDROID is a signed integer type for representing the size of a
+     * memory buffer.
      */
     #include <khrplatform.h>
-    typedef khronos_ssize_t EGLsizei;
+    typedef khronos_ssize_t EGLsizeiANDROID;
 
     /*
      * EGLSetBlobFunc is a pointer to an application-provided function that a
      * client API implementation may use to insert a key/value pair into the
      * cache.
      */
-    typedef void (*EGLSetBlobFunc) (const void* key, EGLsizei keySize,
-        const void* value, EGLsizei valueSize)
+    typedef void (*EGLSetBlobFuncANDROID) (const void* key,
+        EGLsizeiANDROID keySize, const void* value, EGLsizeiANDROID valueSize)
 
     /*
      * EGLGetBlobFunc is a pointer to an application-provided function that a
      * client API implementation may use to retrieve a cached value from the
      * cache.
      */
-    typedef EGLsizei (*EGLGetBlobFunc) (const void* key, EGLsizei keySize,
-        void* value, EGLsizei valueSize)
+    typedef EGLsizeiANDROID (*EGLGetBlobFuncANDROID) (const void* key,
+        EGLsizeiANDROID keySize, void* value, EGLsizeiANDROID valueSize)
 
 New Procedures and Functions
 
-    void eglSetBlobCacheFuncs(EGLDisplay dpy,
-                              EGLSetBlobFunc set,
-                              EGLGetBlobFunc get);
+    void eglSetBlobCacheFuncsANDROID(EGLDisplay dpy,
+                                     EGLSetBlobFunc set,
+                                     EGLGetBlobFunc get);
 
 New Tokens
 
@@ -107,8 +107,8 @@
     function pointers through which the client APIs can request data be cached
     and retrieved.  The command
 
-        void eglSetBlobCacheFuncs(EGLDisplay dpy,
-            EGLSetBlobFunc set, EGLGetBlobFunc get);
+        void eglSetBlobCacheFuncsANDROID(EGLDisplay dpy,
+            EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get);
 
     sets the callback function pointers that client APIs associated with
     display <dpy> can use to interact with caching functionality provided by
@@ -120,17 +120,17 @@
 
     Cache functions may only be specified once during the lifetime of an
     EGLDisplay.  The <set> and <get> functions may be called at any time and
-    from any thread from the time at which eglSetBlobCacheFuncs is called until
-    the time that the last resource associated with <dpy> is deleted and <dpy>
-    itself is terminated.  Concurrent calls to these functions from different
-    threads is also allowed.
+    from any thread from the time at which eglSetBlobCacheFuncsANDROID is
+    called until the time that the last resource associated with <dpy> is
+    deleted and <dpy> itself is terminated.  Concurrent calls to these
+    functions from different threads is also allowed.
 
-    If eglSetBlobCacheFuncs generates an error then all client APIs must behave
-    as though eglSetBlobCacheFuncs was not called for the display <dpy>.  If
-    <set> or <get> is NULL then an EGL_BAD_PARAMETER error is generated.  If a
-    successful eglSetBlobCacheFuncs call was already made for <dpy> and the
-    display has not since been terminated then an EGL_BAD_PARAMETER error is
-    generated.
+    If eglSetBlobCacheFuncsANDROID generates an error then all client APIs must
+    behave as though eglSetBlobCacheFuncsANDROID was not called for the display
+    <dpy>.  If <set> or <get> is NULL then an EGL_BAD_PARAMETER error is
+    generated.  If a successful eglSetBlobCacheFuncsANDROID call was already
+    made for <dpy> and the display has not since been terminated then an
+    EGL_BAD_PARAMETER error is generated.
 
     3.9.1 Cache Operations
 
@@ -138,8 +138,8 @@
     key, a client API implementation can call the application-provided callback
     function
 
-        void (*set) (const void* key, EGLsizei keySize, const void* value,
-            EGLsizei valueSize)
+        void (*set) (const void* key, EGLsizeiANDROID keySize,
+            const void* value, EGLsizeiANDROID valueSize)
 
     <key> and <value> are pointers to the beginning of the key and value,
     respectively, that are to be inserted.  <keySize> and <valueSize> specify
@@ -157,8 +157,8 @@
     client API implementation can call the application-provided callback
     function
 
-        EGLsizei (*get) (const void* key, EGLsizei keySize, void* value,
-            EGLsizei valueSize)
+        EGLsizeiANDROID (*get) (const void* key, EGLsizeiANDROID keySize,
+            void* value, EGLsizeiANDROID valueSize)
 
     <key> is a pointer to the beginning of the key.  <keySize> specifies the
     size in bytes of the binary key pointed to by <key>.  If the cache contains
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/tests/EGLTest/Android.mk b/opengl/tests/EGLTest/Android.mk
index 92d7eb1..14104d1 100644
--- a/opengl/tests/EGLTest/Android.mk
+++ b/opengl/tests/EGLTest/Android.mk
@@ -7,6 +7,7 @@
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_SRC_FILES := \
+    egl_cache_test.cpp \
     EGL_test.cpp \
 
 LOCAL_SHARED_LIBRARIES := \
@@ -21,9 +22,12 @@
 
 LOCAL_C_INCLUDES := \
     bionic \
+    bionic/libc/private \
     bionic/libstdc++/include \
     external/gtest/include \
     external/stlport/stlport \
+    frameworks/base/opengl/libs \
+    frameworks/base/opengl/libs/EGL \
 
 include $(BUILD_EXECUTABLE)
 
diff --git a/opengl/tests/EGLTest/egl_cache_test.cpp b/opengl/tests/EGLTest/egl_cache_test.cpp
new file mode 100644
index 0000000..c7d9e3e
--- /dev/null
+++ b/opengl/tests/EGLTest/egl_cache_test.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "EGL_test"
+//#define LOG_NDEBUG 0
+
+#include <gtest/gtest.h>
+
+#include <utils/Log.h>
+
+#include "egl_cache.h"
+#include "egl_display.h"
+
+namespace android {
+
+class EGLCacheTest : public ::testing::Test {
+protected:
+    virtual void SetUp() {
+        mCache = egl_cache_t::get();
+    }
+
+    virtual void TearDown() {
+        mCache->setCacheFilename("");
+        mCache->terminate();
+    }
+
+    egl_cache_t* mCache;
+};
+
+TEST_F(EGLCacheTest, UninitializedCacheAlwaysMisses) {
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mCache->setBlob("abcd", 4, "efgh", 4);
+    ASSERT_EQ(0, mCache->getBlob("abcd", 4, buf, 4));
+    ASSERT_EQ(0xee, buf[0]);
+    ASSERT_EQ(0xee, buf[1]);
+    ASSERT_EQ(0xee, buf[2]);
+    ASSERT_EQ(0xee, buf[3]);
+}
+
+TEST_F(EGLCacheTest, InitializedCacheAlwaysHits) {
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY));
+    mCache->setBlob("abcd", 4, "efgh", 4);
+    ASSERT_EQ(4, mCache->getBlob("abcd", 4, buf, 4));
+    ASSERT_EQ('e', buf[0]);
+    ASSERT_EQ('f', buf[1]);
+    ASSERT_EQ('g', buf[2]);
+    ASSERT_EQ('h', buf[3]);
+}
+
+TEST_F(EGLCacheTest, TerminatedCacheAlwaysMisses) {
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY));
+    mCache->setBlob("abcd", 4, "efgh", 4);
+    mCache->terminate();
+    ASSERT_EQ(0, mCache->getBlob("abcd", 4, buf, 4));
+    ASSERT_EQ(0xee, buf[0]);
+    ASSERT_EQ(0xee, buf[1]);
+    ASSERT_EQ(0xee, buf[2]);
+    ASSERT_EQ(0xee, buf[3]);
+}
+
+class EGLCacheSerializationTest : public EGLCacheTest {
+
+protected:
+
+    virtual void SetUp() {
+        EGLCacheTest::SetUp();
+
+        char* tn = tempnam("/sdcard", "EGL_test-cache-");
+        mFilename = tn;
+        free(tn);
+    }
+
+    virtual void TearDown() {
+        unlink(mFilename.string());
+        EGLCacheTest::TearDown();
+    }
+
+    String8 mFilename;
+};
+
+TEST_F(EGLCacheSerializationTest, ReinitializedCacheContainsValues) {
+    char buf[4] = { 0xee, 0xee, 0xee, 0xee };
+    mCache->setCacheFilename(mFilename);
+    mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY));
+    mCache->setBlob("abcd", 4, "efgh", 4);
+    mCache->terminate();
+    mCache->initialize(egl_display_t::get(EGL_DEFAULT_DISPLAY));
+    ASSERT_EQ(4, mCache->getBlob("abcd", 4, buf, 4));
+    ASSERT_EQ('e', buf[0]);
+    ASSERT_EQ('f', buf[1]);
+    ASSERT_EQ('g', buf[2]);
+    ASSERT_EQ('h', buf[3]);
+}
+
+}
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 53502dbc..f63c0c1 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -28,10 +28,7 @@
 endif
 ifeq ($(TARGET_BOARD_PLATFORM), s5pc110)
 	LOCAL_CFLAGS += -DHAS_CONTEXT_PRIORITY -DNEVER_DEFAULT_TO_ASYNC_MODE
-endif
-
-ifneq (,$(findstring $(TARGET_DEVICE),tuna toro maguro))
-	LOCAL_CFLAGS += -DREFRESH_RATE=59
+	LOCAL_CFLAGS += -DREFRESH_RATE=56
 endif
 
 
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index 329c052..f94d321 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -284,22 +284,6 @@
     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
     glGetIntegerv(GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
 
-
-#ifdef EGL_ANDROID_swap_rectangle
-    if (extensions.hasExtension("EGL_ANDROID_swap_rectangle")) {
-        if (eglSetSwapRectangleANDROID(display, surface,
-                0, 0, mWidth, mHeight) == EGL_TRUE) {
-            // This could fail if this extension is not supported by this
-            // specific surface (of config)
-            mFlags |= SWAP_RECTANGLE;
-        }
-    }
-    // when we have the choice between PARTIAL_UPDATES and SWAP_RECTANGLE
-    // choose PARTIAL_UPDATES, which should be more efficient
-    if (mFlags & PARTIAL_UPDATES)
-        mFlags &= ~SWAP_RECTANGLE;
-#endif
-
     LOGI("EGL informations:");
     LOGI("# of configs : %d", numConfigs);
     LOGI("vendor    : %s", extensions.getEglVendor());
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 50b8604..d3b0dbf 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -360,18 +360,6 @@
                 mCurrentScalingMode);
 
         if (!isFixedSize()) {
-            // we're being resized and there is a freeze display request,
-            // acquire a freeze lock, so that the screen stays put
-            // until we've redrawn at the new size; this is to avoid
-            // glitches upon orientation changes.
-            if (mFlinger->hasFreezeRequest()) {
-                // if the surface is hidden, don't try to acquire the
-                // freeze lock, since hidden surfaces may never redraw
-                if (!(front.flags & ISurfaceComposer::eLayerHidden)) {
-                    mFreezeLock = mFlinger->getFreezeLock();
-                }
-            }
-
             // this will make sure LayerBase::doTransaction doesn't update
             // the drawing state's size
             Layer::State& editDraw(mDrawingState);
@@ -385,14 +373,6 @@
                 temp.requested_h);
     }
 
-    if (temp.sequence != front.sequence) {
-        if (temp.flags & ISurfaceComposer::eLayerHidden || temp.alpha == 0) {
-            // this surface is now hidden, so it shouldn't hold a freeze lock
-            // (it may never redraw, which is fine if it is hidden)
-            mFreezeLock.clear();
-        }
-    }
-        
     return LayerBase::doTransaction(flags);
 }
 
@@ -466,7 +446,7 @@
         glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
         glTexParameterx(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 
-        // update the layer size and release freeze-lock
+        // update the layer size if needed
         const Layer::State& front(drawingState());
 
         // FIXME: mPostedDirtyRegion = dirty & bounds
@@ -503,9 +483,6 @@
 
                 // recompute visible region
                 recomputeVisibleRegions = true;
-
-                // we now have the correct size, unfreeze the screen
-                mFreezeLock.clear();
             }
 
             LOGD_IF(DEBUG_RESIZE,
@@ -538,11 +515,6 @@
         dirtyRegion.andSelf(visibleRegionScreen);
         outDirtyRegion.orSelf(dirtyRegion);
     }
-    if (visibleRegionScreen.isEmpty()) {
-        // an invisible layer should not hold a freeze-lock
-        // (because it may never be updated and therefore never release it)
-        mFreezeLock.clear();
-    }
 }
 
 void Layer::dump(String8& result, char* buffer, size_t SIZE) const
@@ -560,9 +532,9 @@
     snprintf(buffer, SIZE,
             "      "
             "format=%2d, activeBuffer=[%4ux%4u:%4u,%3X],"
-            " freezeLock=%p, transform-hint=0x%02x, queued-frames=%d\n",
+            " transform-hint=0x%02x, queued-frames=%d\n",
             mFormat, w0, h0, s0,f0,
-            getFreezeLock().get(), getTransformHint(), mQueuedFrames);
+            getTransformHint(), mQueuedFrames);
 
     result.append(buffer);
 
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 82e3521..2b9471b 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -39,7 +39,6 @@
 
 // ---------------------------------------------------------------------------
 
-class FreezeLock;
 class Client;
 class GLExtensions;
 
@@ -80,7 +79,6 @@
     virtual wp<IBinder> getSurfaceTextureBinder() const;
 
     // only for debugging
-    inline const sp<FreezeLock>&  getFreezeLock() const { return mFreezeLock; }
     inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; }
 
 protected:
@@ -124,9 +122,6 @@
     bool mProtectedByApp; // application requires protected path to external sink
     Region mPostedDirtyRegion;
 
-    // page-flip thread and transaction thread (currently main thread)
-    sp<FreezeLock>  mFreezeLock;
-
     // binder thread, transaction thread
     mutable Mutex mLock;
 };
diff --git a/services/surfaceflinger/LayerScreenshot.cpp b/services/surfaceflinger/LayerScreenshot.cpp
index e30ccbf..68e6660 100644
--- a/services/surfaceflinger/LayerScreenshot.cpp
+++ b/services/surfaceflinger/LayerScreenshot.cpp
@@ -27,6 +27,7 @@
 #include "SurfaceFlinger.h"
 #include "DisplayHardware/DisplayHardware.h"
 
+
 namespace android {
 // ---------------------------------------------------------------------------
 
@@ -45,23 +46,64 @@
     }
 }
 
+status_t LayerScreenshot::captureLocked() {
+    GLfloat u, v;
+    status_t result = mFlinger->renderScreenToTextureLocked(0, &mTextureName, &u, &v);
+    if (result != NO_ERROR) {
+        return result;
+    }
+    initTexture(u, v);
+    return NO_ERROR;
+}
+
 status_t LayerScreenshot::capture() {
     GLfloat u, v;
     status_t result = mFlinger->renderScreenToTexture(0, &mTextureName, &u, &v);
     if (result != NO_ERROR) {
         return result;
     }
+    initTexture(u, v);
+    return NO_ERROR;
+}
 
+void LayerScreenshot::initTexture(GLfloat u, GLfloat v) {
     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);
-
     mTexCoords[0] = 0;         mTexCoords[1] = v;
     mTexCoords[2] = 0;         mTexCoords[3] = 0;
     mTexCoords[4] = u;         mTexCoords[5] = 0;
     mTexCoords[6] = u;         mTexCoords[7] = v;
+}
 
-    return NO_ERROR;
+void LayerScreenshot::initStates(uint32_t w, uint32_t h, uint32_t flags) {
+    LayerBaseClient::initStates(w, h, flags);
+    if (!(flags & ISurfaceComposer::eHidden)) {
+        capture();
+    }
+}
+
+uint32_t LayerScreenshot::doTransaction(uint32_t flags)
+{
+    const Layer::State& draw(drawingState());
+    const Layer::State& curr(currentState());
+
+    if (draw.flags & ISurfaceComposer::eLayerHidden) {
+        if (!(curr.flags & ISurfaceComposer::eLayerHidden)) {
+            // we're going from hidden to visible
+            status_t err = captureLocked();
+            if (err != NO_ERROR) {
+                LOGW("createScreenshotSurface failed (%s)", strerror(-err));
+            }
+        }
+    } else if (curr.flags & ISurfaceComposer::eLayerHidden) {
+        // we're going from visible to hidden
+        if (mTextureName) {
+            glDeleteTextures(1, &mTextureName);
+            mTextureName = 0;
+        }
+    }
+    return LayerBaseClient::doTransaction(flags);
 }
 
 void LayerScreenshot::onDraw(const Region& clip) const
diff --git a/services/surfaceflinger/LayerScreenshot.h b/services/surfaceflinger/LayerScreenshot.h
index e3a2b19..ab90047 100644
--- a/services/surfaceflinger/LayerScreenshot.h
+++ b/services/surfaceflinger/LayerScreenshot.h
@@ -41,12 +41,18 @@
 
         status_t capture();
 
+    virtual void initStates(uint32_t w, uint32_t h, uint32_t flags);
+    virtual uint32_t doTransaction(uint32_t flags);
     virtual void onDraw(const Region& clip) const;
     virtual bool isOpaque() const         { return false; }
     virtual bool isSecure() const         { return false; }
     virtual bool isProtectedByApp() const { return false; }
     virtual bool isProtectedByDRM() const { return false; }
     virtual const char* getTypeId() const { return "LayerScreenshot"; }
+
+private:
+    status_t captureLocked();
+    void initTexture(GLfloat u, GLfloat v);
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ba8f630..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 {
@@ -80,15 +82,12 @@
 SurfaceFlinger::SurfaceFlinger()
     :   BnSurfaceComposer(), Thread(false),
         mTransactionFlags(0),
-        mResizeTransationPending(false),
+        mTransationPending(false),
         mLayersRemoved(false),
         mBootTime(systemTime()),
         mVisibleRegionsDirty(false),
         mHwWorkListDirty(false),
-        mFreezeDisplay(false),
         mElectronBeamAnimationMode(0),
-        mFreezeCount(0),
-        mFreezeDisplayTime(0),
         mDebugRegion(0),
         mDebugBackground(0),
         mDebugDDMS(0),
@@ -191,11 +190,6 @@
 {
     // the window manager died on us. prepare its eulogy.
 
-    // unfreeze the screen in case it was... frozen
-    mFreezeDisplayTime = 0;
-    mFreezeCount = 0;
-    mFreezeDisplay = false;
-
     // reset screen orientation
     setOrientation(0, eOrientationDefault, 0);
 
@@ -323,33 +317,7 @@
 {
     while (true) {
         nsecs_t timeout = -1;
-        const nsecs_t freezeDisplayTimeout = ms2ns(5000);
-        if (UNLIKELY(isFrozen())) {
-            // wait 5 seconds
-            const nsecs_t now = systemTime();
-            if (mFreezeDisplayTime == 0) {
-                mFreezeDisplayTime = now;
-            }
-            nsecs_t waitTime = freezeDisplayTimeout - (now - mFreezeDisplayTime);
-            timeout = waitTime>0 ? waitTime : 0;
-        }
-
         sp<MessageBase> msg = mEventQueue.waitMessage(timeout);
-
-        // see if we timed out
-        if (isFrozen()) {
-            const nsecs_t now = systemTime();
-            nsecs_t frozenTime = (now - mFreezeDisplayTime);
-            if (frozenTime >= freezeDisplayTimeout) {
-                // we timed out and are still frozen
-                LOGW("timeout expired mFreezeDisplay=%d, mFreezeCount=%d",
-                        mFreezeDisplay, mFreezeCount);
-                mFreezeDisplayTime = 0;
-                mFreezeCount = 0;
-                mFreezeDisplay = false;
-            }
-        }
-
         if (msg != 0) {
             switch (msg->what) {
                 case MessageQueue::INVALIDATE:
@@ -589,13 +557,6 @@
             mDirtyRegion.set(hw.bounds());
         }
 
-        if (mCurrentState.freezeDisplay != mDrawingState.freezeDisplay) {
-            // freezing or unfreezing the display -> trigger animation if needed
-            mFreezeDisplay = mCurrentState.freezeDisplay;
-            if (mFreezeDisplay)
-                 mFreezeDisplayTime = 0;
-        }
-
         if (currentLayers.size() > mDrawingState.layersSortedByZ.size()) {
             // layers have been added
             mVisibleRegionsDirty = true;
@@ -621,11 +582,6 @@
     commitTransaction();
 }
 
-sp<FreezeLock> SurfaceFlinger::getFreezeLock() const
-{
-    return new FreezeLock(const_cast<SurfaceFlinger *>(this));
-}
-
 void SurfaceFlinger::computeVisibleRegions(
     const LayerVector& currentLayers, Region& dirtyRegion, Region& opaqueRegion)
 {
@@ -754,8 +710,16 @@
 
 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;
-    mResizeTransationPending = false;
+    mTransationPending = false;
     mTransactionCV.broadcast();
 }
 
@@ -1206,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
@@ -1243,15 +1207,14 @@
 
 
 void SurfaceFlinger::setTransactionState(const Vector<ComposerState>& state,
-        int orientation) {
+        int orientation, uint32_t flags) {
     Mutex::Autolock _l(mStateLock);
 
-    uint32_t flags = 0;
+    uint32_t transactionFlags = 0;
     if (mCurrentState.orientation != orientation) {
         if (uint32_t(orientation)<=eOrientation270 || orientation==42) {
             mCurrentState.orientation = orientation;
-            flags |= eTransactionNeeded;
-            mResizeTransationPending = true;
+            transactionFlags |= eTransactionNeeded;
         } else if (orientation != eOrientationUnchanged) {
             LOGW("setTransactionState: ignoring unrecognized orientation: %d",
                     orientation);
@@ -1262,56 +1225,31 @@
     for (size_t i=0 ; i<count ; i++) {
         const ComposerState& s(state[i]);
         sp<Client> client( static_cast<Client *>(s.client.get()) );
-        flags |= setClientStateLocked(client, s.state);
-    }
-    if (flags) {
-        setTransactionFlags(flags);
+        transactionFlags |= setClientStateLocked(client, s.state);
     }
 
-    signalEvent();
+    if (transactionFlags) {
+        // this triggers the transaction
+        setTransactionFlags(transactionFlags);
 
-    // if there is a transaction with a resize, wait for it to
-    // take effect before returning.
-    while (mResizeTransationPending) {
-        status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
-        if (CC_UNLIKELY(err != NO_ERROR)) {
-            // just in case something goes wrong in SF, return to the
-            // called after a few seconds.
-            LOGW_IF(err == TIMED_OUT, "closeGlobalTransaction timed out!");
-            mResizeTransationPending = false;
-            break;
+        // if this is a synchronous transaction, wait for it to take effect
+        // before returning.
+        if (flags & eSynchronous) {
+            mTransationPending = true;
+        }
+        while (mTransationPending) {
+            status_t err = mTransactionCV.waitRelative(mStateLock, s2ns(5));
+            if (CC_UNLIKELY(err != NO_ERROR)) {
+                // just in case something goes wrong in SF, return to the
+                // called after a few seconds.
+                LOGW_IF(err == TIMED_OUT, "closeGlobalTransaction timed out!");
+                mTransationPending = false;
+                break;
+            }
         }
     }
 }
 
-status_t SurfaceFlinger::freezeDisplay(DisplayID dpy, uint32_t flags)
-{
-    if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
-        return BAD_VALUE;
-
-    Mutex::Autolock _l(mStateLock);
-    mCurrentState.freezeDisplay = 1;
-    setTransactionFlags(eTransactionNeeded);
-
-    // flags is intended to communicate some sort of animation behavior
-    // (for instance fading)
-    return NO_ERROR;
-}
-
-status_t SurfaceFlinger::unfreezeDisplay(DisplayID dpy, uint32_t flags)
-{
-    if (UNLIKELY(uint32_t(dpy) >= DISPLAY_COUNT))
-        return BAD_VALUE;
-
-    Mutex::Autolock _l(mStateLock);
-    mCurrentState.freezeDisplay = 0;
-    setTransactionFlags(eTransactionNeeded);
-
-    // flags is intended to communicate some sort of animation behavior
-    // (for instance fading)
-    return NO_ERROR;
-}
-
 int SurfaceFlinger::setOrientation(DisplayID dpy,
         int orientation, uint32_t flags)
 {
@@ -1434,11 +1372,6 @@
         uint32_t w, uint32_t h, uint32_t flags)
 {
     sp<LayerScreenshot> layer = new LayerScreenshot(this, display, client);
-    status_t err = layer->capture();
-    if (err != NO_ERROR) {
-        layer.clear();
-        LOGW("createScreenshotSurface failed (%s)", strerror(-err));
-    }
     return layer;
 }
 
@@ -1512,7 +1445,6 @@
         if (what & eSizeChanged) {
             if (layer->setSize(s.w, s.h)) {
                 flags |= eTraversalNeeded;
-                mResizeTransationPending = true;
             }
         }
         if (what & eAlphaChanged) {
@@ -1605,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++) {
@@ -1626,14 +1558,19 @@
                 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);
 
         mWormholeRegion.dump(result, "WormholeRegion");
         const DisplayHardware& hw(graphicPlane(0).displayHardware());
         snprintf(buffer, SIZE,
-                "  display frozen: %s, freezeCount=%d, orientation=%d, canDraw=%d\n",
-                mFreezeDisplay?"yes":"no", mFreezeCount,
+                "  orientation=%d, canDraw=%d\n",
                 mCurrentState.orientation, hw.canDraw());
         result.append(buffer);
         snprintf(buffer, SIZE,
@@ -1693,8 +1630,6 @@
         case CREATE_CONNECTION:
         case SET_TRANSACTION_STATE:
         case SET_ORIENTATION:
-        case FREEZE_DISPLAY:
-        case UNFREEZE_DISPLAY:
         case BOOT_FINISHED:
         case TURN_ELECTRON_BEAM_OFF:
         case TURN_ELECTRON_BEAM_ON:
@@ -1766,10 +1701,6 @@
                 GraphicLog::getInstance().setEnabled(enabled);
                 return NO_ERROR;
             }
-            case 1007: // set mFreezeCount
-                mFreezeCount = data.readInt32();
-                mFreezeDisplayTime = 0;
-                return NO_ERROR;
             case 1008:  // toggle use of hw composer
                 n = data.readInt32();
                 mDebugDisableHWC = n ? 1 : 0;
@@ -1866,8 +1797,10 @@
     // redraw the screen entirely...
     glDisable(GL_TEXTURE_EXTERNAL_OES);
     glDisable(GL_TEXTURE_2D);
+    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);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 3284fdb..17b80a6 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -46,7 +46,6 @@
 
 class Client;
 class DisplayHardware;
-class FreezeLock;
 class Layer;
 class LayerDim;
 class LayerScreenshot;
@@ -169,9 +168,7 @@
     virtual sp<IMemoryHeap>             getCblk() const;
     virtual void                        bootFinished();
     virtual void                        setTransactionState(const Vector<ComposerState>& state,
-                                                            int orientation);
-    virtual status_t                    freezeDisplay(DisplayID dpy, uint32_t flags);
-    virtual status_t                    unfreezeDisplay(DisplayID dpy, uint32_t flags);
+                                                            int orientation, uint32_t flags);
     virtual int                         setOrientation(DisplayID dpy, int orientation, uint32_t flags);
     virtual bool                        authenticateSurfaceTexture(const sp<ISurfaceTexture>& surface) const;
 
@@ -189,6 +186,8 @@
 
             status_t renderScreenToTexture(DisplayID dpy,
                     GLuint* textureName, GLfloat* uOut, GLfloat* vOut);
+            status_t renderScreenToTextureLocked(DisplayID dpy,
+                    GLuint* textureName, GLfloat* uOut, GLfloat* vOut);
 
             status_t postMessageAsync(const sp<MessageBase>& msg,
                     nsecs_t reltime=0, uint32_t flags = 0);
@@ -269,12 +268,10 @@
     struct State {
         State() {
             orientation = ISurfaceComposer::eOrientationDefault;
-            freezeDisplay = 0;
         }
         LayerVector     layersSortedByZ;
         uint8_t         orientation;
         uint8_t         orientationFlags;
-        uint8_t         freezeDisplay;
     };
 
     virtual bool        threadLoop();
@@ -333,23 +330,7 @@
             status_t turnElectronBeamOnImplLocked(int32_t mode);
             status_t electronBeamOffAnimationImplLocked();
             status_t electronBeamOnAnimationImplLocked();
-            status_t renderScreenToTextureLocked(DisplayID dpy,
-                    GLuint* textureName, GLfloat* uOut, GLfloat* vOut);
 
-            friend class FreezeLock;
-            sp<FreezeLock> getFreezeLock() const;
-            inline void incFreezeCount() {
-                if (mFreezeCount == 0)
-                    mFreezeDisplayTime = 0;
-                mFreezeCount++;
-            }
-            inline void decFreezeCount() { if (mFreezeCount > 0) mFreezeCount--; }
-            inline bool hasFreezeRequest() const { return mFreezeDisplay; }
-            inline bool isFrozen() const { 
-                return (mFreezeDisplay || mFreezeCount>0) && mBootFinished;
-            }
-
-            
             void        debugFlashRegions();
             void        debugShowFPS() const;
             void        drawWormhole() const;
@@ -363,7 +344,8 @@
     volatile    int32_t                 mTransactionFlags;
                 Condition               mTransactionCV;
                 SortedVector< sp<LayerBase> > mLayerPurgatory;
-                bool                    mResizeTransationPending;
+                bool                    mTransationPending;
+                Vector< sp<LayerBase> > mLayersPendingRemoval;
 
                 // protected by mStateLock (but we could use another lock)
                 GraphicPlane                mGraphicPlanes[1];
@@ -390,10 +372,7 @@
                 Region                      mWormholeRegion;
                 bool                        mVisibleRegionsDirty;
                 bool                        mHwWorkListDirty;
-                bool                        mFreezeDisplay;
                 int32_t                     mElectronBeamAnimationMode;
-                int32_t                     mFreezeCount;
-                nsecs_t                     mFreezeDisplayTime;
                 Vector< sp<LayerBase> >     mVisibleLayersSortedByZ;
 
 
@@ -429,20 +408,6 @@
 };
 
 // ---------------------------------------------------------------------------
-
-class FreezeLock : public LightRefBase<FreezeLock> {
-    SurfaceFlinger* mFlinger;
-public:
-    FreezeLock(SurfaceFlinger* flinger)
-        : mFlinger(flinger) {
-        mFlinger->incFreezeCount();
-    }
-    ~FreezeLock() {
-        mFlinger->decFreezeCount();
-    }
-};
-
-// ---------------------------------------------------------------------------
 }; // namespace android
 
 #endif // ANDROID_SURFACE_FLINGER_H
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() {
diff --git a/services/surfaceflinger/tests/Android.mk b/services/surfaceflinger/tests/Android.mk
index 5053e7d..b655648 100644
--- a/services/surfaceflinger/tests/Android.mk
+++ b/services/surfaceflinger/tests/Android.mk
@@ -1 +1,40 @@
-include $(call all-subdir-makefiles)
+# Build the unit tests,
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := SurfaceFlinger_test
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+    Transaction_test.cpp \
+
+LOCAL_SHARED_LIBRARIES := \
+	libEGL \
+	libGLESv2 \
+	libandroid \
+	libbinder \
+	libcutils \
+	libgui \
+	libstlport \
+	libui \
+	libutils \
+
+LOCAL_C_INCLUDES := \
+    bionic \
+    bionic/libstdc++/include \
+    external/gtest/include \
+    external/stlport/stlport \
+
+# Build the binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
+# to integrate with auto-test framework.
+include $(BUILD_NATIVE_TEST)
+
+# Include subdirectory makefiles
+# ============================================================
+
+# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
+# team really wants is to build the stuff defined by this makefile.
+ifeq (,$(ONE_SHOT_MAKEFILE))
+include $(call first-makefiles-under,$(LOCAL_PATH))
+endif
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
new file mode 100644
index 0000000..afafd8a
--- /dev/null
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include <binder/IMemory.h>
+#include <surfaceflinger/ISurfaceComposer.h>
+#include <surfaceflinger/Surface.h>
+#include <surfaceflinger/SurfaceComposerClient.h>
+#include <utils/String8.h>
+
+namespace android {
+
+// Fill an RGBA_8888 formatted surface with a single color.
+static void fillSurfaceRGBA8(const sp<SurfaceControl>& sc,
+        uint8_t r, uint8_t g, uint8_t b) {
+    Surface::SurfaceInfo info;
+    sp<Surface> s = sc->getSurface();
+    ASSERT_TRUE(s != NULL);
+    ASSERT_EQ(NO_ERROR, s->lock(&info));
+    uint8_t* img = reinterpret_cast<uint8_t*>(info.bits);
+    for (uint32_t y = 0; y < info.h; y++) {
+        for (uint32_t x = 0; x < info.w; x++) {
+            uint8_t* pixel = img + (4 * (y*info.s + x));
+            pixel[0] = r;
+            pixel[1] = g;
+            pixel[2] = b;
+            pixel[3] = 255;
+        }
+    }
+    ASSERT_EQ(NO_ERROR, s->unlockAndPost());
+}
+
+// A ScreenCapture is a screenshot from SurfaceFlinger that can be used to check
+// individual pixel values for testing purposes.
+class ScreenCapture : public RefBase {
+public:
+    static void captureScreen(sp<ScreenCapture>* sc) {
+        sp<IMemoryHeap> heap;
+        uint32_t w=0, h=0;
+        PixelFormat fmt=0;
+        sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+        ASSERT_EQ(NO_ERROR, sf->captureScreen(0, &heap, &w, &h, &fmt, 0, 0,
+                0, INT_MAX));
+        ASSERT_TRUE(heap != NULL);
+        ASSERT_EQ(PIXEL_FORMAT_RGBA_8888, fmt);
+        *sc = new ScreenCapture(w, h, heap);
+    }
+
+    void checkPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b) {
+        const uint8_t* img = reinterpret_cast<const uint8_t*>(mHeap->base());
+        const uint8_t* pixel = img + (4 * (y*mWidth + x));
+        if (r != pixel[0] || g != pixel[1] || b != pixel[2]) {
+            String8 err(String8::format("pixel @ (%3d, %3d): "
+                    "expected [%3d, %3d, %3d], got [%3d, %3d, %3d]",
+                    x, y, r, g, b, pixel[0], pixel[1], pixel[2]));
+            EXPECT_EQ(String8(), err);
+        }
+    }
+
+private:
+    ScreenCapture(uint32_t w, uint32_t h, const sp<IMemoryHeap>& heap) :
+        mWidth(w),
+        mHeight(h),
+        mHeap(heap)
+    {}
+
+    const uint32_t mWidth;
+    const uint32_t mHeight;
+    sp<IMemoryHeap> mHeap;
+};
+
+class LayerUpdateTest : public ::testing::Test {
+protected:
+    virtual void SetUp() {
+        mComposerClient = new SurfaceComposerClient;
+        ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
+
+        ssize_t displayWidth = mComposerClient->getDisplayWidth(0);
+        ssize_t displayHeight = mComposerClient->getDisplayHeight(0);
+
+        // Background surface
+        mBGSurfaceControl = mComposerClient->createSurface(
+                String8("BG Test Surface"), 0, displayWidth, displayHeight,
+                PIXEL_FORMAT_RGBA_8888, 0);
+        ASSERT_TRUE(mBGSurfaceControl != NULL);
+        ASSERT_TRUE(mBGSurfaceControl->isValid());
+        fillSurfaceRGBA8(mBGSurfaceControl, 63, 63, 195);
+
+        // Foreground surface
+        mFGSurfaceControl = mComposerClient->createSurface(
+                String8("FG Test Surface"), 0, 64, 64, PIXEL_FORMAT_RGBA_8888, 0);
+        ASSERT_TRUE(mFGSurfaceControl != NULL);
+        ASSERT_TRUE(mFGSurfaceControl->isValid());
+
+        fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+
+        // Synchronization surface
+        mSyncSurfaceControl = mComposerClient->createSurface(
+                String8("Sync Test Surface"), 0, 1, 1, PIXEL_FORMAT_RGBA_8888, 0);
+        ASSERT_TRUE(mSyncSurfaceControl != NULL);
+        ASSERT_TRUE(mSyncSurfaceControl->isValid());
+
+        fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+
+        SurfaceComposerClient::openGlobalTransaction();
+
+        ASSERT_EQ(NO_ERROR, mBGSurfaceControl->setLayer(INT_MAX-2));
+        ASSERT_EQ(NO_ERROR, mBGSurfaceControl->show());
+
+        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setLayer(INT_MAX-1));
+        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(64, 64));
+        ASSERT_EQ(NO_ERROR, mFGSurfaceControl->show());
+
+        ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->setLayer(INT_MAX-1));
+        ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->setPosition(displayWidth-2,
+                displayHeight-2));
+        ASSERT_EQ(NO_ERROR, mSyncSurfaceControl->show());
+
+        SurfaceComposerClient::closeGlobalTransaction(true);
+    }
+
+    virtual void TearDown() {
+        mComposerClient->dispose();
+        mBGSurfaceControl = 0;
+        mFGSurfaceControl = 0;
+        mSyncSurfaceControl = 0;
+        mComposerClient = 0;
+    }
+
+    void waitForPostedBuffers() {
+        // Since the sync surface is in synchronous mode (i.e. double buffered)
+        // posting three buffers to it should ensure that at least two
+        // SurfaceFlinger::handlePageFlip calls have been made, which should
+        // guaranteed that a buffer posted to another Surface has been retired.
+        fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+        fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+        fillSurfaceRGBA8(mSyncSurfaceControl, 31, 31, 31);
+    }
+
+    sp<SurfaceComposerClient> mComposerClient;
+    sp<SurfaceControl> mBGSurfaceControl;
+    sp<SurfaceControl> mFGSurfaceControl;
+
+    // This surface is used to ensure that the buffers posted to
+    // mFGSurfaceControl have been picked up by SurfaceFlinger.
+    sp<SurfaceControl> mSyncSurfaceControl;
+};
+
+TEST_F(LayerUpdateTest, LayerMoveWorks) {
+    sp<ScreenCapture> sc;
+    {
+        SCOPED_TRACE("before move");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(  0,  12,  63,  63, 195);
+        sc->checkPixel( 75,  75, 195,  63,  63);
+        sc->checkPixel(145, 145,  63,  63, 195);
+    }
+
+    SurfaceComposerClient::openGlobalTransaction();
+    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setPosition(128, 128));
+    SurfaceComposerClient::closeGlobalTransaction(true);
+    {
+        // This should reflect the new position, but not the new color.
+        SCOPED_TRACE("after move, before redraw");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel( 24,  24,  63,  63, 195);
+        sc->checkPixel( 75,  75,  63,  63, 195);
+        sc->checkPixel(145, 145, 195,  63,  63);
+    }
+
+    fillSurfaceRGBA8(mFGSurfaceControl, 63, 195, 63);
+    waitForPostedBuffers();
+    {
+        // This should reflect the new position and the new color.
+        SCOPED_TRACE("after redraw");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel( 24,  24,  63,  63, 195);
+        sc->checkPixel( 75,  75,  63,  63, 195);
+        sc->checkPixel(145, 145,  63, 195,  63);
+    }
+}
+
+TEST_F(LayerUpdateTest, LayerResizeWorks) {
+    sp<ScreenCapture> sc;
+    {
+        SCOPED_TRACE("before resize");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(  0,  12,  63,  63, 195);
+        sc->checkPixel( 75,  75, 195,  63,  63);
+        sc->checkPixel(145, 145,  63,  63, 195);
+    }
+
+    LOGD("resizing");
+    SurfaceComposerClient::openGlobalTransaction();
+    ASSERT_EQ(NO_ERROR, mFGSurfaceControl->setSize(128, 128));
+    SurfaceComposerClient::closeGlobalTransaction(true);
+    LOGD("resized");
+    {
+        // This should not reflect the new size or color because SurfaceFlinger
+        // has not yet received a buffer of the correct size.
+        SCOPED_TRACE("after resize, before redraw");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel(  0,  12,  63,  63, 195);
+        sc->checkPixel( 75,  75, 195,  63,  63);
+        sc->checkPixel(145, 145,  63,  63, 195);
+    }
+
+    LOGD("drawing");
+    fillSurfaceRGBA8(mFGSurfaceControl, 63, 195, 63);
+    waitForPostedBuffers();
+    LOGD("drawn");
+    {
+        // This should reflect the new size and the new color.
+        SCOPED_TRACE("after redraw");
+        ScreenCapture::captureScreen(&sc);
+        sc->checkPixel( 24,  24,  63,  63, 195);
+        sc->checkPixel( 75,  75,  63, 195,  63);
+        sc->checkPixel(145, 145,  63, 195,  63);
+    }
+}
+
+}