Refactor GammaFontRenderer

This change is the first step to a shader-based text antialias
gamma correction.

Change-Id: I9eb02d4c56cb95d05219f712290c865b46141954
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 214cc92..56eb317 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -49,6 +49,7 @@
 
 Caches::Caches(): Singleton<Caches>(), mInitialized(false) {
     init();
+    initFont();
     initExtensions();
     initConstraints();
 
@@ -74,6 +75,7 @@
 
     mTexCoordsArrayEnabled = false;
 
+    glDisable(GL_SCISSOR_TEST);
     scissorEnabled = false;
     mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
 
@@ -90,6 +92,10 @@
     mInitialized = true;
 }
 
+void Caches::initFont() {
+    fontRenderer = GammaFontRenderer::createRenderer();
+}
+
 void Caches::initExtensions() {
     if (extensions.hasDebugMarker()) {
         eventMark = glInsertEventMarkerEXT;
@@ -170,8 +176,8 @@
             arcShapeCache.getSize(), arcShapeCache.getMaxSize());
     log.appendFormat("  TextDropShadowCache  %8d / %8d\n", dropShadowCache.getSize(),
             dropShadowCache.getMaxSize());
-    for (uint32_t i = 0; i < fontRenderer.getFontRendererCount(); i++) {
-        const uint32_t size = fontRenderer.getFontRendererSize(i);
+    for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
+        const uint32_t size = fontRenderer->getFontRendererSize(i);
         log.appendFormat("  FontRenderer %d       %8d / %8d\n", i, size, size);
     }
     log.appendFormat("Other:\n");
@@ -191,8 +197,8 @@
     total += ovalShapeCache.getSize();
     total += rectShapeCache.getSize();
     total += arcShapeCache.getSize();
-    for (uint32_t i = 0; i < fontRenderer.getFontRendererCount(); i++) {
-        total += fontRenderer.getFontRendererSize(i);
+    for (uint32_t i = 0; i < fontRenderer->getFontRendererCount(); i++) {
+        total += fontRenderer->getFontRendererSize(i);
     }
 
     log.appendFormat("Total memory usage:\n");
@@ -245,10 +251,10 @@
             patchCache.clear();
             dropShadowCache.clear();
             gradientCache.clear();
-            fontRenderer.clear();
+            fontRenderer->clear();
             // fall through
         case kFlushMode_Moderate:
-            fontRenderer.flush();
+            fontRenderer->flush();
             textureCache.flush();
             pathCache.clear();
             roundRectShapeCache.clear();
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index f83e291..5e09d94 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -249,9 +249,10 @@
     PatchCache patchCache;
     TextDropShadowCache dropShadowCache;
     FboCache fboCache;
-    GammaFontRenderer fontRenderer;
     ResourceCache resourceCache;
 
+    GammaFontRenderer* fontRenderer;
+
     // Debug methods
     PFNGLINSERTEVENTMARKEREXTPROC eventMark;
     PFNGLPUSHGROUPMARKEREXTPROC startMark;
@@ -261,6 +262,7 @@
     PFNGLGETOBJECTLABELEXTPROC getLabel;
 
 private:
+    void initFont();
     void initExtensions();
     void initConstraints();
 
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 0d6e62a..3b3691c 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -677,10 +677,19 @@
     unsigned int stride = glyph.rowBytes();
 
     uint32_t cacheX = 0, bX = 0, cacheY = 0, bY = 0;
-    for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
-        for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) {
-            uint8_t tempCol = bitmapBuffer[bY * stride + bX];
-            cacheBuffer[cacheY * cacheWidth + cacheX] = mGammaTable[tempCol];
+    if (mGammaTable) {
+        for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
+            for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) {
+                uint8_t tempCol = bitmapBuffer[bY * stride + bX];
+                cacheBuffer[cacheY * cacheWidth + cacheX] = mGammaTable[tempCol];
+            }
+        }
+    } else {
+        for (cacheX = startX, bX = 0; cacheX < endX; cacheX++, bX++) {
+            for (cacheY = startY, bY = 0; cacheY < endY; cacheY++, bY++) {
+                uint8_t tempCol = bitmapBuffer[bY * stride + bX];
+                cacheBuffer[cacheY * cacheWidth + cacheX] = tempCol;
+            }
         }
     }
 
