Make sure atlas antries can correctly filter/wrap textures

The virtual textures would each have their own values for wrapping
and filtering which could lead to conflict and/or extraneous GL
commands being issued.

Change-Id: I64cb59a03e598f46bf645bd1d30fccfa63a07431
diff --git a/libs/hwui/AssetAtlas.cpp b/libs/hwui/AssetAtlas.cpp
index 4d2fc014..8511e7c 100644
--- a/libs/hwui/AssetAtlas.cpp
+++ b/libs/hwui/AssetAtlas.cpp
@@ -31,11 +31,12 @@
     }
 
     mImage = new Image(buffer);
-    mTexture = mImage->getTexture();
 
-    if (mTexture) {
-        mWidth = buffer->getWidth();
-        mHeight = buffer->getHeight();
+    if (mImage->getTexture()) {
+        mTexture = new Texture();
+        mTexture->id = mImage->getTexture();
+        mTexture->width = buffer->getWidth();
+        mTexture->height = buffer->getHeight();
 
         createEntries(map, count);
     } else {
@@ -43,6 +44,7 @@
 
         delete mImage;
         mImage = NULL;
+        mTexture = NULL;
     }
 }
 
@@ -51,12 +53,13 @@
         delete mImage;
         mImage = NULL;
 
+        delete mTexture;
+        mTexture = NULL;
+
         for (size_t i = 0; i < mEntries.size(); i++) {
             delete mEntries.valueAt(i);
         }
         mEntries.clear();
-
-        mWidth = mHeight = 0;
     }
 }
 
@@ -71,13 +74,36 @@
 
 Texture* AssetAtlas::getEntryTexture(SkBitmap* const bitmap) const {
     ssize_t index = mEntries.indexOfKey(bitmap);
-    return index >= 0 ? &mEntries.valueAt(index)->texture : NULL;
+    return index >= 0 ? mEntries.valueAt(index)->texture : NULL;
 }
 
 /**
+ * Delegates changes to wrapping and filtering to the base atlas texture
+ * instead of applying the changes to the virtual textures.
+ */
+struct DelegateTexture: public Texture {
+    DelegateTexture(Texture* delegate): Texture(), mDelegate(delegate) { }
+
+    virtual void setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture = false,
+            bool force = false, GLenum renderTarget = GL_TEXTURE_2D) {
+        mDelegate->setWrapST(wrapS, wrapT, bindTexture, force, renderTarget);
+    }
+
+    virtual void setFilterMinMag(GLenum min, GLenum mag, bool bindTexture = false,
+            bool force = false, GLenum renderTarget = GL_TEXTURE_2D) {
+        mDelegate->setFilterMinMag(min, mag, bindTexture, force, renderTarget);
+    }
+private:
+    Texture* const mDelegate;
+}; // struct DelegateTexture
+
+/**
  * TODO: This method does not take the rotation flag into account
  */
 void AssetAtlas::createEntries(int* map, int count) {
+    const float width = float(mTexture->width);
+    const float height = float(mTexture->height);
+
     for (int i = 0; i < count; ) {
         SkBitmap* bitmap = (SkBitmap*) map[i++];
         int x = map[i++];
@@ -88,15 +114,17 @@
         if (!bitmap) continue;
 
         const UvMapper mapper(
-                x / (float) mWidth, (x + bitmap->width()) / (float) mWidth,
-                y / (float) mHeight, (y + bitmap->height()) / (float) mHeight);
+                x / width, (x + bitmap->width()) / width,
+                y / height, (y + bitmap->height()) / height);
 
-        Entry* entry = new Entry(bitmap, x, y, rotated, mapper, *this);
-        entry->texture.id = mTexture;
-        entry->texture.blend = !bitmap->isOpaque();
-        entry->texture.width = bitmap->width();
-        entry->texture.height = bitmap->height();
-        entry->texture.uvMapper = &entry->uvMapper;
+        Texture* texture = new DelegateTexture(mTexture);
+        Entry* entry = new Entry(bitmap, x, y, rotated, texture, mapper, *this);
+
+        texture->id = mTexture->id;
+        texture->blend = !bitmap->isOpaque();
+        texture->width = bitmap->width();
+        texture->height = bitmap->height();
+        texture->uvMapper = &entry->uvMapper;
 
         mEntries.add(entry->bitmap, entry);
     }