Make table color filter use asNewCustomStage.

R=robertphillips@google.com
Review URL: https://codereview.appspot.com/6713051

git-svn-id: http://skia.googlecode.com/svn/trunk@5976 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/effects/SkTableColorFilter.cpp b/src/effects/SkTableColorFilter.cpp
index fcfb444..83049f2 100644
--- a/src/effects/SkTableColorFilter.cpp
+++ b/src/effects/SkTableColorFilter.cpp
@@ -38,7 +38,11 @@
         SkDELETE(fBitmap);
     }
 
-    virtual bool asComponentTable(SkBitmap* table) SK_OVERRIDE;
+    virtual bool asComponentTable(SkBitmap* table) const SK_OVERRIDE;
+
+#if SK_SUPPORT_GPU
+    virtual GrCustomStage* asNewCustomStage(GrContext* context) const SK_OVERRIDE;
+#endif
 
     virtual void filterSpan(const SkPMColor src[], int count,
                             SkPMColor dst[]) SK_OVERRIDE;
@@ -50,7 +54,7 @@
     virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
 
 private:
-    SkBitmap* fBitmap;
+    mutable const SkBitmap* fBitmap; // lazily allocated
 
     enum {
         kA_Flag = 1 << 0,
@@ -184,13 +188,13 @@
     SkASSERT(raw == count * 256);
 }
 
-bool SkTable_ColorFilter::asComponentTable(SkBitmap* table) {
+bool SkTable_ColorFilter::asComponentTable(SkBitmap* table) const {
     if (table) {
         if (NULL == fBitmap) {
-            fBitmap = SkNEW(SkBitmap);
-            fBitmap->setConfig(SkBitmap::kA8_Config, 256, 4, 256);
-            fBitmap->allocPixels();
-            uint8_t* bitmapPixels = fBitmap->getAddr8(0, 0);
+            SkBitmap* bmp = SkNEW(SkBitmap);
+            bmp->setConfig(SkBitmap::kA8_Config, 256, 4, 256);
+            bmp->allocPixels();
+            uint8_t* bitmapPixels = bmp->getAddr8(0, 0);
             int offset = 0;
             static const unsigned kFlags[] = { kA_Flag, kR_Flag, kG_Flag, kB_Flag };
 
@@ -203,12 +207,168 @@
                 }
                 bitmapPixels += 256;
             }
+            fBitmap = bmp;
         }
         *table = *fBitmap;
     }
     return true;
 }
 
