Add a new method for text gamma correction

To select the gamma correction method, adb shell setprop hwui.text_gamma_correction
with one of the following values:

lookup3
lookup
shader3
shader

See Properties.h for more information about these different methods.
You can also control gamma correction using the following properties:

hwui.text_gamma
hwui.text_gamma.black_threshold
hwui.text_gamma.white_threshold

Change-Id: I47970b804d2c590c37d3da5008db094241579e25
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index 7d150bb..6795ac3 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -65,9 +65,6 @@
 // Turn on to enable additional debugging in the font renderers
 #define DEBUG_FONT_RENDERER 0
 
-// Force gamma correction in shaders
-#define DEBUG_FONT_RENDERER_FORCE_SHADER_GAMMA 0
-
 // Turn on to dump display list state
 #define DEBUG_DISPLAY_LIST 0
 
diff --git a/libs/hwui/GammaFontRenderer.cpp b/libs/hwui/GammaFontRenderer.cpp
index 226f4bc..fe532abc 100644
--- a/libs/hwui/GammaFontRenderer.cpp
+++ b/libs/hwui/GammaFontRenderer.cpp
@@ -43,16 +43,16 @@
     // 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();
+        if (!strcasecmp(property, "shader")) {
+            return new ShaderGammaFontRenderer(false);
+        } else if (!strcasecmp(property, "shader3")) {
+            return new ShaderGammaFontRenderer(true);
+        } else if (!strcasecmp(property, "lookup")) {
+            return new LookupGammaFontRenderer();
         }
     }
 
