Add debug mode to measure performance.

Change-Id: I9d4c84034dc200b99c8266165942a7cdbcb5c0c5
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 3a85bc1..cd57ab2 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -30,6 +30,7 @@
 #include <SkTemplates.h>
 #include <SkXfermode.h>
 
+#include <OpenGLDebugRenderer.h>
 #include <OpenGLRenderer.h>
 #include <SkiaShader.h>
 #include <SkiaColorFilter.h>
@@ -48,6 +49,8 @@
  */
 #ifdef USE_OPENGL_RENDERER
 
+#define DEBUG_RENDERER 0
+
 // ----------------------------------------------------------------------------
 // Java APIs
 // ----------------------------------------------------------------------------
@@ -62,7 +65,11 @@
 // ----------------------------------------------------------------------------
 
 static OpenGLRenderer* android_view_GLES20Canvas_createRenderer(JNIEnv* env, jobject canvas) {
+#if DEBUG_RENDERER
+    return new OpenGLDebugRenderer;
+#else
     return new OpenGLRenderer;
+#endif
 }
 
 static void android_view_GLES20Canvas_destroyRenderer(JNIEnv* env, jobject canvas,
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 0469508..e8ffd99 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -5,11 +5,13 @@
 # defined in the current device/board configuration
 ifeq ($(USE_OPENGL_RENDERER),true)
 	LOCAL_SRC_FILES:= \
+		FboCache.cpp \
 		FontRenderer.cpp \
 		GammaFontRenderer.cpp \
 		GradientCache.cpp \
 		LayerCache.cpp \
 		Matrix.cpp \
+		OpenGLDebugRenderer.cpp \
 		OpenGLRenderer.cpp \
 		Patch.cpp \
 		PatchCache.cpp \
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 5ef66f3..a4933c0 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -31,6 +31,7 @@
 #include "ProgramCache.h"
 #include "PathCache.h"
 #include "TextDropShadowCache.h"
+#include "FboCache.h"
 #include "Line.h"
 
 namespace android {
@@ -65,6 +66,7 @@
     PatchCache patchCache;
     TextDropShadowCache dropShadowCache;
     GammaFontRenderer fontRenderer;
+    FboCache fboCache;
 
     Line line;
 }; // class Caches
diff --git a/libs/hwui/FboCache.cpp b/libs/hwui/FboCache.cpp
new file mode 100644
index 0000000..77fbda2
--- /dev/null
+++ b/libs/hwui/FboCache.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include "FboCache.h"
+#include "Properties.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Constructors/destructor
+///////////////////////////////////////////////////////////////////////////////
+
+FboCache::FboCache(): mMaxSize(DEFAULT_FBO_CACHE_SIZE) {
+    char property[PROPERTY_VALUE_MAX];
+    if (property_get(PROPERTY_FBO_CACHE_SIZE, property, NULL) > 0) {
+        LOGD("  Setting fbo cache size to %s", property);
+        mMaxSize = atoi(property);
+    } else {
+        LOGD("  Using default fbo cache size of %d", DEFAULT_FBO_CACHE_SIZE);
+    }
+}
+
+FboCache::~FboCache() {
+    clear();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Size management
+///////////////////////////////////////////////////////////////////////////////
+
+uint32_t FboCache::getSize() {
+    return mCache.size();
+}
+
+uint32_t FboCache::getMaxSize() {
+    return mMaxSize;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Caching
+///////////////////////////////////////////////////////////////////////////////
+
+void FboCache::clear() {
+
+}
+
+GLuint FboCache::get() {
+    return 0;
+}
+
+bool FboCache::put(GLuint fbo) {
+    return false;
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/FboCache.h b/libs/hwui/FboCache.h
new file mode 100644
index 0000000..66f66ea
--- /dev/null
+++ b/libs/hwui/FboCache.h
@@ -0,0 +1,81 @@
+/*
+ * 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_FBO_CACHE_H
+#define ANDROID_UI_FBO_CACHE_H
+
+#include <GLES2/gl2.h>
+
+#include <utils/SortedVector.h>
+
+#include "GenerationCache.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Cache
+///////////////////////////////////////////////////////////////////////////////
+
+class FboCache {
+public:
+    FboCache();
+    ~FboCache();
+
+    /**
+     * Returns an FBO from the cache. If no FBO is available, a new one
+     * is created. If creating a new FBO fails, 0 is returned.
+     *
+     * When an FBO is obtained from the cache, it is removed and the
+     * total number of FBOs available in the cache decreases.
+     *
+     * @return The name of the FBO, or 0 if no FBO can be obtained.
+     */
+    GLuint get();
+
+    /**
+     * Adds the specified FBO to the cache.
+     *
+     * @param fbo The FBO to add to the cache.
+     *
+     * @return True if the FBO was added, false otherwise.
+     */
+    bool put(GLuint fbo);
+
+    /**
+     * Clears the cache. This causes all FBOs to be deleted.
+     */
+    void clear();
+
+    /**
+     * Returns the current size of the cache.
+     */
+    uint32_t getSize();
+
+    /**
+     * Returns the maximum number of FBOs that the cache can hold.
+     */
+    uint32_t getMaxSize();
+
+private:
+    SortedVector<GLuint> mCache;
+    uint32_t mMaxSize;
+}; // class FboCache
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_UI_FBO_CACHE_H
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 2959814..b66696d 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -19,6 +19,7 @@
 #include <SkUtils.h>
 
 #include <cutils/properties.h>
+
 #include <utils/Log.h>
 
 #include "FontRenderer.h"
diff --git a/libs/hwui/OpenGLDebugRenderer.cpp b/libs/hwui/OpenGLDebugRenderer.cpp
new file mode 100644
index 0000000..f5a4286
--- /dev/null
+++ b/libs/hwui/OpenGLDebugRenderer.cpp
@@ -0,0 +1,114 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "OpenGLRenderer"
+
+#include <utils/StopWatch.h>
+
+#include "OpenGLDebugRenderer.h"
+
+namespace android {
+namespace uirenderer {
+
+void OpenGLDebugRenderer::prepare() {
+    mPrimitivesCount = 0;
+    LOGD("========= Frame start =========");
+    OpenGLRenderer::prepare();
+}
+
+void OpenGLDebugRenderer::finish() {
+    LOGD("========= Frame end =========");
+    LOGD("Primitives draw count = %d", mPrimitivesCount);
+    OpenGLRenderer::finish();
+}
+
+void OpenGLDebugRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
+    mPrimitivesCount++;
+    StopWatch w("composeLayer");
+    return OpenGLRenderer::composeLayer(current, previous);
+}
+
+int OpenGLDebugRenderer::saveLayer(float left, float top, float right, float bottom,
+        const SkPaint* p, int flags) {
+    mPrimitivesCount++;
+    StopWatch w("saveLayer");
+    return OpenGLRenderer::saveLayer(left, top, right, bottom, p, flags);
+}
+
+void OpenGLDebugRenderer::drawBitmap(SkBitmap* bitmap, float left, float top,
+        const SkPaint* paint) {
+    mPrimitivesCount++;
+    StopWatch w("drawBitmap");
+    OpenGLRenderer::drawBitmap(bitmap, left, top, paint);
+}
+
+void OpenGLDebugRenderer::drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix,
+        const SkPaint* paint) {
+    mPrimitivesCount++;
+    StopWatch w("drawBitmapMatrix");
+    OpenGLRenderer::drawBitmap(bitmap, matrix, paint);
+}
+
+void OpenGLDebugRenderer::drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
+        float srcRight, float srcBottom, float dstLeft, float dstTop,
+        float dstRight, float dstBottom, const SkPaint* paint) {
+    mPrimitivesCount++;
+    StopWatch w("drawBitmapRect");
+    OpenGLRenderer::drawBitmap(bitmap, srcLeft, srcTop, srcRight, srcBottom,
+            dstLeft, dstTop, dstRight, dstBottom, paint);
+}
+
+void OpenGLDebugRenderer::drawPatch(SkBitmap* bitmap, Res_png_9patch* patch,
+        float left, float top, float right, float bottom, const SkPaint* paint) {
+    mPrimitivesCount++;
+    StopWatch w("drawPatch");
+    OpenGLRenderer::drawPatch(bitmap, patch, left, top, right, bottom, paint);
+}
+
+void OpenGLDebugRenderer::drawColor(int color, SkXfermode::Mode mode) {
+    mPrimitivesCount++;
+    StopWatch w("drawColor");
+    OpenGLRenderer::drawColor(color, mode);
+}
+
+void OpenGLDebugRenderer::drawRect(float left, float top, float right, float bottom,
+        const SkPaint* paint) {
+    mPrimitivesCount++;
+    StopWatch w("drawRect");
+    OpenGLRenderer::drawRect(left, top, right, bottom, paint);
+}
+
+void OpenGLDebugRenderer::drawPath(SkPath* path, SkPaint* paint) {
+    mPrimitivesCount++;
+    StopWatch w("drawPath");
+    OpenGLRenderer::drawPath(path, paint);
+}
+
+void OpenGLDebugRenderer::drawLines(float* points, int count, const SkPaint* paint) {
+    mPrimitivesCount++;
+    StopWatch w("drawLines");
+    OpenGLRenderer::drawLines(points, count, paint);
+}
+
+void OpenGLDebugRenderer::drawText(const char* text, int bytesCount, int count, float x, float y,
+        SkPaint* paint) {
+    mPrimitivesCount++;
+    StopWatch w("drawText");
+    OpenGLRenderer::drawText(text, bytesCount, count, x, y, paint);
+}
+
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/OpenGLDebugRenderer.h b/libs/hwui/OpenGLDebugRenderer.h
new file mode 100644
index 0000000..37fac93
--- /dev/null
+++ b/libs/hwui/OpenGLDebugRenderer.h
@@ -0,0 +1,68 @@
+/*
+ * 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_OPENGL_DEBUG_RENDERER_H
+#define ANDROID_UI_OPENGL_DEBUG_RENDERER_H
+
+#include "OpenGLRenderer.h"
+
+namespace android {
+namespace uirenderer {
+
+///////////////////////////////////////////////////////////////////////////////
+// Renderer
+///////////////////////////////////////////////////////////////////////////////
+
+class OpenGLDebugRenderer: public OpenGLRenderer {
+public:
+    OpenGLDebugRenderer(): mPrimitivesCount(0) {
+    }
+
+    ~OpenGLDebugRenderer() {
+    }
+
+    void prepare();
+    void finish();
+
+    int saveLayer(float left, float top, float right, float bottom,
+            const SkPaint* p, int flags);
+
+    void drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint);
+    void drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint);
+    void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
+            float srcRight, float srcBottom, float dstLeft, float dstTop,
+            float dstRight, float dstBottom, const SkPaint* paint);
+    void drawPatch(SkBitmap* bitmap, Res_png_9patch* patch, float left, float top,
+            float right, float bottom, const SkPaint* paint);
+    void drawColor(int color, SkXfermode::Mode mode);
+    void drawRect(float left, float top, float right, float bottom, const SkPaint* paint);
+    void drawPath(SkPath* path, SkPaint* paint);
+    void drawLines(float* points, int count, const SkPaint* paint);
+    void drawText(const char* text, int bytesCount, int count, float x, float y,
+            SkPaint* paint);
+
+protected:
+    void composeLayer(sp<Snapshot> current, sp<Snapshot> previous);
+
+private:
+    uint32_t mPrimitivesCount;
+
+}; // class OpenGLDebugRenderer
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif // ANDROID_UI_OPENGL_DEBUG_RENDERER_H
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index e032085..dbd499e 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -24,6 +24,7 @@
 #include <SkTypeface.h>
 
 #include <utils/Log.h>
+#include <utils/StopWatch.h>
 
 #include "OpenGLRenderer.h"
 
@@ -710,6 +711,7 @@
     if (text == NULL || count == 0 || (paint->getAlpha() == 0 && paint->getXfermode() == NULL)) {
         return;
     }
+
     paint->setAntiAlias(true);
 
     float length = -1.0f;
@@ -739,6 +741,7 @@
     FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(paint);
     fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()),
             paint->getTextSize());
+
     if (mHasShadow) {
         glActiveTexture(gTextureUnits[0]);
         mCaches.dropShadowCache.setFontRenderer(fontRenderer);
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index f903505..af2a70b 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -62,11 +62,13 @@
 class OpenGLRenderer {
 public:
     OpenGLRenderer();
-    ~OpenGLRenderer();
+    virtual ~OpenGLRenderer();
 
     void setViewport(int width, int height);
-    void prepare();
-    void finish();
+
+    virtual void prepare();
+    virtual void finish();
+
     void acquireContext();
     void releaseContext();
 
@@ -75,8 +77,10 @@
     void restore();
     void restoreToCount(int saveCount);
 
-    int saveLayer(float left, float top, float right, float bottom, const SkPaint* p, int flags);
-    int saveLayerAlpha(float left, float top, float right, float bottom, int alpha, int flags);
+    virtual int saveLayer(float left, float top, float right, float bottom,
+            const SkPaint* p, int flags);
+    virtual int saveLayerAlpha(float left, float top, float right, float bottom,
+            int alpha, int flags);
 
     void translate(float dx, float dy);
     void rotate(float degrees);
@@ -90,16 +94,19 @@
     bool quickReject(float left, float top, float right, float bottom);
     bool clipRect(float left, float top, float right, float bottom, SkRegion::Op op);
 
-    void drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint);
-    void drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint);
-    void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop, float srcRight, float srcBottom,
-            float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint);
-    void drawPatch(SkBitmap* bitmap, Res_png_9patch* patch, float left, float top,
+    virtual void drawBitmap(SkBitmap* bitmap, float left, float top, const SkPaint* paint);
+    virtual void drawBitmap(SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint);
+    virtual void drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
+            float srcRight, float srcBottom, float dstLeft, float dstTop,
+            float dstRight, float dstBottom, const SkPaint* paint);
+    virtual void drawPatch(SkBitmap* bitmap, Res_png_9patch* patch, float left, float top,
             float right, float bottom, const SkPaint* paint);
-    void drawColor(int color, SkXfermode::Mode mode);
-    void drawRect(float left, float top, float right, float bottom, const SkPaint* paint);
-    void drawPath(SkPath* path, SkPaint* paint);
-    void drawLines(float* points, int count, const SkPaint* paint);
+    virtual void drawColor(int color, SkXfermode::Mode mode);
+    virtual void drawRect(float left, float top, float right, float bottom, const SkPaint* paint);
+    virtual void drawPath(SkPath* path, SkPaint* paint);
+    virtual void drawLines(float* points, int count, const SkPaint* paint);
+    virtual void drawText(const char* text, int bytesCount, int count, float x, float y,
+            SkPaint* paint);
 
     void resetShader();
     void setupShader(SkiaShader* shader);
@@ -110,7 +117,17 @@
     void resetShadow();
     void setupShadow(float radius, float dx, float dy, int color);
 
-    void drawText(const char* text, int bytesCount, int count, float x, float y, SkPaint* paint);
+protected:
+    /**
+     * Compose the layer defined in the current snapshot with the layer
+     * defined by the previous snapshot.
+     *
+     * The current snapshot *must* be a layer (flag kFlagIsLayer set.)
+     *
+     * @param curent The current snapshot containing the layer to compose
+     * @param previous The previous snapshot to compose the current layer with
+     */
+    virtual void composeLayer(sp<Snapshot> current, sp<Snapshot> previous);
 
 private:
     /**
@@ -138,17 +155,6 @@
     void setScissorFromClip();
 
     /**
-     * Compose the layer defined in the current snapshot with the layer
-     * defined by the previous snapshot.
-     *
-     * The current snapshot *must* be a layer (flag kFlagIsLayer set.)
-     *
-     * @param curent The current snapshot containing the layer to compose
-     * @param previous The previous snapshot to compose the current layer with
-     */
-    void composeLayer(sp<Snapshot> current, sp<Snapshot> previous);
-
-    /**
      * Creates a new layer stored in the specified snapshot.
      *
      * @param snapshot The snapshot associated with the new layer
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 4e2f091..d573805 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -30,6 +30,7 @@
 #define PROPERTY_GRADIENT_CACHE_SIZE "ro.hwui.gradient_cache_size"
 #define PROPERTY_PATH_CACHE_SIZE "ro.hwui.path_cache_size"
 #define PROPERTY_DROP_SHADOW_CACHE_SIZE "ro.hwui.drop_shadow_cache_size"
+#define PROPERTY_FBO_CACHE_SIZE "ro.hwui.fbo_cache_size"
 
 // These properties are defined in pixels
 #define PROPERTY_TEXT_CACHE_WIDTH "ro.hwui.text_cache_width"
@@ -43,12 +44,13 @@
 // Converts a number of mega-bytes into bytes
 #define MB(s) s * 1024 * 1024
 
-#define DEFAULT_TEXTURE_CACHE_SIZE 20.0f
-#define DEFAULT_LAYER_CACHE_SIZE 6.0f
-#define DEFAULT_PATH_CACHE_SIZE 6.0f
+#define DEFAULT_TEXTURE_CACHE_SIZE 18.0f
+#define DEFAULT_LAYER_CACHE_SIZE 4.0f
+#define DEFAULT_PATH_CACHE_SIZE 5.0f
 #define DEFAULT_PATCH_CACHE_SIZE 100
 #define DEFAULT_GRADIENT_CACHE_SIZE 0.5f
 #define DEFAULT_DROP_SHADOW_CACHE_SIZE 2.0f
+#define DEFAULT_FBO_CACHE_SIZE 25
 
 #define DEFAULT_TEXT_GAMMA 1.4f
 #define DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD 64