+#if SK_SUPPORT_GPU
+
+#include "GrCustomStage.h"
+#include "gl/GrGLProgramStage.h"
+#include "SkGr.h"
+
+class GLColorTableEffect;
+
+class ColorTableEffect : public GrCustomStage {
+public:
+
+    explicit ColorTableEffect(GrTexture* texture);
+    virtual ~ColorTableEffect();
+
+    static const char* Name() { return "ColorTable"; }
+    virtual const GrProgramStageFactory& getFactory() const SK_OVERRIDE;
+    virtual bool isEqual(const GrCustomStage&) const SK_OVERRIDE;
+
+    virtual const GrTextureAccess& textureAccess(int index) const SK_OVERRIDE;
+
+    typedef GLColorTableEffect GLProgramStage;
+
+private:
+    GR_DECLARE_CUSTOM_STAGE_TEST;
+
+    GrTextureAccess fTextureAccess;
+
+    typedef GrCustomStage INHERITED;
+};
+
+class GLColorTableEffect : public GrGLProgramStage {
+public:
+    GLColorTableEffect(const GrProgramStageFactory& factory,
+                         const GrCustomStage& stage);
+
+    virtual void setupVariables(GrGLShaderBuilder* state) SK_OVERRIDE {}
+    virtual void emitVS(GrGLShaderBuilder* state,
+                        const char* vertexCoords) SK_OVERRIDE {}
+    virtual void emitFS(GrGLShaderBuilder* state,
+                        const char* outputColor,
+                        const char* inputColor,
+                        const TextureSamplerArray&) SK_OVERRIDE;
+
+    virtual void setData(const GrGLUniformManager&,
+                         const GrCustomStage&,
+                         const GrRenderTarget*,
+                         int stageNum) SK_OVERRIDE {}
+
+    static StageKey GenKey(const GrCustomStage&, const GrGLCaps&);
+
+private:
+
+    typedef GrGLProgramStage INHERITED;
+};
+
+GLColorTableEffect::GLColorTableEffect(
+    const GrProgramStageFactory& factory, const GrCustomStage& stage)
+    : INHERITED(factory) {
+ }
+
+void GLColorTableEffect::emitFS(GrGLShaderBuilder* builder,
+                                  const char* outputColor,
+                                  const char* inputColor,
+                                  const TextureSamplerArray& samplers) {
+    static const float kColorScaleFactor = 255.0f / 256.0f;
+    static const float kColorOffsetFactor = 1.0f / 512.0f;
+    SkString* code = &builder->fFSCode;
+    if (NULL == inputColor) {
+        // the input color is solid white (all ones).
+        static const float kMaxValue = kColorScaleFactor + kColorOffsetFactor;
+        code->appendf("\t\tvec4 coord = vec4(%f, %f, %f, %f);\n",
+                      kMaxValue, kMaxValue, kMaxValue, kMaxValue);
+
+    } else {
+        code->appendf("\t\tfloat nonZeroAlpha = max(%s.a, .0001);\n", inputColor);
+        code->appendf("\t\tvec4 coord = vec4(%s.rgb / nonZeroAlpha, nonZeroAlpha);\n", inputColor);
+        code->appendf("\t\tcoord = coord * %f + vec4(%f, %f, %f, %f);\n",
+                      kColorScaleFactor,
+                      kColorOffsetFactor, kColorOffsetFactor,
+                      kColorOffsetFactor, kColorOffsetFactor);
+    }
+
+    code->appendf("\t\t%s.a = ", outputColor);
+    builder->appendTextureLookup(code, samplers[0], "vec2(coord.a, 0.125)");
+    code->append(";\n");
+
+    code->appendf("\t\t%s.r = ", outputColor);
+    builder->appendTextureLookup(code, samplers[0], "vec2(coord.r, 0.375)");
+    code->append(";\n");
+
+    code->appendf("\t\t%s.g = ", outputColor);
+    builder->appendTextureLookup(code, samplers[0], "vec2(coord.g, 0.625)");
+    code->append(";\n");
+
+    code->appendf("\t\t%s.b = ", outputColor);
+    builder->appendTextureLookup(code, samplers[0], "vec2(coord.b, 0.875)");
+    code->append(";\n");
+
+    code->appendf("\t\t%s.rgb *= %s.a;\n", outputColor, outputColor);
+}
+
+GrGLProgramStage::StageKey GLColorTableEffect::GenKey(const GrCustomStage& s,
+                                                        const GrGLCaps& caps) {
+    return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+ColorTableEffect::ColorTableEffect(GrTexture* texture)
+    : INHERITED(1)
+    , fTextureAccess(texture, "a") {
+}
+
+ColorTableEffect::~ColorTableEffect() {
+}
+
+const GrProgramStageFactory&  ColorTableEffect::getFactory() const {
+    return GrTProgramStageFactory<ColorTableEffect>::getInstance();
+}
+
+bool ColorTableEffect::isEqual(const GrCustomStage& sBase) const {
+    return INHERITED::isEqual(sBase);
+}
+
+const GrTextureAccess& ColorTableEffect::textureAccess(int index) const {
+    GrAssert(0 == index);
+    return fTextureAccess;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+GR_DEFINE_CUSTOM_STAGE_TEST(ColorTableEffect);
+
+GrCustomStage* ColorTableEffect::TestCreate(SkRandom* random,
+                                              GrContext* context,
+                                              GrTexture* textures[]) {
+    return SkNEW_ARGS(ColorTableEffect, (textures[GrCustomStageUnitTest::kAlphaTextureIdx]));
+}
+
+GrCustomStage* SkTable_ColorFilter::asNewCustomStage(GrContext* context) const {
+    SkBitmap bitmap;
+    this->asComponentTable(&bitmap);
+    // passing NULL because this custom effect does no tiling or filtering.
+    GrTexture* texture = GrLockCachedBitmapTexture(context, bitmap, NULL);
+    GrCustomStage* stage = SkNEW_ARGS(ColorTableEffect, (texture));
+
+    // Unlock immediately, this is not great, but we don't have a way of
+    // knowing when else to unlock it currently. TODO: Remove this when
+    // unref becomes the unlock replacement for all types of textures.
+    GrUnlockCachedBitmapTexture(texture);
+    return stage;
+}
+
+#endif // SK_SUPPORT_GPU
+
 ///////////////////////////////////////////////////////////////////////////////
 
 #ifdef SK_CPU_BENDIAN