Create xfer processor backend.

This includes:
-Having an actual XP stage at the end of the gl pipeline.
-All Blending work is handled by XP until actually setting GL blend states
-GLPrograms test to test XP

BUG=skia:

Committed: https://skia.googlesource.com/skia/+/4dffc940c430eec66d4707490eace19c9b3f7904

Review URL: https://codereview.chromium.org/764643004
diff --git a/src/gpu/gl/GrGLProcessor.h b/src/gpu/gl/GrGLProcessor.h
index 6dccd33..a4fad75 100644
--- a/src/gpu/gl/GrGLProcessor.h
+++ b/src/gpu/gl/GrGLProcessor.h
@@ -117,14 +117,4 @@
     typedef GrGLProcessor INHERITED;
 };
 
-class GrGLXferProcessor : public GrGLFragmentProcessor {
-public:
-    GrGLXferProcessor() {}
-    
-    virtual ~GrGLXferProcessor() {}
-
-private:
-    typedef GrGLFragmentProcessor INHERITED;
-};
-
 #endif
diff --git a/src/gpu/gl/GrGLProgram.cpp b/src/gpu/gl/GrGLProgram.cpp
index 29c44ac..da687c1 100644
--- a/src/gpu/gl/GrGLProgram.cpp
+++ b/src/gpu/gl/GrGLProgram.cpp
@@ -12,11 +12,13 @@
 #include "GrCoordTransform.h"
 #include "GrGLGeometryProcessor.h"
 #include "GrGLProcessor.h"
+#include "GrGLXferProcessor.h"
 #include "GrGpuGL.h"
 #include "GrGLPathRendering.h"
 #include "GrGLShaderVar.h"
 #include "GrGLSL.h"
 #include "GrOptDrawState.h"
+#include "GrXferProcessor.h"
 #include "SkXfermode.h"
 
 #define GL_CALL(X) GR_GL_CALL(fGpu->glInterface(), X)
@@ -57,6 +59,7 @@
                          GrGLuint programID,
                          const UniformInfoArray& uniforms,
                          GrGLInstalledGeoProc* geometryProcessor,
+                         GrGLInstalledXferProc* xferProcessor,
                          GrGLInstalledFragProcs* fragmentProcessors)
     : fColor(GrColor_ILLEGAL)
     , fCoverage(0)
@@ -64,6 +67,7 @@
     , fBuiltinUniformHandles(builtinUniforms)
     , fProgramID(programID)
     , fGeometryProcessor(geometryProcessor)
+    , fXferProcessor(xferProcessor)
     , fFragmentProcessors(SkRef(fragmentProcessors))
     , fDesc(desc)
     , fGpu(gpu)
@@ -91,6 +95,9 @@
     if (fGeometryProcessor.get()) {
         this->initSamplers(fGeometryProcessor.get(), &texUnitIdx);
     }
+    if (fXferProcessor.get()) {
+        this->initSamplers(fXferProcessor.get(), &texUnitIdx);
+    }
     int numProcs = fFragmentProcessors->fProcs.count();
     for (int i = 0; i < numProcs; i++) {
         this->initSamplers(fFragmentProcessors->fProcs[i], &texUnitIdx);
@@ -162,6 +169,11 @@
         fGeometryProcessor->fGLProc->setData(fProgramDataManager, gp, bt);
         this->bindTextures(fGeometryProcessor, gp);
     }
+    if (fXferProcessor.get()) {
+        const GrXferProcessor& xp = *optState.getXferProcessor();
+        fXferProcessor->fGLProc->setData(fProgramDataManager, xp);
+        this->bindTextures(fXferProcessor, xp);
+    }
     this->setFragmentData(optState);
 
     // Some of GrGLProgram subclasses need to update state here
@@ -284,8 +296,10 @@
                                          const BuiltinUniformHandles& builtinUniforms,
                                          GrGLuint programID,
                                          const UniformInfoArray& uniforms,
+                                         GrGLInstalledXferProc* xferProcessor,
                                          GrGLInstalledFragProcs* fragmentProcessors)