-#if DEBUG_FONT_RENDERER_FORCE_SHADER_GAMMA
-    return new ShaderGammaFontRenderer();
-#else
-    return new LookupGammaFontRenderer();
-#endif
+    return new Lookup3GammaFontRenderer();
 }
 
 GammaFontRenderer::GammaFontRenderer() {
@@ -96,20 +96,26 @@
 // Shader-based renderer
 ///////////////////////////////////////////////////////////////////////////////
 
-ShaderGammaFontRenderer::ShaderGammaFontRenderer(): GammaFontRenderer() {
+ShaderGammaFontRenderer::ShaderGammaFontRenderer(bool multiGamma): GammaFontRenderer() {
     INIT_LOGD("Creating shader gamma font renderer");
     mRenderer = NULL;
+    mMultiGamma = multiGamma;
 }
 
 void ShaderGammaFontRenderer::describe(ProgramDescription& description,
         const SkPaint* paint) const {
     if (paint->getShader() == NULL) {
-        const int l = luminance(paint);
+        if (mMultiGamma) {
+            const int l = luminance(paint);
 
-        if (l <= mBlackThreshold) {
-            description.hasGammaCorrection = true;
-            description.gamma = mGamma;
-        } else if (l >= mWhiteThreshold) {
+            if (l <= mBlackThreshold) {
+                description.hasGammaCorrection = true;
+                description.gamma = mGamma;
+            } else if (l >= mWhiteThreshold) {
+                description.hasGammaCorrection = true;
+                description.gamma = 1.0f / mGamma;
+            }
+        } else {
             description.hasGammaCorrection = true;
             description.gamma = 1.0f / mGamma;
         }
@@ -131,16 +137,32 @@
     INIT_LOGD("Creating lookup gamma font renderer");
 
     // Compute the gamma tables
+    const float gamma = 1.0f / mGamma;
+
+    for (uint32_t i = 0; i <= 255; i++) {
+        mGammaTable[i] = uint8_t((float)::floor(pow(i / 255.0f, gamma) * 255.0f + 0.5f));
+    }
+
+    mRenderer = NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Lookup-based renderer, using 3 different correction tables
+///////////////////////////////////////////////////////////////////////////////
+
+Lookup3GammaFontRenderer::Lookup3GammaFontRenderer(): GammaFontRenderer() {
+    INIT_LOGD("Creating lookup3 gamma font renderer");
+
+    // Compute the gamma tables
     const float blackGamma = mGamma;
     const float whiteGamma = 1.0f / mGamma;
 
     for (uint32_t i = 0; i <= 255; i++) {
-        mGammaTable[i] = i;
-
         const float v = i / 255.0f;
         const float black = pow(v, blackGamma);
         const float white = pow(v, whiteGamma);
 
+        mGammaTable[i] = i;
         mGammaTable[256 + i] = uint8_t((float)::floor(black * 255.0f + 0.5f));
         mGammaTable[512 + i] = uint8_t((float)::floor(white * 255.0f + 0.5f));
     }
@@ -149,20 +171,20 @@
     memset(mRenderersUsageCount, 0, sizeof(uint32_t) * kGammaCount);
 }
 
-LookupGammaFontRenderer::~LookupGammaFontRenderer() {
+Lookup3GammaFontRenderer::~Lookup3GammaFontRenderer() {
     for (int i = 0; i < kGammaCount; i++) {
         delete mRenderers[i];
     }
 }
 
-void LookupGammaFontRenderer::clear() {
+void Lookup3GammaFontRenderer::clear() {
     for (int i = 0; i < kGammaCount; i++) {
         delete mRenderers[i];
         mRenderers[i] = NULL;
     }
 }
 
-void LookupGammaFontRenderer::flush() {
+void Lookup3GammaFontRenderer::flush() {
     int count = 0;
     int min = -1;
     uint32_t minCount = UINT_MAX;
@@ -190,7 +212,7 @@
     }
 }
 
-FontRenderer* LookupGammaFontRenderer::getRenderer(Gamma gamma) {
+FontRenderer* Lookup3GammaFontRenderer::getRenderer(Gamma gamma) {
     FontRenderer* renderer = mRenderers[gamma];
     if (!renderer) {
         renderer = new FontRenderer();
@@ -201,7 +223,7 @@
     return renderer;
 }
 
-FontRenderer& LookupGammaFontRenderer::getFontRenderer(const SkPaint* paint) {
+FontRenderer& Lookup3GammaFontRenderer::getFontRenderer(const SkPaint* paint) {
     if (paint->getShader() == NULL) {
         const int l = luminance(paint);
 
diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h
index 8e1db78..9180778 100644
--- a/libs/hwui/GammaFontRenderer.h
+++ b/libs/hwui/GammaFontRenderer.h
@@ -79,23 +79,71 @@
     }
 
     uint32_t getFontRendererSize(uint32_t fontRenderer) const {
-        return mRenderer->getCacheSize();
+        return mRenderer ? mRenderer->getCacheSize() : 0;
     }
 
     void describe(ProgramDescription& description, const SkPaint* paint) const;
     void setupProgram(ProgramDescription& description, Program* program) const;
 
 private:
-    ShaderGammaFontRenderer();
+    ShaderGammaFontRenderer(bool multiGamma);
 
     FontRenderer* mRenderer;
+    bool mMultiGamma;
 
     friend class GammaFontRenderer;
 };
 
 class LookupGammaFontRenderer: public GammaFontRenderer {
 public:
-    ~LookupGammaFontRenderer();
+    ~LookupGammaFontRenderer() {
+        delete mRenderer;
+    }
+
+    void clear() {
+        delete mRenderer;
+    }
+
+    void flush() {
+        if (mRenderer) {
+            mRenderer->flushLargeCaches();
+        }
+    }
+
+    FontRenderer& getFontRenderer(const SkPaint* paint) {
+        if (!mRenderer) {
+            mRenderer = new FontRenderer;
+            mRenderer->setGammaTable(&mGammaTable[0]);
+        }
+        return *mRenderer;
+    }
+
+    uint32_t getFontRendererCount() const {
+        return 1;
+    }
+
+    uint32_t getFontRendererSize(uint32_t fontRenderer) const {
+        return mRenderer ? mRenderer->getCacheSize() : 0;
+    }
+
+    void describe(ProgramDescription& description, const SkPaint* paint) const {
+    }
+
+    void setupProgram(ProgramDescription& description, Program* program) const {
+    }
+
+private:
+    LookupGammaFontRenderer();
+
+    FontRenderer* mRenderer;
+    uint8_t mGammaTable[256];
+
+    friend class GammaFontRenderer;
+};
+
+class Lookup3GammaFontRenderer: public GammaFontRenderer {
+public:
+    ~Lookup3GammaFontRenderer();
 
     void clear();
     void flush();
@@ -122,7 +170,7 @@
     }
 
 private:
-    LookupGammaFontRenderer();
+    Lookup3GammaFontRenderer();
 
     enum Gamma {
         kGammaDefault = 0,
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 4a12e39..447b1d0 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -74,13 +74,28 @@
 #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"
+// or in lookup tables. Accepted values:
+//
+//     - "lookup3", correction based on lookup tables. Gamma correction
+//        is different for black and white text (see thresholds below)
+//
+//     - "lookup", correction based on a single lookup table
+//
+//     - "shader3", correction applied by a GLSL shader. Gamma correction
+//        is different for black and white text (see thresholds below)
+//
+//     - "shader", correction applied by a GLSL shader
+//
+// See PROPERTY_TEXT_GAMMA, PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD and
+// PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD for more control.
+#define PROPERTY_TEXT_GAMMA_SHADER "hwui.text_gamma_correction"
 
 // Gamma (>= 1.0, <= 10.0)
-#define PROPERTY_TEXT_GAMMA "ro.text_gamma"
-#define PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD "ro.text_gamma.black_threshold"
-#define PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD "ro.text_gamma.white_threshold"
+#define PROPERTY_TEXT_GAMMA "hwui.text_gamma"
+// Luminance threshold below which black gamma correction is applied. Range: [0..255]
+#define PROPERTY_TEXT_BLACK_GAMMA_THRESHOLD "hwui.text_gamma.black_threshold"
+// Lumincance threshold above which white gamma correction is applied. Range: [0..255]
+#define PROPERTY_TEXT_WHITE_GAMMA_THRESHOLD "hwui.text_gamma.white_threshold"
 
 // Converts a number of mega-bytes into bytes
 #define MB(s) s * 1024 * 1024