diff --git a/libs/hwui/GammaFontRenderer.cpp b/libs/hwui/GammaFontRenderer.cpp
index 1be957f..75d5b10 100644
--- a/libs/hwui/GammaFontRenderer.cpp
+++ b/libs/hwui/GammaFontRenderer.cpp
@@ -24,20 +24,30 @@
 namespace uirenderer {
 
 ///////////////////////////////////////////////////////////////////////////////
-// Constructors/destructor
+// Base class GammaFontRenderer
 ///////////////////////////////////////////////////////////////////////////////
 
-GammaFontRenderer::GammaFontRenderer() {
-    INIT_LOGD("Creating gamma font renderer");
+GammaFontRenderer* GammaFontRenderer::createRenderer() {
+    // Choose the best renderer
+    char property[PROPERTY_VALUE_MAX];
+    if (property_get(PROPERTY_TEXT_GAMMA_SHADER, property, DEFAULT_TEXT_GAMMA_SHADER) > 0) {
+        if (!strcasecmp(property, "true")) {
+            return new ShaderGammaFontRenderer();
+        }
+    }
 
+    return new LookupGammaFontRenderer();
+}
+
+GammaFontRenderer::GammaFontRenderer() {
     // Get the renderer properties
     char property[PROPERTY_VALUE_MAX];
 
     // Get the gamma
-    float gamma = DEFAULT_TEXT_GAMMA;
+    mGamma = DEFAULT_TEXT_GAMMA;
     if (property_get(PROPERTY_TEXT_GAMMA, property, NULL) > 0) {
         INIT_LOGD("  Setting text gamma to %s", property);
-        gamma = atof(property);
+        mGamma = atof(property);
     } else {
         INIT_LOGD("  Using default text gamma of %.2f", DEFAULT_TEXT_GAMMA);
     }
@@ -61,10 +71,29 @@
         INIT_LOGD("  Using default white black gamma threshold of %d",
                 DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD);
     }
+}
+
+GammaFontRenderer::~GammaFontRenderer() {
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Shader-based renderer
+///////////////////////////////////////////////////////////////////////////////
+
+ShaderGammaFontRenderer::ShaderGammaFontRenderer(): GammaFontRenderer() {
+    INIT_LOGD("Creating shader gamma font renderer");
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Lookup-based renderer
+///////////////////////////////////////////////////////////////////////////////
+
+LookupGammaFontRenderer::LookupGammaFontRenderer(): GammaFontRenderer() {
+    INIT_LOGD("Creating lookup gamma font renderer");
 
     // Compute the gamma tables
-    const float blackGamma = gamma;
-    const float whiteGamma = 1.0f / gamma;
+    const float blackGamma = mGamma;
+    const float whiteGamma = 1.0f / mGamma;
 
     for (uint32_t i = 0; i <= 255; i++) {
         mGammaTable[i] = i;
@@ -81,20 +110,20 @@
     memset(mRenderersUsageCount, 0, sizeof(uint32_t) * kGammaCount);
 }
 
-GammaFontRenderer::~GammaFontRenderer() {
+LookupGammaFontRenderer::~LookupGammaFontRenderer() {
     for (int i = 0; i < kGammaCount; i++) {
         delete mRenderers[i];
     }
 }
 
-void GammaFontRenderer::clear() {
+void LookupGammaFontRenderer::clear() {
     for (int i = 0; i < kGammaCount; i++) {
         delete mRenderers[i];
         mRenderers[i] = NULL;
     }
 }
 
-void GammaFontRenderer::flush() {
+void LookupGammaFontRenderer::flush() {
     int count = 0;
     int min = -1;
     uint32_t minCount = UINT_MAX;
@@ -122,7 +151,7 @@
     }
 }
 
-FontRenderer* GammaFontRenderer::getRenderer(Gamma gamma) {
+FontRenderer* LookupGammaFontRenderer::getRenderer(Gamma gamma) {
     FontRenderer* renderer = mRenderers[gamma];
     if (!renderer) {
         renderer = new FontRenderer();
@@ -133,7 +162,7 @@
     return renderer;
 }
 
-FontRenderer& GammaFontRenderer::getFontRenderer(const SkPaint* paint) {
+FontRenderer& LookupGammaFontRenderer::getFontRenderer(const SkPaint* paint) {
     if (paint->getShader() == NULL) {
         uint32_t c = paint->getColor();
         const int r = (c >> 16) & 0xFF;
diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h
index 99f08f0..988947a 100644
--- a/libs/hwui/GammaFontRenderer.h
+++ b/libs/hwui/GammaFontRenderer.h
@@ -24,16 +24,72 @@
 namespace android {
 namespace uirenderer {
 
-struct GammaFontRenderer {
-    GammaFontRenderer();
-    ~GammaFontRenderer();
+class GammaFontRenderer {
+public:
+    virtual ~GammaFontRenderer();
 
-    enum Gamma {
-        kGammaDefault = 0,
-        kGammaBlack = 1,
-        kGammaWhite = 2,
-        kGammaCount = 3
-    };
+    virtual void clear() = 0;
+    virtual void flush() = 0;
+
+    virtual FontRenderer& getFontRenderer(const SkPaint* paint) = 0;
+
+    virtual uint32_t getFontRendererCount() const = 0;
+
+    virtual uint32_t getFontRendererSize(uint32_t fontRenderer) const = 0;
+
+    static GammaFontRenderer* createRenderer();
+
+protected:
+    GammaFontRenderer();
+
+    int mBlackThreshold;
+    int mWhiteThreshold;
+
+    float mGamma;
+};
+
+class ShaderGammaFontRenderer: public GammaFontRenderer {
+public:
+    ~ShaderGammaFontRenderer() {
+        delete mRenderer;
+    }
+
+    void clear() {
+        delete mRenderer;
+    }
+
+    void flush() {
+        if (mRenderer) {
+            mRenderer->flushLargeCaches();
+        }
+    }
+
+    FontRenderer& getFontRenderer(const SkPaint* paint) {
+        if (!mRenderer) {
+            mRenderer = new FontRenderer;
+        }
+        return *mRenderer;
+    }
+
+    uint32_t getFontRendererCount() const {
+        return 1;
+    }
+
+    uint32_t getFontRendererSize(uint32_t fontRenderer) const {
+        return mRenderer->getCacheSize();
+    }
+
+private:
+    ShaderGammaFontRenderer();
+
+    FontRenderer* mRenderer;
+
+    friend class GammaFontRenderer;
+};
+
+class LookupGammaFontRenderer: public GammaFontRenderer {
+public:
+    ~LookupGammaFontRenderer();
 
     void clear();
     void flush();
@@ -54,15 +110,23 @@
     }
 
 private:
+    LookupGammaFontRenderer();
+
+    enum Gamma {
+        kGammaDefault = 0,
+        kGammaBlack = 1,
+        kGammaWhite = 2,
+        kGammaCount = 3
+    };
+
     FontRenderer* getRenderer(Gamma gamma);
 
     uint32_t mRenderersUsageCount[kGammaCount];
     FontRenderer* mRenderers[kGammaCount];
 
-    int mBlackThreshold;
-    int mWhiteThreshold;
-
     uint8_t mGammaTable[256 * kGammaCount];
+
+    friend class GammaFontRenderer;
 };
 
 }; // namespace uirenderer
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index cbf7b02..ca798db 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -2277,7 +2277,7 @@
         y = (int) floorf(y + mSnapshot->transform->getTranslateY() + 0.5f);
     }
 
-    FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(paint);
+    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
     fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()),
             paint->getTextSize());
 
@@ -2367,7 +2367,7 @@
     ALOGD("OpenGLRenderer drawText() with FontID=%d", SkTypeface::UniqueID(paint->getTypeface()));
 #endif
 
-    FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(paint);
+    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
     fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()),
             paint->getTextSize());
 
@@ -2466,7 +2466,7 @@
         return DrawGlInfo::kStatusDone;
     }
 
-    FontRenderer& fontRenderer = mCaches.fontRenderer.getFontRenderer(paint);
+    FontRenderer& fontRenderer = mCaches.fontRenderer->getFontRenderer(paint);
     fontRenderer.setFont(paint, SkTypeface::UniqueID(paint->getTypeface()),
             paint->getTextSize());
 
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index c0311fb..4a12e39 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -73,6 +73,10 @@
 #define PROPERTY_TEXT_CACHE_WIDTH "ro.hwui.text_cache_width"
 #define PROPERTY_TEXT_CACHE_HEIGHT "ro.hwui.text_cache_height"
 
+// Indicates whether gamma correction should be applied in the shaders
+// or in lookup tables. Accepted values: true, false
+#define PROPERTY_TEXT_GAMMA_SHADER "ro.hwui.text_gamma_shader"
+
 // Gamma (>= 1.0, <= 10.0)
 #define PROPERTY_TEXT_GAMMA "ro.text_gamma"
 #define PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD "ro.text_gamma.black_threshold"
@@ -92,6 +96,8 @@
 
 #define DEFAULT_TEXTURE_CACHE_FLUSH_RATE 0.6f
 
+#define DEFAULT_TEXT_GAMMA_SHADER "false"
+
 #define DEFAULT_TEXT_GAMMA 1.4f
 #define DEFAULT_TEXT_BLACK_GAMMA_THRESHOLD 64
 #define DEFAULT_TEXT_WHITE_GAMMA_THRESHOLD 192