-    : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, NULL, fragmentProcessors) {
+    : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, NULL,
+                xferProcessor, fragmentProcessors) {
 }
 
 void GrGLNvprProgramBase::onSetMatrixAndRenderTargetHeight(const GrOptDrawState& optState) {
@@ -303,9 +317,11 @@
                                  const BuiltinUniformHandles& builtinUniforms,
                                  GrGLuint programID,
                                  const UniformInfoArray& uniforms,
+                                 GrGLInstalledXferProc* xferProcessor,
                                  GrGLInstalledFragProcs* fragmentProcessors,
                                  const SeparableVaryingInfoArray& separableVaryings)
-    : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, fragmentProcessors) {
+    : INHERITED(gpu, desc, builtinUniforms, programID, uniforms,
+                xferProcessor, fragmentProcessors) {
     int count = separableVaryings.count();
     fVaryings.push_back_n(count);
     for (int i = 0; i < count; i++) {
@@ -353,9 +369,10 @@
                                              const BuiltinUniformHandles& builtinUniforms,
                                              GrGLuint programID,
                                              const UniformInfoArray& uniforms,
+                                             GrGLInstalledXferProc* xp,
                                              GrGLInstalledFragProcs* fps,
                                              int texCoordSetCnt)
-    : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, fps)
+    : INHERITED(gpu, desc, builtinUniforms, programID, uniforms, xp, fps)
     , fTexCoordSetCnt(texCoordSetCnt) {
 }
 
diff --git a/src/gpu/gl/GrGLProgram.h b/src/gpu/gl/GrGLProgram.h
index 36bf860..ea8be85 100644
--- a/src/gpu/gl/GrGLProgram.h
+++ b/src/gpu/gl/GrGLProgram.h
@@ -141,6 +141,7 @@
                 GrGLuint programID,
                 const UniformInfoArray&,
                 GrGLInstalledGeoProc* geometryProcessor,
+                GrGLInstalledXferProc* xferProcessor,
                 GrGLInstalledFragProcs* fragmentProcessors);
 
     // Sets the texture units for samplers.
@@ -180,6 +181,7 @@
 
     // the installed effects
     SkAutoTDelete<GrGLInstalledGeoProc> fGeometryProcessor;
+    SkAutoTDelete<GrGLInstalledXferProc> fXferProcessor;
     SkAutoTUnref<GrGLInstalledFragProcs> fFragmentProcessors;
 
     GrProgramDesc fDesc;
@@ -205,6 +207,7 @@
                         const BuiltinUniformHandles&,
                         GrGLuint programID,
                         const UniformInfoArray&,
+                        GrGLInstalledXferProc* xferProcessor,
                         GrGLInstalledFragProcs* fragmentProcessors);
     virtual void onSetMatrixAndRenderTargetHeight(const GrOptDrawState&);
 
@@ -223,6 +226,7 @@
                     const BuiltinUniformHandles&,
                     GrGLuint programID,
                     const UniformInfoArray&,
+                    GrGLInstalledXferProc* xferProcessor,
                     GrGLInstalledFragProcs* fragmentProcessors,
                     const SeparableVaryingInfoArray& separableVaryings);
     virtual void didSetData(GrGpu::DrawType) SK_OVERRIDE;
@@ -252,7 +256,8 @@
                           const BuiltinUniformHandles&,
                           GrGLuint programID,
                           const UniformInfoArray&,
-                          GrGLInstalledFragProcs* fragmentProcessors,
+                          GrGLInstalledXferProc* xp,
+                          GrGLInstalledFragProcs* fps,
                           int texCoordSetCnt);
     virtual void didSetData(GrGpu::DrawType) SK_OVERRIDE;
     virtual void setTransformData(const GrPendingFragmentStage&,
diff --git a/src/gpu/gl/GrGLProgramDesc.cpp b/src/gpu/gl/GrGLProgramDesc.cpp
index 068386c..2476c55 100644
--- a/src/gpu/gl/GrGLProgramDesc.cpp
+++ b/src/gpu/gl/GrGLProgramDesc.cpp
@@ -189,13 +189,21 @@
         const GrFragmentProcessor& fp = *fps.getProcessor();
         GrProcessorKeyBuilder b(&desc->fKey);
         fp.getGLProcessorKey(gpu->glCaps(), &b);
-        if (!get_meta_key(*fps.getProcessor(), gpu->glCaps(),
-                         gen_transform_key(fps, requiresLocalCoordAttrib), 0, &b)) {
+        if (!get_meta_key(fp, gpu->glCaps(),
+                          gen_transform_key(fps, requiresLocalCoordAttrib), 0, &b)) {
             desc->fKey.reset();
             return false;
         }
     }
 
+    const GrXferProcessor& xp = *optState.getXferProcessor();
+    GrProcessorKeyBuilder b(&desc->fKey);
+    xp.getGLProcessorKey(gpu->glCaps(), &b);
+    if (!get_meta_key(xp, gpu->glCaps(), 0, 0, &b)) {
+        desc->fKey.reset();
+        return false;
+    }
+
     // --------DO NOT MOVE HEADER ABOVE THIS LINE--------------------------------------------------
     // Because header is a pointer into the dynamic array, we can't push any new data into the key
     // below here.
@@ -260,9 +268,6 @@
         header->fFragPosKey = 0;
     }
 
