Merge "Optimize text GL setup" into jb-mr2-dev
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 009dcb9..26c7e5d 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -21,6 +21,7 @@
 
 #include <cutils/properties.h>
 
+#include <utils/Functor.h>
 #include <utils/Log.h>
 
 #include <RenderScript.h>
@@ -416,6 +417,8 @@
         CacheTexture* texture = mCacheTextures[i];
         if (texture->canDraw()) {
             if (first) {
+                if (mFunctor) (*mFunctor)(0, NULL);
+
                 checkTextureUpdate();
                 caches.bindIndicesBuffer(mIndexBufferID);
 
@@ -561,11 +564,12 @@
     return image;
 }
 
-void FontRenderer::initRender(const Rect* clip, Rect* bounds) {
+void FontRenderer::initRender(const Rect* clip, Rect* bounds, Functor* functor) {
     checkInit();
 
     mDrawn = false;
     mBounds = bounds;
+    mFunctor = functor;
     mClip = clip;
 }
 
@@ -583,13 +587,13 @@
 
 bool FontRenderer::renderPosText(SkPaint* paint, const Rect* clip, const char *text,
         uint32_t startIndex, uint32_t len, int numGlyphs, int x, int y,
-        const float* positions, Rect* bounds) {
+        const float* positions, Rect* bounds, Functor* functor) {
     if (!mCurrentFont) {
         ALOGE("No font set");
         return false;
     }
 
-    initRender(clip, bounds);
+    initRender(clip, bounds, functor);
     mCurrentFont->render(paint, text, startIndex, len, numGlyphs, x, y, positions);
     finishRender();
 
@@ -604,7 +608,7 @@
         return false;
     }
 
-    initRender(clip, bounds);
+    initRender(clip, bounds, NULL);
     mCurrentFont->render(paint, text, startIndex, len, numGlyphs, path, hOffset, vOffset);
     finishRender();
 
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 080cc71..1da3b6c 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -38,6 +38,8 @@
     class ScriptIntrinsicBlur;
 }
 
+class Functor;
+
 namespace android {
 namespace uirenderer {
 
@@ -62,7 +64,8 @@
 
     // bounds is an out parameter
     bool renderPosText(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex,
-            uint32_t len, int numGlyphs, int x, int y, const float* positions, Rect* bounds);
+            uint32_t len, int numGlyphs, int x, int y, const float* positions, Rect* bounds,
+            Functor* functor);
     // bounds is an out parameter
     bool renderTextOnPath(SkPaint* paint, const Rect* clip, const char *text, uint32_t startIndex,
             uint32_t len, int numGlyphs, SkPath* path, float hOffset, float vOffset, Rect* bounds);
@@ -88,13 +91,8 @@
     DropShadow renderDropShadow(SkPaint* paint, const char *text, uint32_t startIndex,
             uint32_t len, int numGlyphs, uint32_t radius, const float* positions);
 
-    GLuint getTexture(bool linearFiltering = false) {
-        checkInit();
-
-        mCurrentCacheTexture->setLinearFiltering(linearFiltering);
+    void setTextureFiltering(bool linearFiltering) {
         mLinearFiltering = linearFiltering;
-
-        return mCurrentCacheTexture->getTextureId();
     }
 
     uint32_t getCacheSize() const {
@@ -125,7 +123,7 @@
     void initVertexArrayBuffers();
 
     void checkInit();
-    void initRender(const Rect* clip, Rect* bounds);
+    void initRender(const Rect* clip, Rect* bounds, Functor* functor);
     void finishRender();
 
     void issueDrawCommand();
@@ -167,6 +165,7 @@
     uint32_t mMaxNumberOfQuads;
     uint32_t mIndexBufferID;
 
+    Functor* mFunctor;
     const Rect* mClip;
     Rect* mBounds;
     bool mDrawn;
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index a78a035..bc28d65 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -1752,7 +1752,7 @@
 }
 
 void OpenGLRenderer::setupDrawTexture(GLuint texture) {
-    bindTexture(texture);
+    if (texture) bindTexture(texture);
     mTextureUnit++;
     mCaches.enableTexCoordsVertexArray();
 }
@@ -2411,7 +2411,8 @@
 
 status_t OpenGLRenderer::drawRoundRect(float left, float top, float right, float bottom,
         float rx, float ry, SkPaint* p) {
-    if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p)) {
+    if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p) ||
+            (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
         return DrawGlInfo::kStatusDone;
     }
 
@@ -2436,7 +2437,8 @@
 
 status_t OpenGLRenderer::drawCircle(float x, float y, float radius, SkPaint* p) {
     if (mSnapshot->isIgnored() || quickRejectPreStroke(x - radius, y - radius,
-            x + radius, y + radius, p)) {
+            x + radius, y + radius, p) ||
+            (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
         return DrawGlInfo::kStatusDone;
     }
     if (p->getPathEffect() != 0) {
@@ -2456,7 +2458,8 @@
 
 status_t OpenGLRenderer::drawOval(float left, float top, float right, float bottom,
         SkPaint* p) {
-    if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p)) {
+    if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p) ||
+            (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
         return DrawGlInfo::kStatusDone;
     }
 
@@ -2477,7 +2480,8 @@
 
 status_t OpenGLRenderer::drawArc(float left, float top, float right, float bottom,
         float startAngle, float sweepAngle, bool useCenter, SkPaint* p) {
-    if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p)) {
+    if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p) ||
+            (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
         return DrawGlInfo::kStatusDone;
     }
 
@@ -2513,7 +2517,8 @@
 #define SkPaintDefaults_MiterLimit SkIntToScalar(4)
 
 status_t OpenGLRenderer::drawRect(float left, float top, float right, float bottom, SkPaint* p) {
-    if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p)) {
+    if (mSnapshot->isIgnored() || quickRejectPreStroke(left, top, right, bottom, p) ||
+            (p->getAlpha() == 0 && getXfermode(p->getXfermode()) != SkXfermode::kClear_Mode)) {
         return DrawGlInfo::kStatusDone;
     }
 
@@ -2589,6 +2594,48 @@
     return alpha == 0.0f && getXfermode(paint->getXfermode()) == SkXfermode::kSrcOver_Mode;
 }
 
+class TextSetupFunctor: public Functor {
+public:
+    TextSetupFunctor(OpenGLRenderer& renderer, float x, float y, bool pureTranslate,
+            int alpha, SkXfermode::Mode mode, SkPaint* paint): Functor(),
+            renderer(renderer), x(x), y(y), pureTranslate(pureTranslate),
+            alpha(alpha), mode(mode), paint(paint) {
+    }
+    ~TextSetupFunctor() { }
+
+    status_t operator ()(int what, void* data) {
+        renderer.setupDraw();
+        renderer.setupDrawTextGamma(paint);
+        renderer.setupDrawDirtyRegionsDisabled();
+        renderer.setupDrawWithTexture(true);
+        renderer.setupDrawAlpha8Color(paint->getColor(), alpha);
+        renderer.setupDrawColorFilter();
+        renderer.setupDrawShader();
+        renderer.setupDrawBlending(true, mode);
+        renderer.setupDrawProgram();
+        renderer.setupDrawModelView(x, y, x, y, pureTranslate, true);
+        // Calling setupDrawTexture with the name 0 will enable the
+        // uv attributes and increase the texture unit count
+        // texture binding will be performed by the font renderer as
+        // needed
+        renderer.setupDrawTexture(0);
+        renderer.setupDrawPureColorUniforms();
+        renderer.setupDrawColorFilterUniforms();
+        renderer.setupDrawShaderUniforms(pureTranslate);
+        renderer.setupDrawTextGammaUniforms();
+
+        return NO_ERROR;
+    }
+
+    OpenGLRenderer& renderer;
+    float x;
+    float y;
+    bool pureTranslate;
+    int alpha;
+    SkXfermode::Mode mode;
+    SkPaint* paint;
+};
+
 status_t OpenGLRenderer::drawPosText(const char* text, int bytesCount, int count,
         const float* positions, SkPaint* paint) {
     if (text == NULL || count == 0 || mSnapshot->isIgnored() || canSkipText(paint)) {
@@ -2625,31 +2672,16 @@
     if (pureTranslate && !linearFilter) {
         linearFilter = fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f;
     }
-
-    mCaches.activeTexture(0);
-    setupDraw();
-    setupDrawTextGamma(paint);
-    setupDrawDirtyRegionsDisabled();
-    setupDrawWithTexture(true);
-    setupDrawAlpha8Color(paint->getColor(), alpha);
-    setupDrawColorFilter();
-    setupDrawShader();
-    setupDrawBlending(true, mode);
-    setupDrawProgram();
-    setupDrawModelView(x, y, x, y, pureTranslate, true);
-    setupDrawTexture(fontRenderer.getTexture(linearFilter));
-    setupDrawPureColorUniforms();
-    setupDrawColorFilterUniforms();
-    setupDrawShaderUniforms(pureTranslate);
-    setupDrawTextGammaUniforms();
+    fontRenderer.setTextureFiltering(linearFilter);
 
     const Rect* clip = pureTranslate ? mSnapshot->clipRect : &mSnapshot->getLocalClip();
     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
     const bool hasActiveLayer = hasLayer();
 
+    TextSetupFunctor functor(*this, x, y, pureTranslate, alpha, mode, paint);
     if (fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
-            positions, hasActiveLayer ? &bounds : NULL)) {
+            positions, hasActiveLayer ? &bounds : NULL, &functor)) {
         if (hasActiveLayer) {
             if (!pureTranslate) {
                 currentTransform().mapRect(bounds);
@@ -2742,40 +2774,22 @@
 
     // Pick the appropriate texture filtering
     bool linearFilter = !pureTranslate || fabs(y - (int) y) > 0.0f || fabs(x - (int) x) > 0.0f;
-
-    // The font renderer will always use texture unit 0
-    mCaches.activeTexture(0);
-    setupDraw();
-    setupDrawTextGamma(paint);
-    setupDrawDirtyRegionsDisabled();
-    setupDrawWithTexture(true);
-    setupDrawAlpha8Color(paint->getColor(), alpha);
-    setupDrawColorFilter();
-    setupDrawShader();
-    setupDrawBlending(true, mode);
-    setupDrawProgram();
-    setupDrawModelView(x, y, x, y, pureTranslate, true);
-    // See comment above; the font renderer must use texture unit 0
-    // assert(mTextureUnit == 0)
-    setupDrawTexture(fontRenderer.getTexture(linearFilter));
-    setupDrawPureColorUniforms();
-    setupDrawColorFilterUniforms();
-    setupDrawShaderUniforms(pureTranslate);
-    setupDrawTextGammaUniforms();
+    fontRenderer.setTextureFiltering(linearFilter);
 
     // TODO: Implement better clipping for scaled/rotated text
     const Rect* clip = !pureTranslate ? NULL : mSnapshot->clipRect;
     Rect bounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
 
     bool status;
+    TextSetupFunctor functor(*this, x, y, pureTranslate, alpha, mode, paint);
     if (CC_UNLIKELY(paint->getTextAlign() != SkPaint::kLeft_Align)) {
         SkPaint paintCopy(*paint);
         paintCopy.setTextAlign(SkPaint::kLeft_Align);
         status = fontRenderer.renderPosText(&paintCopy, clip, text, 0, bytesCount, count, x, y,
-                positions, hasActiveLayer ? &bounds : NULL);
+                positions, hasActiveLayer ? &bounds : NULL, &functor);
     } else {
         status = fontRenderer.renderPosText(paint, clip, text, 0, bytesCount, count, x, y,
-                positions, hasActiveLayer ? &bounds : NULL);
+                positions, hasActiveLayer ? &bounds : NULL, &functor);
     }
 
     if (status && hasActiveLayer) {
@@ -2798,12 +2812,12 @@
 
     FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
     fontRenderer.setFont(paint, mat4::identity());
+    fontRenderer.setTextureFiltering(true);
 
     int alpha;
     SkXfermode::Mode mode;
     getAlphaAndMode(paint, &alpha, &mode);
 
-    mCaches.activeTexture(0);
     setupDraw();
     setupDrawTextGamma(paint);
     setupDrawDirtyRegionsDisabled();
@@ -2814,7 +2828,11 @@
     setupDrawBlending(true, mode);
     setupDrawProgram();
     setupDrawModelView(0.0f, 0.0f, 0.0f, 0.0f, false, true);
-    setupDrawTexture(fontRenderer.getTexture(true));
+    // Calling setupDrawTexture with the name 0 will enable the
+    // uv attributes and increase the texture unit count
+    // texture binding will be performed by the font renderer as
+    // needed
+    setupDrawTexture(0);
     setupDrawPureColorUniforms();
     setupDrawColorFilterUniforms();
     setupDrawShaderUniforms(false);
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 01fcfc6..71bd6bb 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -85,6 +85,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 class DisplayList;
+class TextSetupFunctor;
 class VertexBuffer;
 
 /**
@@ -995,6 +996,7 @@
     String8 mName;
 
     friend class DisplayListRenderer;
+    friend class TextSetupFunctor;
 
 }; // class OpenGLRenderer