Add blend constant color and use it for lcd text common case (no fancy blend or shaded text)

Review URL: http://codereview.appspot.com/4274057/

git-svn-id: http://skia.googlecode.com/svn/trunk@941 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/gpu/include/GrDrawTarget.h b/gpu/include/GrDrawTarget.h
index aef5937..35f912b 100644
--- a/gpu/include/GrDrawTarget.h
+++ b/gpu/include/GrDrawTarget.h
@@ -136,6 +136,7 @@
         uint32_t                fFlagBits;
         GrBlendCoeff            fSrcBlend;
         GrBlendCoeff            fDstBlend;
+        GrColor                 fBlendConstant;
         GrTexture*              fTextures[kNumStages];
         GrSamplerState          fSamplerStates[kNumStages];
         GrRenderTarget*         fRenderTarget;
@@ -359,6 +360,24 @@
     void setBlendFunc(GrBlendCoeff srcCoef, GrBlendCoeff dstCoef);
 
     /**
+     * Sets the blending function constant referenced by the following blending
+     * coeffecients:
+     *      kConstC_BlendCoeff
+     *      kIConstC_BlendCoeff
+     *      kConstA_BlendCoeff
+     *      kIConstA_BlendCoeff
+     *
+     * @param constant the constant to set
+     */
+    void setBlendConstant(GrColor constant) { fCurrDrawState.fBlendConstant = constant; }
+
+    /**
+     * Retrieves the last value set by setBlendConstant()
+     * @return the blending constant value
+     */
+    GrColor getBlendConstant() const { return fCurrDrawState.fBlendConstant; }
+
+    /**
      * Used to save and restore the GrGpu's drawing state
      */
     struct SavedDrawState {
diff --git a/gpu/include/GrGLInterface.h b/gpu/include/GrGLInterface.h
index 0c2a2d9..0a41905 100644
--- a/gpu/include/GrGLInterface.h
+++ b/gpu/include/GrGLInterface.h
@@ -63,6 +63,7 @@
     typedef GLvoid (GR_GL_FUNCTION_TYPE *GrGLBindAttribLocationProc)(GLuint program, GLuint index, const char* name);
     typedef GLvoid (GR_GL_FUNCTION_TYPE *GrGLBindBufferProc)(GLenum target, GLuint buffer);
     typedef GLvoid (GR_GL_FUNCTION_TYPE *GrGLBindTextureProc)(GLenum target, GLuint texture);
+    typedef GLvoid (GR_GL_FUNCTION_TYPE *GrGLBlendColorProc)(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
     typedef GLvoid (GR_GL_FUNCTION_TYPE *GrGLBlendFuncProc)(GLenum sfactor, GLenum dfactor);
     typedef GLvoid (GR_GL_FUNCTION_TYPE *GrGLBufferDataProc)(GLenum target, GLsizei size, const void* data, GLenum usage);
     typedef GLvoid (GR_GL_FUNCTION_TYPE *GrGLBufferSubDataProc)(GLenum target, GLint offset, GLsizei size, const void* data);
@@ -167,6 +168,7 @@
     GrGLBindBufferProc fBindBuffer;
     GrGLBindTextureProc fBindTexture;
     GrGLBlendFuncProc fBlendFunc;
+    GrGLBlendColorProc fBlendColor;
     GrGLBufferDataProc fBufferData;
     GrGLBufferSubDataProc fBufferSubData;
     GrGLClearProc fClear;
diff --git a/gpu/include/GrGLPlatformIncludes.h b/gpu/include/GrGLPlatformIncludes.h
index 1a4fa40..978a992 100644
--- a/gpu/include/GrGLPlatformIncludes.h
+++ b/gpu/include/GrGLPlatformIncludes.h
@@ -335,6 +335,10 @@
 #define GL_MULTISAMPLE_BIT 0x20000000
 
 // OpenGL 1.4 Defines
+#define GL_CONSTANT_COLOR 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
+#define GL_CONSTANT_ALPHA 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
 #define GL_BLEND_DST_RGB 0x80C8
 #define GL_BLEND_SRC_RGB 0x80C9
 #define GL_BLEND_DST_ALPHA 0x80CA
diff --git a/gpu/include/GrTexture.h b/gpu/include/GrTexture.h
index 666aa57..0a65ff7 100644
--- a/gpu/include/GrTexture.h
+++ b/gpu/include/GrTexture.h
@@ -89,6 +89,7 @@
     };
     static size_t BytesPerPixel(PixelConfig);
     static bool PixelConfigIsOpaque(PixelConfig);
+    static bool PixelConfigIsAlphaOnly(PixelConfig);
 
 protected:
     GrTexture(int width,
diff --git a/gpu/include/GrTypes.h b/gpu/include/GrTypes.h
index 3c137f8..8e219f7 100644
--- a/gpu/include/GrTypes.h
+++ b/gpu/include/GrTypes.h
@@ -186,6 +186,12 @@
     kISA_BlendCoeff,     //<! one minus src alpha
     kDA_BlendCoeff,      //<! dst alpha
     kIDA_BlendCoeff,     //<! one minus dst alpha
+    kConstC_BlendCoeff,  //<! constant color
+    kIConstC_BlendCoeff, //<! one minus constant color
+    kConstA_BlendCoeff,  //<! constant color alpha
+    kIConstA_BlendCoeff, //<! one minus constant color alpha
+
+    kBlendCoeffCount
 };
 
 /**
diff --git a/gpu/src/GrGLInterface.cpp b/gpu/src/GrGLInterface.cpp
index f296be7..fa6aa92 100644
--- a/gpu/src/GrGLInterface.cpp
+++ b/gpu/src/GrGLInterface.cpp
@@ -281,6 +281,7 @@
     GR_GL_GET_PROC(BindAttribLocation);
     GR_GL_GET_PROC(BindBuffer);
     GR_GL_GET_PROC(BindTexture);
+    GR_GL_GET_PROC(BlendColor);
     GR_GL_GET_PROC(BufferData);
     GR_GL_GET_PROC(BufferSubData);
     GR_GL_GET_PROC(CompileShader);
diff --git a/gpu/src/GrGpu.cpp b/gpu/src/GrGpu.cpp
index d41005b..2d763e2 100644
--- a/gpu/src/GrGpu.cpp
+++ b/gpu/src/GrGpu.cpp
@@ -56,6 +56,14 @@
     }
 }
 
+bool GrTexture::PixelConfigIsAlphaOnly(PixelConfig config) {
+    switch (config) {
+        case GrTexture::kAlpha_8_PixelConfig:
+            return true;
+        default:
+            return false;
+    }
+}
 
 ////////////////////////////////////////////////////////////////////////////////
 
diff --git a/gpu/src/GrGpuGL.cpp b/gpu/src/GrGpuGL.cpp
index 94e9bfd..f2a2a8f 100644
--- a/gpu/src/GrGpuGL.cpp
+++ b/gpu/src/GrGpuGL.cpp
@@ -45,8 +45,50 @@
     GL_ONE_MINUS_SRC_ALPHA,
     GL_DST_ALPHA,
     GL_ONE_MINUS_DST_ALPHA,
+    GL_CONSTANT_COLOR,
+    GL_ONE_MINUS_CONSTANT_COLOR,
+    GL_CONSTANT_ALPHA,
+    GL_ONE_MINUS_CONSTANT_ALPHA,
 };
 
+bool GrGpuGL::BlendCoefReferencesConstant(GrBlendCoeff coeff) {
+    static const bool gCoeffReferencesBlendConst[] = {
+        false,
+        false,
+        false,
+        false,
+        false,
+        false,
+        false,
+        false,
+        false,
+        false,
+        true,
+        true,
+        true,
+        true,
+    };
+    return gCoeffReferencesBlendConst[coeff];
+    GR_STATIC_ASSERT(kBlendCoeffCount == GR_ARRAY_COUNT(gCoeffReferencesBlendConst));
+}
+
+GR_STATIC_ASSERT(0 == kZero_BlendCoeff);
+GR_STATIC_ASSERT(1 == kOne_BlendCoeff);
+GR_STATIC_ASSERT(2 == kSC_BlendCoeff);
+GR_STATIC_ASSERT(3 == kISC_BlendCoeff);
+GR_STATIC_ASSERT(4 == kDC_BlendCoeff);
+GR_STATIC_ASSERT(5 == kIDC_BlendCoeff);
+GR_STATIC_ASSERT(6 == kSA_BlendCoeff);
+GR_STATIC_ASSERT(7 == kISA_BlendCoeff);
+GR_STATIC_ASSERT(8 == kDA_BlendCoeff);
+GR_STATIC_ASSERT(9 == kIDA_BlendCoeff);
+GR_STATIC_ASSERT(10 == kConstC_BlendCoeff);
+GR_STATIC_ASSERT(11 == kIConstC_BlendCoeff);
+GR_STATIC_ASSERT(12 == kConstA_BlendCoeff);
+GR_STATIC_ASSERT(13 == kIConstA_BlendCoeff);
+
+GR_STATIC_ASSERT(kBlendCoeffCount == GR_ARRAY_COUNT(gXfermodeCoeff2Blend));
+
 ///////////////////////////////////////////////////////////////////////////////
 
 void GrGpuGL::AdjustTextureMatrix(const GrGLTexture* texture,
@@ -458,6 +500,10 @@
     // illegal values
     fHWDrawState.fSrcBlend = (GrBlendCoeff)-1;
     fHWDrawState.fDstBlend = (GrBlendCoeff)-1;
+
+    fHWDrawState.fBlendConstant = 0x00000000;
+    GR_GL(BlendColor(0,0,0,0));
+
     fHWDrawState.fColor = GrColor_ILLEGAL;
 
     fHWDrawState.fViewMatrix = GrMatrix::InvalidMatrix();
@@ -1615,6 +1661,19 @@
             fHWDrawState.fSrcBlend = fCurrDrawState.fSrcBlend;
             fHWDrawState.fDstBlend = fCurrDrawState.fDstBlend;
         }
+        if ((BlendCoefReferencesConstant(fCurrDrawState.fSrcBlend) ||
+             BlendCoefReferencesConstant(fCurrDrawState.fDstBlend)) &&
+            fHWDrawState.fBlendConstant != fCurrDrawState.fBlendConstant) {
+
+            float c[] = {
+                GrColorUnpackR(fCurrDrawState.fBlendConstant) / 255.f,
+                GrColorUnpackG(fCurrDrawState.fBlendConstant) / 255.f,
+                GrColorUnpackB(fCurrDrawState.fBlendConstant) / 255.f,
+                GrColorUnpackA(fCurrDrawState.fBlendConstant) / 255.f
+            };
+            GR_GL(BlendColor(c[0], c[1], c[2], c[3]));
+            fHWDrawState.fBlendConstant = fCurrDrawState.fBlendConstant;
+        }
     }
 
     if (fHWDrawState.fDrawFace != fCurrDrawState.fDrawFace) {
diff --git a/gpu/src/GrGpuGL.h b/gpu/src/GrGpuGL.h
index a731226..ea0c081 100644
--- a/gpu/src/GrGpuGL.h
+++ b/gpu/src/GrGpuGL.h
@@ -132,6 +132,8 @@
     static bool TextureMatrixIsIdentity(const GrGLTexture* texture,
                                         const GrSamplerState& sampler);
 
+    static bool BlendCoefReferencesConstant(GrBlendCoeff coeff);
+
 private:
     // notify callbacks to update state tracking when related
     // objects are bound to GL or deleted outside of the class
diff --git a/gpu/src/GrGpuGLFixed.cpp b/gpu/src/GrGpuGLFixed.cpp
index 695b22c..afd9bb6 100644
--- a/gpu/src/GrGpuGLFixed.cpp
+++ b/gpu/src/GrGpuGLFixed.cpp
@@ -137,6 +137,14 @@
         }
     }
 
+#if GR_SUPPORT_GLES1
+    if (BlendCoefReferencesConstant(fCurrDrawState.fSrcBlend) ||
+        BlendCoefReferencesConstant(fCurrDrawState.fDstBlend)) {
+        uimpl("ES1 doesn't support blend constant");
+        return false;
+    }
+#endif
+
     if (!flushGLStateCommon(type)) {
         return false;
     }
diff --git a/gpu/src/GrTextContext.cpp b/gpu/src/GrTextContext.cpp
index 6819bde..2230af2 100644
--- a/gpu/src/GrTextContext.cpp
+++ b/gpu/src/GrTextContext.cpp
@@ -46,6 +46,25 @@
         int nIndices = fCurrVertex + (fCurrVertex >> 1);
         GrAssert(fCurrTexture);
         fDrawTarget->setTexture(TEXT_STAGE, fCurrTexture);
+
+        if (!GrTexture::PixelConfigIsAlphaOnly(fCurrTexture->config())) {
+            if (kOne_BlendCoeff != fPaint.fSrcBlendCoeff ||
+                kISA_BlendCoeff != fPaint.fDstBlendCoeff ||
+                NULL != fPaint.getTexture()) {
+                GrPrintf("LCD Text will not draw correctly.\n");
+            }
+            // setup blend so that we get mask * paintColor + (1-mask)*dstColor
+            fDrawTarget->setBlendConstant(fPaint.fColor);
+            fDrawTarget->setBlendFunc(kConstC_BlendCoeff, kISC_BlendCoeff);
+            // don't modulate by the paint's color in the frag since we're
+            // already doing it via the blend const.
+            fDrawTarget->setColor(0xffffffff);
+        } else {
+            // set back to normal in case we took LCD path previously.
+            fDrawTarget->setBlendFunc(fPaint.fSrcBlendCoeff, fPaint.fDstBlendCoeff);
+            fDrawTarget->setColor(fPaint.fColor);
+        }
+
         fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
 
         fDrawTarget->drawIndexed(kTriangles_PrimitiveType,