-    header->fPrimaryOutputType = descInfo.fPrimaryOutputType;
-    header->fSecondaryOutputType = descInfo.fSecondaryOutputType;
-
     header->fColorEffectCnt = optState.numColorStages();
     header->fCoverageEffectCnt = optState.numCoverageStages();
     desc->finalize();
diff --git a/src/gpu/gl/GrGLXferProcessor.h b/src/gpu/gl/GrGLXferProcessor.h
new file mode 100644
index 0000000..5c92559
--- /dev/null
+++ b/src/gpu/gl/GrGLXferProcessor.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrGLXferProcessor_DEFINED
+#define GrGLXferProcessor_DEFINED
+
+#include "GrGLProcessor.h"
+
+class GrGLXPBuilder;
+
+class GrGLXferProcessor {
+public:
+    GrGLXferProcessor() {}
+    virtual ~GrGLXferProcessor() {}
+
+    typedef GrGLProcessor::TextureSamplerArray TextureSamplerArray;
+    struct EmitArgs {
+        EmitArgs(GrGLXPBuilder* pb,
+                 const GrXferProcessor& xp,
+                 const char* inputColor,
+                 const char* inputCoverage,
+                 const char* outputPrimary,
+                 const char* outputSecondary,
+                 const TextureSamplerArray& samplers)
+            : fPB(pb)
+            , fXP(xp)
+            , fInputColor(inputColor)
+            , fInputCoverage(inputCoverage)
+            , fOutputPrimary(outputPrimary)
+            , fOutputSecondary(outputSecondary)
+            , fSamplers(samplers) {}
+
+        GrGLXPBuilder* fPB;
+        const GrXferProcessor& fXP;
+        const char* fInputColor;
+        const char* fInputCoverage;
+        const char* fOutputPrimary;
+        const char* fOutputSecondary;
+        const TextureSamplerArray& fSamplers;
+    };
+    /**
+     * This is similar to emitCode() in the base class, except it takes a full shader builder.
+     * This allows the effect subclass to emit vertex code.
+     */
+    virtual void emitCode(const EmitArgs&) = 0;
+
+    /** A GrGLXferProcessor instance can be reused with any GrGLXferProcessor that produces
+        the same stage key; this function reads data from a GrGLXferProcessor and uploads any
+        uniform variables required  by the shaders created in emitCode(). The GrXferProcessor
+        parameter is guaranteed to be of the same type that created this GrGLXferProcessor and
+        to have an identical processor key as the one that created this GrGLXferProcessor.  */
+    virtual void setData(const GrGLProgramDataManager&,
+                         const GrXferProcessor&) = 0;
+private:
+    typedef GrGLProcessor INHERITED;
+};
+#endif
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index c899eba..7db6abd 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -1919,10 +1919,14 @@
     }
 }
 
