Add hooks for drawBitmap().

Change-Id: I58e962c3a8b2bc75c2605fe369ad3002579d86e0

Add texture cache.

Change-Id: I1c0e5581d228869e114438258a1014e33e024ad7
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index fd76811..95ebda1 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -4,7 +4,8 @@
 LOCAL_SRC_FILES:= \
 	Matrix.cpp \
 	OpenGLRenderer.cpp \
-	Program.cpp
+	Program.cpp \
+	TextureCache.cpp
 
 LOCAL_C_INCLUDES += \
 	$(JNI_H_INCLUDE) \
diff --git a/libs/hwui/GenerationCache.h b/libs/hwui/GenerationCache.h
new file mode 100644
index 0000000..c4ff587
--- /dev/null
+++ b/libs/hwui/GenerationCache.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2010 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_UI_GENERATION_CACHE_H
+#define ANDROID_UI_GENERATION_CACHE_H
+
+#include <utils/KeyedVector.h>
+#include <utils/RefBase.h>
+
+namespace android {
+namespace uirenderer {
+
+template<typename EntryKey, typename EntryValue>
+class OnEntryRemoved {
+public:
+    virtual ~OnEntryRemoved() { };
+    virtual void operator()(EntryKey key, EntryValue value) = 0;
+}; // class OnEntryRemoved
+
+template<typename K, typename V>
+class GenerationCache {
+public:
+    GenerationCache(unsigned int maxCapacity): mMaxCapacity(maxCapacity), mListener(NULL) { };
+    ~GenerationCache() { clear(); };
+
+    void setOnEntryRemovedListener(OnEntryRemoved<K*, V*>* listener);
+
+    void clear();
+
+    bool contains(K* key) const;
+    const V* get(K* key);
+    void put(K* key, V* value);
+    const V* remove(K* key);
+
+    unsigned int size() const;
+
+private:
+    void removeOldest();
+
+    template<typename EntryKey, typename EntryValue>
+    struct Entry: public LightRefBase<Entry<EntryKey, EntryValue> > {
+        Entry() { }
+        Entry(const Entry<EntryKey, EntryValue>& e):
+                key(e.key), value(e.value), parent(e.parent), child(e.child) { }
+        Entry(sp<Entry<EntryKey, EntryValue> > e):
+                key(e->key), value(e->value), parent(e->parent), child(e->child) { }
+
+        EntryKey key;
+        EntryValue value;
+
+        sp<Entry<EntryKey, EntryValue> > parent;
+        sp<Entry<EntryKey, EntryValue> > child;
+    }; // struct Entry
+
+    void addToCache(sp<Entry<K*, V*> > entry, K* key, V* value);
+    void attachToCache(sp<Entry<K*, V*> > entry);
+    void detachFromCache(sp<Entry<K*, V*> > entry);
+
+    unsigned int mMaxCapacity;
+
+    OnEntryRemoved<K*, V*>* mListener;
+
+    KeyedVector<K*, sp<Entry<K*, V*> > > mCache;
+
+    sp<Entry<K*, V*> > mOldest;
+    sp<Entry<K*, V*> > mYougest;
+}; // class GenerationCache
+
+template<typename K, typename V>
+unsigned int GenerationCache<K, V>::size() const {
+    return mCache.size();
+}
+
+template<typename K, typename V>
+void GenerationCache<K, V>::setOnEntryRemovedListener(OnEntryRemoved<K*, V*>* listener) {
+    mListener = listener;
+}
+
+template<typename K, typename V>
+void GenerationCache<K, V>::clear() {
+    if (mListener) {
+        while (mCache.size() > 0) {
+            removeOldest();
+        }
+    } else {
+        mCache.clear();
+    }
+    mYougest.clear();
+    mOldest.clear();
+}
+
+template<typename K, typename V>
+bool GenerationCache<K, V>::contains(K* key) const {
+    return mCache.indexOfKey(key) >= 0;
+}
+
+template<typename K, typename V>
+const V* GenerationCache<K, V>::get(K* key) {
+    ssize_t index = mCache.indexOfKey(key);
+    if (index >= 0) {
+        sp<Entry<K*, V*> > entry = mCache.valueAt(index);
+        if (entry.get()) {
+            detachFromCache(entry);
+            attachToCache(entry);
+            return entry->value;
+        }
+    }
+
+    return NULL;
+}
+
+template<typename K, typename V>
+void GenerationCache<K, V>::put(K* key, V* value) {
+    if (mCache.size() >= mMaxCapacity) {
+        removeOldest();
+    }
+
+    ssize_t index = mCache.indexOfKey(key);
+    if (index >= 0) {
+        sp<Entry<K*, V*> > entry = mCache.valueAt(index);
+        detachFromCache(entry);
+        addToCache(entry, key, value);
+    } else {
+        sp<Entry<K*, V*> > entry = new Entry<K*, V*>;
+        addToCache(entry, key, value);
+    }
+}
+
+template<typename K, typename V>
+void GenerationCache<K, V>::addToCache(sp<Entry<K*, V*> > entry, K* key, V* value) {
+    entry->key = key;
+    entry->value = value;
+    mCache.add(key, entry);
+    attachToCache(entry);
+}
+
+template<typename K, typename V>
+const V* GenerationCache<K, V>::remove(K* key) {
+    ssize_t index = mCache.indexOfKey(key);
+    if (index >= 0) {
+        sp<Entry<K*, V*> > entry = mCache.valueAt(index);
+        if (mListener) {
+            (*mListener)(entry->key, entry->value);
+        }
+        mCache.removeItemsAt(index, 1);
+        detachFromCache(entry);
+    }
+
+    return NULL;
+}
+
+template<typename K, typename V>
+void GenerationCache<K, V>::removeOldest() {
+    if (mOldest.get()) {
+        remove(mOldest->key);
+    }
+}
+
+template<typename K, typename V>
+void GenerationCache<K, V>::attachToCache(sp<Entry<K*, V*> > entry) {
+    if (!mYougest.get()) {
+        mYougest = mOldest = entry;
+    } else {
+        entry->parent = mYougest;
+        mYougest->child = entry;
+        mYougest = entry;
+    }
+}
+
+template<typename K, typename V>
+void GenerationCache<K, V>::detachFromCache(sp<Entry<K*, V*> > entry) {
+    if (entry->parent.get()) {
+        entry->parent->child = entry->child;
+    }
+
+    if (entry->child.get()) {
+        entry->child->parent = entry->parent;
+    }
+
+    if (mOldest == entry) {
+        mOldest = entry->child;
+    }
+
+    if (mYougest == entry) {
+        mYougest = entry->parent;
+    }
+
+    entry->parent.clear();
+    entry->child.clear();
+}
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_UI_GENERATION_CACHE_H
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index aa992c4..d8023859 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -33,6 +33,8 @@
 // Defines
 ///////////////////////////////////////////////////////////////////////////////
 
+#define MAX_TEXTURE_COUNT 128
+
 #define SV(x, y) { { x, y } }
 #define FV(x, y, u, v) { { x, y }, { u, v } }
 
@@ -81,7 +83,7 @@
 // Constructors/destructor
 ///////////////////////////////////////////////////////////////////////////////
 
-OpenGLRenderer::OpenGLRenderer() {
+OpenGLRenderer::OpenGLRenderer(): mTextureCache(MAX_TEXTURE_COUNT) {
     LOGD("Create OpenGLRenderer");
 
     mDrawColorShader = new DrawColorProgram;
@@ -92,6 +94,8 @@
 
 OpenGLRenderer::~OpenGLRenderer() {
     LOGD("Destroy OpenGLRenderer");
+
+    mTextureCache.clear();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -374,6 +378,10 @@
 // Drawing
 ///////////////////////////////////////////////////////////////////////////////
 
+void OpenGLRenderer::drawBitmap(const SkBitmap* bitmap, float left, float top, const SkPaint* paint) {
+    LOGD("Drawing bitmap!");
+}
+
 void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
     const Rect& clip = mSnapshot->clipRect;
     drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode);
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 1af73c1..e5cc98c 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -20,7 +20,9 @@
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
+#include <SkBitmap.h>
 #include <SkMatrix.h>
+#include <SkPaint.h>
 #include <SkXfermode.h>
 
 #include <utils/RefBase.h>
@@ -29,6 +31,8 @@
 #include "Program.h"
 #include "Rect.h"
 #include "Snapshot.h"
+#include "Texture.h"
+#include "TextureCache.h"
 
 namespace android {
 namespace uirenderer {
@@ -98,6 +102,7 @@
     bool quickReject(float left, float top, float right, float bottom);
     bool clipRect(float left, float top, float right, float bottom);
 
+    void drawBitmap(const SkBitmap* bitmap, float left, float top, const SkPaint* paint);
     void drawColor(int color, SkXfermode::Mode mode);
     void drawRect(float left, float top, float right, float bottom, const SkPaint* paint);
 
@@ -218,6 +223,9 @@
 
     // Used to draw textured quads
     TextureVertex mDrawTextureVertices[4];
+
+    // Used to cache all drawBitmap textures
+    TextureCache mTextureCache;
 }; // class OpenGLRenderer
 
 }; // namespace uirenderer
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
new file mode 100644
index 0000000..b3b17ca
--- /dev/null
+++ b/libs/hwui/Texture.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010 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_UI_TEXTURE_H
+#define ANDROID_UI_TEXTURE_H
+
+#include <GLES2/gl2.h>
+
+namespace android {
+namespace uirenderer {
+
+/**
+ * Represents an OpenGL texture.
+ */
+struct Texture {
+    /**
+     * Name of the texture.
+     */
+    GLuint id;
+    /**
+     * Indicates whether the texture requires blending.
+     */
+    bool blend;
+    /**
+     * Width of the backing bitmap.
+     */
+    unsigned int width;
+    /**
+     * Height of the backing bitmap.
+     */
+    unsigned int height;
+}; // struct Texture
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_UI_TEXTURE_H
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
new file mode 100644
index 0000000..b4a57ee
--- /dev/null
+++ b/libs/hwui/TextureCache.cpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2010 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 <GLES2/gl2.h>
+
+#include "TextureCache.h"
+
+namespace android {
+namespace uirenderer {
+
+TextureCache::TextureCache(unsigned int maxEntries): mCache(maxEntries) {
+    mCache.setOnEntryRemovedListener(this);
+}
+
+TextureCache::~TextureCache() {
+    mCache.clear();
+}
+
+void TextureCache::operator()(SkBitmap* key, Texture* value) {
+    LOGD("Entry removed");
+    if (value) {
+        glDeleteTextures(1, &value->id);
+        delete value;
+    }
+}
+
+Texture* TextureCache::get(SkBitmap* bitmap) {
+    Texture* texture = mCache.get(bitmap);
+    if (!texture) {
+        texture = generateTexture(bitmap);
+        mCache.put(bitmap, texture);
+    }
+    return texture;
+}
+
+Texture* TextureCache::remove(SkBitmap* bitmap) {
+    return mCache.remove(bitmap);
+}
+
+void TextureCache::clear() {
+    mCache.clear();
+}
+
+Texture* TextureCache::generateTexture(SkBitmap* bitmap) {
+    Texture* texture = new Texture;
+
+    texture->width = bitmap->width();
+    texture->height = bitmap->height();
+
+    glGenTextures(1, &texture->id);
+    glBindTexture(GL_TEXTURE_2D, texture->id);
+
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+    switch (bitmap->getConfig()) {
+    case SkBitmap::kRGB_565_Config:
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB565, texture->width, texture->height,
+                0, GL_RGB565, GL_UNSIGNED_SHORT_5_6_5, bitmap->getPixels());
+        break;
+    case SkBitmap::kARGB_8888_Config:
+        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->width, texture->height,
+                0, GL_RGBA, GL_UNSIGNED_BYTE, bitmap->getPixels());
+        break;
+    }
+
+    return texture;
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
new file mode 100644
index 0000000..42328f4
--- /dev/null
+++ b/libs/hwui/TextureCache.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 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_UI_TEXTURE_CACHE_H
+#define ANDROID_UI_TEXTURE_CACHE_H
+
+#include <SkBitmap.h>
+
+#include "Texture.h"
+#include "GenerationCache.h"
+
+namespace android {
+namespace uirenderer {
+
+class TextureCache: public OnEntryRemoved<SkBitmap*, Texture*> {
+public:
+    TextureCache(unsigned int maxEntries);
+    ~TextureCache();
+
+    void operator()(SkBitmap* key, Texture* value);
+
+    Texture* get(SkBitmap* bitmap);
+    Texture* remove(SkBitmap* bitmap);
+    void clear();
+
+private:
+    Texture* generateTexture(SkBitmap* bitmap);
+
+    GenerationCache<SkBitmap, Texture> mCache;
+}; // class TextureCache
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_UI_TEXTURE_CACHE_H