-void GrGpuGL::flushBlend(const GrOptDrawState& optState, bool isLines,
-                         GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff) {
+void GrGpuGL::flushBlend(const GrOptDrawState& optState) {
     // Any optimization to disable blending should have already been applied and
     // tweaked the coeffs to (1, 0).
+    
+    GrXferProcessor::BlendInfo blendInfo;
+    optState.getXferProcessor()->getBlendInfo(&blendInfo);
+    GrBlendCoeff srcCoeff = blendInfo.fSrcBlend;
+    GrBlendCoeff dstCoeff = blendInfo.fDstBlend;
     bool blendOff = kOne_GrBlendCoeff == srcCoeff && kZero_GrBlendCoeff == dstCoeff;
     if (blendOff) {
         if (kNo_TriState != fHWBlendState.fEnabled) {
@@ -1941,7 +1945,7 @@
             fHWBlendState.fSrcCoeff = srcCoeff;
             fHWBlendState.fDstCoeff = dstCoeff;
         }
-        GrColor blendConst = optState.getBlendConstant();
+        GrColor blendConst = blendInfo.fBlendConstant;
         if ((BlendCoeffReferencesConstant(srcCoeff) ||
              BlendCoeffReferencesConstant(dstCoeff)) &&
             (!fHWBlendState.fConstColorValid ||
diff --git a/src/gpu/gl/GrGpuGL.h b/src/gpu/gl/GrGpuGL.h
index 8a60988..76995b9 100644
--- a/src/gpu/gl/GrGpuGL.h
+++ b/src/gpu/gl/GrGpuGL.h
@@ -172,11 +172,7 @@
                        size_t* indexOffsetInBytes);
 
     // Subclasses should call this to flush the blend state.
-    // The params should be the final coefficients to apply
-    // (after any blending optimizations or dual source blending considerations
-    // have been accounted for).
-    void flushBlend(const GrOptDrawState& optState, bool isLines,
-                    GrBlendCoeff srcCoeff, GrBlendCoeff dstCoeff);
+    void flushBlend(const GrOptDrawState& optState);
 
     bool hasExtension(const char* ext) const { return fGLContext.hasExtension(ext); }
 
diff --git a/src/gpu/gl/GrGpuGL_program.cpp b/src/gpu/gl/GrGpuGL_program.cpp
index a808aa8..19ddc76 100644
--- a/src/gpu/gl/GrGpuGL_program.cpp
+++ b/src/gpu/gl/GrGpuGL_program.cpp
@@ -213,9 +213,6 @@
     } else {
         this->flushMiscFixedFunctionState(optState);
 
-        GrBlendCoeff srcCoeff = optState.getSrcBlendCoeff();
-        GrBlendCoeff dstCoeff = optState.getDstBlendCoeff();
-
         fCurrentProgram.reset(fProgramCache->getProgram(optState));
         if (NULL == fCurrentProgram.get()) {
             SkDEBUGFAIL("Failed to create program!");
@@ -230,7 +227,7 @@
             fHWProgramID = programID;
         }
 
-        this->flushBlend(optState, kDrawLines_DrawType == optState.drawType(), srcCoeff, dstCoeff);
+        this->flushBlend(optState);
 
         fCurrentProgram->setData(optState);
     }
diff --git a/src/gpu/gl/builders/GrGLFragmentShaderBuilder.cpp b/src/gpu/gl/builders/GrGLFragmentShaderBuilder.cpp
index 49be12d..b6daca7 100644
--- a/src/gpu/gl/builders/GrGLFragmentShaderBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLFragmentShaderBuilder.cpp
@@ -256,55 +256,6 @@
     return dual_source_output_name();
 }
 
-void GrGLFragmentShaderBuilder::enableSecondaryOutput(const GrGLSLExpr4& inputColor,
-                                                      const GrGLSLExpr4& inputCoverage) {
-    this->enableSecondaryOutput();
-    const char* secondaryOutputName = this->getSecondaryColorOutputName();
-    GrGLSLExpr4 coeff(1);
-    switch (fProgramBuilder->header().fSecondaryOutputType) {
-        case GrProgramDesc::kCoverage_SecondaryOutputType:
-            break;
-        case GrProgramDesc::kCoverageISA_SecondaryOutputType:
-            // Get (1-A) into coeff
-            coeff = GrGLSLExpr4::VectorCast(GrGLSLExpr1(1) - inputColor.a());
-            break;
-        case GrProgramDesc::kCoverageISC_SecondaryOutputType:
-            // Get (1-RGBA) into coeff
-            coeff = GrGLSLExpr4(1) - inputColor;
-            break;
-        default:
-            SkFAIL("Unexpected Secondary Output");
-    }
-    // Get coeff * coverage into modulate and then write that to the dual source output.
-    this->codeAppendf("\t%s = %s;\n", secondaryOutputName, (coeff * inputCoverage).c_str());
-}
-
-void GrGLFragmentShaderBuilder::combineColorAndCoverage(const GrGLSLExpr4& inputColor,
-                                                        const GrGLSLExpr4& inputCoverage) {
-    GrGLSLExpr4 fragColor = inputColor * inputCoverage;
-    switch (fProgramBuilder->header().fPrimaryOutputType) {
-        case GrProgramDesc::kModulate_PrimaryOutputType:
-            break;
-        case GrProgramDesc::kCombineWithDst_PrimaryOutputType:
-            {
-                // Tack on "+(1-coverage)dst onto the frag color.
-                GrGLSLExpr4 dstCoeff = GrGLSLExpr4(1) - inputCoverage;
-                GrGLSLExpr4 dstContribution = dstCoeff * GrGLSLExpr4(this->dstColor());
-                fragColor = fragColor + dstContribution;
-            }
-            break;
-        default:
-            SkFAIL("Unknown Primary Output");
-    }
-
-    // On any post 1.10 GLSL supporting GPU, we declare custom output
-    if (k110_GrGLSLGeneration != fProgramBuilder->gpu()->glslGeneration()) {
-        this->enableCustomOutput();
-    }
-
-    this->codeAppendf("\t%s = %s;\n", this->getPrimaryColorOutputName(), fragColor.c_str());
-}
-
 bool GrGLFragmentShaderBuilder::compileAndAttachShaders(GrGLuint programId,
                                                         SkTDArray<GrGLuint>* shaderIds) const {
     GrGpuGL* gpu = fProgramBuilder->gpu();
diff --git a/src/gpu/gl/builders/GrGLFragmentShaderBuilder.h b/src/gpu/gl/builders/GrGLFragmentShaderBuilder.h
index 03f0e7f..456ec4f 100644
--- a/src/gpu/gl/builders/GrGLFragmentShaderBuilder.h
+++ b/src/gpu/gl/builders/GrGLFragmentShaderBuilder.h
@@ -100,8 +100,6 @@
     void enableSecondaryOutput();
     const char* getPrimaryColorOutputName() const;
     const char* getSecondaryColorOutputName() const;
-    void enableSecondaryOutput(const GrGLSLExpr4& inputColor, const GrGLSLExpr4& inputCoverage);
-    void combineColorAndCoverage(const GrGLSLExpr4& inputColor, const GrGLSLExpr4& inputCoverage);
     bool compileAndAttachShaders(GrGLuint programId, SkTDArray<GrGLuint>* shaderIds) const;
     void bindFragmentShaderLocations(GrGLuint programID);
 
diff --git a/src/gpu/gl/builders/GrGLLegacyNvprProgramBuilder.cpp b/src/gpu/gl/builders/GrGLLegacyNvprProgramBuilder.cpp
index b251593..b90bab2 100644
--- a/src/gpu/gl/builders/GrGLLegacyNvprProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLLegacyNvprProgramBuilder.cpp
@@ -45,5 +45,6 @@
 
 GrGLProgram* GrGLLegacyNvprProgramBuilder::createProgram(GrGLuint programID) {
     return SkNEW_ARGS(GrGLLegacyNvprProgram, (fGpu, fDesc, fUniformHandles, programID, fUniforms,
-                                              fFragmentProcessors.get(),  fTexCoordSetCnt));
+                                              fXferProcessor, fFragmentProcessors.get(),
+                                              fTexCoordSetCnt));
 }
diff --git a/src/gpu/gl/builders/GrGLNvprProgramBuilder.cpp b/src/gpu/gl/builders/GrGLNvprProgramBuilder.cpp
index f5a5586..ba19275 100644
--- a/src/gpu/gl/builders/GrGLNvprProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLNvprProgramBuilder.cpp
@@ -72,5 +72,6 @@
     // building
     this->resolveSeparableVaryings(programID);
     return SkNEW_ARGS(GrGLNvprProgram, (fGpu, fDesc, fUniformHandles, programID, fUniforms,
-                                        fFragmentProcessors.get(), fSeparableVaryingInfos));
+                                        fXferProcessor, fFragmentProcessors.get(),
+                                        fSeparableVaryingInfos));
 }
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
index 7929801..daa0b6b 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -9,6 +9,7 @@
 #include "gl/GrGLProgram.h"
 #include "gl/GrGLSLPrettyPrint.h"
 #include "gl/GrGLUniformHandle.h"
+#include "../GrGLXferProcessor.h"
 #include "../GrGpuGL.h"
 #include "GrCoordTransform.h"
 #include "GrGLLegacyNvprProgramBuilder.h"
@@ -55,20 +56,12 @@
 
     pb->emitAndInstallProcs(&inputColor, &inputCoverageVec4);
 
-    // write the secondary color output if necessary
-    if (GrProgramDesc::kNone_SecondaryOutputType != header.fSecondaryOutputType) {
-        pb->fFS.enableSecondaryOutput(inputColor, inputCoverageVec4);
-    }
-
-    pb->fFS.combineColorAndCoverage(inputColor, inputCoverageVec4);
-
     return pb->finalize();
 }
 
-GrGLProgramBuilder*
-GrGLProgramBuilder::CreateProgramBuilder(const GrOptDrawState& optState,
-                                         bool hasGeometryProcessor,
-                                         GrGpuGL* gpu) {
+GrGLProgramBuilder* GrGLProgramBuilder::CreateProgramBuilder(const GrOptDrawState& optState,
+                                                             bool hasGeometryProcessor,
+                                                             GrGpuGL* gpu) {
     const GrProgramDesc& desc = optState.programDesc();
     if (GrGLProgramDescBuilder::GetHeader(desc).fUseNvpr) {
         SkASSERT(gpu->glCaps().pathRenderingSupport());
@@ -95,6 +88,7 @@
     , fOutOfStage(true)
     , fStageIndex(-1)
     , fGeometryProcessor(NULL)
+    , fXferProcessor(NULL)
     , fOptState(optState)
     , fDesc(optState.programDesc())
     , fGpu(gpu)
@@ -260,6 +254,8 @@
     if (fOptState.hasGeometryProcessor()) {
         fVS.transformToNormalizedDeviceSpace();
     }
+
+    this->emitAndInstallXferProc(*fOptState.getXferProcessor(), *inputColor, *inputCoverage);
 }
 
 void GrGLProgramBuilder::emitAndInstallFragProcs(int procOffset,
@@ -368,10 +364,55 @@
     verify(gp);
 }
 
+void GrGLProgramBuilder::emitAndInstallXferProc(const GrXferProcessor& xp,
+                                                const GrGLSLExpr4& colorIn,
+                                                const GrGLSLExpr4& coverageIn) {
+    // Program builders have a bit of state we need to clear with each effect
+    AutoStageAdvance adv(this);
+
+    SkASSERT(!fXferProcessor);
+    fXferProcessor = SkNEW(GrGLInstalledXferProc);
+
+    fXferProcessor->fGLProc.reset(xp.createGLInstance());
+
+    // Enable dual source secondary output if we have one
+    if (xp.hasSecondaryOutput()) {
+        fFS.enableSecondaryOutput();
+    }
+
+    // On any post 1.10 GLSL supporting GPU, we declare custom output
+    if (k110_GrGLSLGeneration != fFS.fProgramBuilder->gpu()->glslGeneration()) {
+        fFS.enableCustomOutput();
+    }
+
+    SkString openBrace;
+    openBrace.printf("{ // Xfer Processor: %s\n", xp.name());
+    fFS.codeAppend(openBrace.c_str());
+
+    SkSTArray<4, GrGLProcessor::TextureSampler> samplers(xp.numTextures());
+    this->emitSamplers(xp, &samplers, fXferProcessor);
+
+    GrGLXferProcessor::EmitArgs args(this, xp, colorIn.c_str(), coverageIn.c_str(),
+                                     fFS.getPrimaryColorOutputName(),
+                                     fFS.getSecondaryColorOutputName(), samplers);
+    fXferProcessor->fGLProc->emitCode(args);
+
+    // We have to check that effects and the code they emit are consistent, ie if an effect
+    // asks for dst color, then the emit code needs to follow suit
+    verify(xp);
+    fFS.codeAppend("}");
+}
+
 void GrGLProgramBuilder::verify(const GrGeometryProcessor& gp) {
     SkASSERT(fFS.hasReadFragmentPosition() == gp.willReadFragmentPosition());
 }
 
+void GrGLProgramBuilder::verify(const GrXferProcessor& xp) {
+    // TODO: Once will readDst is only xp enable this assert and remove it from the
+    // FragmentProcessor verify()
+    //SkASSERT(fFS.hasReadDstColor() == xp.willReadDstColor());
+}
+
 void GrGLProgramBuilder::verify(const GrFragmentProcessor& fp) {
     SkASSERT(fFS.hasReadFragmentPosition() == fp.willReadFragmentPosition());
     SkASSERT(fFS.hasReadDstColor() == fp.willReadDstColor());
@@ -543,7 +584,7 @@
 
 GrGLProgram* GrGLProgramBuilder::createProgram(GrGLuint programID) {
     return SkNEW_ARGS(GrGLProgram, (fGpu, fDesc, fUniformHandles, programID, fUniforms,
-                                    fGeometryProcessor, fFragmentProcessors.get()));
+                                    fGeometryProcessor, fXferProcessor, fFragmentProcessors.get()));
 }
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.h b/src/gpu/gl/builders/GrGLProgramBuilder.h
index 1798e60..69eed27 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.h
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.h
@@ -14,6 +14,7 @@
 #include "../GrGLProgramDataManager.h"
 #include "../GrGLUniformHandle.h"
 #include "../GrGLGeometryProcessor.h"
+#include "../GrGLXferProcessor.h"
 #include "../../GrOptDrawState.h"
 #include "../../GrPendingFragmentStage.h"
 
@@ -111,6 +112,7 @@
 
     friend class GrGLVertexBuilder;
     friend class GrGLGeometryBuilder;
+    friend class GrGLXferBuilder;
     friend class GrGLFragmentShaderBuilder;
 };
 
@@ -170,8 +172,18 @@
      */
 };
 
+/* a specializations for XPs. Lets the user add uniforms and FS code */
+class GrGLXPBuilder : public virtual GrGLUniformBuilder {
+public:
+    virtual GrGLFPFragmentBuilder* getFragmentShaderBuilder() = 0;
+
+    /*
+     * *NOTE* NO MEMBERS ALLOWED, MULTIPLE INHERITANCE
+     */
+};
 struct GrGLInstalledProc;
 struct GrGLInstalledGeoProc;
+struct GrGLInstalledXferProc;
 struct GrGLInstalledFragProc;
 struct GrGLInstalledFragProcs;
 
@@ -183,7 +195,8 @@
  * respective builders
 */
 class GrGLProgramBuilder : public GrGLGPBuilder,
-                           public GrGLFPBuilder {
+                           public GrGLFPBuilder,
+                           public GrGLXPBuilder {
 public:
     /** Generates a shader program.
      *
@@ -283,8 +296,12 @@
     void emitAndInstallProc(const GrGeometryProcessor&,
                             const char* outColor,
                             const char* outCoverage);
+    void emitAndInstallXferProc(const GrXferProcessor&,
+                                const GrGLSLExpr4& colorIn,
+                                const GrGLSLExpr4& coverageIn);
 
     void verify(const GrGeometryProcessor&);
+    void verify(const GrXferProcessor&);
     void verify(const GrFragmentProcessor&);
     void emitSamplers(const GrProcessor&,
                       GrGLProcessor::TextureSamplerArray* outSamplers,
@@ -358,6 +375,7 @@
     int fStageIndex;
 
     GrGLInstalledGeoProc* fGeometryProcessor;
+    GrGLInstalledXferProc* fXferProcessor;
     SkAutoTUnref<GrGLInstalledFragProcs> fFragmentProcessors;
 
     const GrOptDrawState& fOptState;
@@ -391,6 +409,10 @@
     SkAutoTDelete<GrGLGeometryProcessor> fGLProc;
 };
 
+struct GrGLInstalledXferProc : public GrGLInstalledProc {
+    SkAutoTDelete<GrGLXferProcessor> fGLProc;
+};
+
 struct GrGLInstalledFragProc : public GrGLInstalledProc {
     GrGLInstalledFragProc() : fGLProc(NULL) {}
     class ShaderVarHandle {