Remove texture sampling from GrConfigConversionEffect

Elevates default precision for the entire fragment program
to maintain precision on some ES implementations.

Re-land fixed version of:
  https://skia-review.googlesource.com/10026/
  https://skia-review.googlesource.com/10056

BUG=skia:

Change-Id: Ibe43dba9c223e430b2f9f8ed5cb97ed7a049e6c2
Reviewed-on: https://skia-review.googlesource.com/10160
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index c1961f9..df5c16d 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -909,20 +909,19 @@
     ASSERT_SINGLE_OWNER
     // We should have already called this->testPMConversionsIfNecessary().
     SkASSERT(fDidTestPMConversions);
-    if (kRGBA_half_GrPixelConfig == proxy->config()) {
-        return GrFragmentProcessor::UnpremulOutput(
-                GrSimpleTextureEffect::Make(this->resourceProvider(), std::move(proxy),
-                                            nullptr, matrix));
-    } else {
+    GrPixelConfig config = proxy->config();
+    sk_sp<GrFragmentProcessor> fp = GrSimpleTextureEffect::Make(this->resourceProvider(),
+                                                                std::move(proxy), nullptr, matrix);
+    if (kRGBA_half_GrPixelConfig == config) {
+        return GrFragmentProcessor::UnpremulOutput(std::move(fp));
+    } else if (kRGBA_8888_GrPixelConfig == config || kBGRA_8888_GrPixelConfig == config) {
         GrConfigConversionEffect::PMConversion pmToUPM =
             static_cast<GrConfigConversionEffect::PMConversion>(fPMToUPMConversion);
         if (GrConfigConversionEffect::kPMConversionCnt != pmToUPM) {
-            return GrConfigConversionEffect::Make(this->resourceProvider(), std::move(proxy),
-                                                  pmToUPM, matrix);
-        } else {
-            return nullptr;
+            return GrConfigConversionEffect::Make(std::move(fp), pmToUPM);
         }
     }
+    return nullptr;
 }
 
 sk_sp<GrFragmentProcessor> GrContext::createUPMToPMEffect(sk_sp<GrTextureProxy> proxy,
@@ -930,20 +929,19 @@
     ASSERT_SINGLE_OWNER
     // We should have already called this->testPMConversionsIfNecessary().
     SkASSERT(fDidTestPMConversions);
-    if (kRGBA_half_GrPixelConfig == proxy->config()) {
-        return GrFragmentProcessor::PremulOutput(
-                GrSimpleTextureEffect::Make(this->resourceProvider(), std::move(proxy),
-                                            nullptr, matrix));
-    } else {
+    GrPixelConfig config = proxy->config();
+    sk_sp<GrFragmentProcessor> fp = GrSimpleTextureEffect::Make(this->resourceProvider(),
+                                                                std::move(proxy), nullptr, matrix);
+    if (kRGBA_half_GrPixelConfig == config) {
+        return GrFragmentProcessor::PremulOutput(std::move(fp));
+    } else if (kRGBA_8888_GrPixelConfig == config || kBGRA_8888_GrPixelConfig == config) {
         GrConfigConversionEffect::PMConversion upmToPM =
             static_cast<GrConfigConversionEffect::PMConversion>(fUPMToPMConversion);
         if (GrConfigConversionEffect::kPMConversionCnt != upmToPM) {
-            return GrConfigConversionEffect::Make(this->resourceProvider(), std::move(proxy),
-                                                  upmToPM, matrix);
-        } else {
-            return nullptr;
+            return GrConfigConversionEffect::Make(std::move(fp), upmToPM);
         }
     }
+    return nullptr;
 }
 
 bool GrContext::validPMUPMConversionExists(GrPixelConfig config) const {
diff --git a/src/gpu/effects/GrConfigConversionEffect.cpp b/src/gpu/effects/GrConfigConversionEffect.cpp
index ac4d300..07225f1 100644
--- a/src/gpu/effects/GrConfigConversionEffect.cpp
+++ b/src/gpu/effects/GrConfigConversionEffect.cpp
@@ -10,7 +10,6 @@
 #include "GrClip.h"
 #include "GrContext.h"
 #include "GrRenderTargetContext.h"
-#include "GrSimpleTextureEffect.h"
 #include "SkMatrix.h"
 #include "glsl/GrGLSLFragmentProcessor.h"
 #include "glsl/GrGLSLFragmentShaderBuilder.h"
@@ -19,59 +18,43 @@
 public:
     void emitCode(EmitArgs& args) override {
         const GrConfigConversionEffect& cce = args.fFp.cast<GrConfigConversionEffect>();
-        GrConfigConversionEffect::PMConversion pmConversion = cce.pmConversion();
-
-        // Using highp for GLES here in order to avoid some precision issues on specific GPUs.
-        GrShaderVar tmpVar("tmpColor", kVec4f_GrSLType, 0, kHigh_GrSLPrecision);
-        SkString tmpDecl;
-        tmpVar.appendDecl(args.fShaderCaps, &tmpDecl);
-
         GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
 
-        fragBuilder->codeAppendf("%s;", tmpDecl.c_str());
+        // Use highp throughout the shader to avoid some precision issues on specific GPUs.
+        fragBuilder->elevateDefaultPrecision(kHigh_GrSLPrecision);
 
-        fragBuilder->codeAppendf("%s = ", tmpVar.c_str());
-        fragBuilder->appendTextureLookup(args.fTexSamplers[0], args.fTransformedCoords[0].c_str(),
-                                         args.fTransformedCoords[0].getType());
-        fragBuilder->codeAppend(";");
+        if (nullptr == args.fInputColor) {
+            // could optimize this case, but we aren't for now.
+            args.fInputColor = "vec4(1)";
+        }
+        fragBuilder->codeAppendf("vec4 color = %s;", args.fInputColor);
 
-        switch (pmConversion) {
+        switch (cce.pmConversion()) {
             case GrConfigConversionEffect::kMulByAlpha_RoundUp_PMConversion:
-                fragBuilder->codeAppendf(
-                    "%s = vec4(ceil(%s.rgb * %s.a * 255.0) / 255.0, %s.a);",
-                    tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str());
+                fragBuilder->codeAppend(
+                    "color.rgb = ceil(color.rgb * color.a * 255.0) / 255.0;");
                 break;
             case GrConfigConversionEffect::kMulByAlpha_RoundDown_PMConversion:
                 // Add a compensation(0.001) here to avoid the side effect of the floor operation.
                 // In Intel GPUs, the integer value converted from floor(%s.r * 255.0) / 255.0
                 // is less than the integer value converted from  %s.r by 1 when the %s.r is
                 // converted from the integer value 2^n, such as 1, 2, 4, 8, etc.
-                fragBuilder->codeAppendf(
-                    "%s = vec4(floor(%s.rgb * %s.a * 255.0 + 0.001) / 255.0, %s.a);",
-                    tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str());
-
+                fragBuilder->codeAppend(
+                    "color.rgb = floor(color.rgb * color.a * 255.0 + 0.001) / 255.0;");
                 break;
             case GrConfigConversionEffect::kDivByAlpha_RoundUp_PMConversion:
-                fragBuilder->codeAppendf(
-                    "%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(ceil(%s.rgb / %s.a * 255.0) / 255.0, %s.a);",
-                    tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(),
-                    tmpVar.c_str());
+                fragBuilder->codeAppend(
+                    "color.rgb = color.a <= 0.0 ? vec3(0,0,0) : ceil(color.rgb / color.a * 255.0) / 255.0;");
                 break;
             case GrConfigConversionEffect::kDivByAlpha_RoundDown_PMConversion:
-                fragBuilder->codeAppendf(
-                    "%s = %s.a <= 0.0 ? vec4(0,0,0,0) : vec4(floor(%s.rgb / %s.a * 255.0) / 255.0, %s.a);",
-                    tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(), tmpVar.c_str(),
-                    tmpVar.c_str());
+                fragBuilder->codeAppend(
+                    "color.rgb = color.a <= 0.0 ? vec3(0,0,0) : floor(color.rgb / color.a * 255.0) / 255.0;");
                 break;
             default:
                 SkFAIL("Unknown conversion op.");
                 break;
         }
-        fragBuilder->codeAppendf("%s = %s;", args.fOutputColor, tmpVar.c_str());
-
-        SkString modulate;
-        GrGLSLMulVarBy4f(&modulate, args.fOutputColor, args.fInputColor);
-        fragBuilder->codeAppend(modulate.c_str());
+        fragBuilder->codeAppendf("%s = color;", args.fOutputColor);
     }
 
     static inline void GenKey(const GrProcessor& processor, const GrShaderCaps&,
@@ -87,17 +70,11 @@
 };
 
 ///////////////////////////////////////////////////////////////////////////////
-GrConfigConversionEffect::GrConfigConversionEffect(GrResourceProvider* resourceProvider,
-                                                   sk_sp<GrTextureProxy> proxy,
-                                                   PMConversion pmConversion,
-                                                   const SkMatrix& matrix)
-        : INHERITED(resourceProvider, kNone_OptimizationFlags, proxy, nullptr, matrix)
+
+GrConfigConversionEffect::GrConfigConversionEffect(PMConversion pmConversion)
+        : INHERITED(kNone_OptimizationFlags)
         , fPMConversion(pmConversion) {
     this->initClassID<GrConfigConversionEffect>();
-    // We expect to get here with non-BGRA/RGBA only if we're doing not doing a premul/unpremul
-    // conversion.
-    SkASSERT(kRGBA_8888_GrPixelConfig == proxy->config() ||
-             kBGRA_8888_GrPixelConfig == proxy->config());
 }
 
 bool GrConfigConversionEffect::onIsEqual(const GrFragmentProcessor& s) const {
@@ -112,10 +89,7 @@
 #if GR_TEST_UTILS
 sk_sp<GrFragmentProcessor> GrConfigConversionEffect::TestCreate(GrProcessorTestData* d) {
     PMConversion pmConv = static_cast<PMConversion>(d->fRandom->nextULessThan(kPMConversionCnt));
-    return sk_sp<GrFragmentProcessor>(new GrConfigConversionEffect(
-                            d->resourceProvider(),
-                            d->textureProxy(GrProcessorUnitTest::kSkiaPMTextureIdx),
-                            pmConv, GrTest::TestMatrix(d->fRandom)));
+    return sk_sp<GrFragmentProcessor>(new GrConfigConversionEffect(pmConv));
 }
 #endif
 
@@ -203,14 +177,11 @@
         GrPaint paint1;
         GrPaint paint2;
         GrPaint paint3;
-        sk_sp<GrFragmentProcessor> pmToUPM1(new GrConfigConversionEffect(
-                resourceProvider, dataProxy, *pmToUPMRule, SkMatrix::I()));
-        sk_sp<GrFragmentProcessor> upmToPM(new GrConfigConversionEffect(
-                resourceProvider, readRTC->asTextureProxyRef(), *upmToPMRule, SkMatrix::I()));
-        sk_sp<GrFragmentProcessor> pmToUPM2(new GrConfigConversionEffect(
-                resourceProvider, tempRTC->asTextureProxyRef(), *pmToUPMRule, SkMatrix::I()));
+        sk_sp<GrFragmentProcessor> pmToUPM(new GrConfigConversionEffect(*pmToUPMRule));
+        sk_sp<GrFragmentProcessor> upmToPM(new GrConfigConversionEffect(*upmToPMRule));
 
-        paint1.addColorFragmentProcessor(std::move(pmToUPM1));
+        paint1.addColorTextureProcessor(resourceProvider, dataProxy, nullptr, SkMatrix::I());
+        paint1.addColorFragmentProcessor(pmToUPM);
         paint1.setPorterDuffXPFactory(SkBlendMode::kSrc);
 
         readRTC->fillRectToRect(GrNoClip(), std::move(paint1), GrAA::kNo, SkMatrix::I(), kDstRect,
@@ -220,13 +191,17 @@
             continue;
         }
 
+        paint2.addColorTextureProcessor(resourceProvider, readRTC->asTextureProxyRef(), nullptr,
+                                        SkMatrix::I());
         paint2.addColorFragmentProcessor(std::move(upmToPM));
         paint2.setPorterDuffXPFactory(SkBlendMode::kSrc);
 
         tempRTC->fillRectToRect(GrNoClip(), std::move(paint2), GrAA::kNo, SkMatrix::I(), kDstRect,
                                 kSrcRect);
 
-        paint3.addColorFragmentProcessor(std::move(pmToUPM2));
+        paint3.addColorTextureProcessor(resourceProvider, tempRTC->asTextureProxyRef(), nullptr,
+                                        SkMatrix::I());
+        paint3.addColorFragmentProcessor(std::move(pmToUPM));
         paint3.setPorterDuffXPFactory(SkBlendMode::kSrc);
 
         readRTC->fillRectToRect(GrNoClip(), std::move(paint3), GrAA::kNo, SkMatrix::I(), kDstRect,
@@ -252,16 +227,12 @@
     }
 }
 
-sk_sp<GrFragmentProcessor> GrConfigConversionEffect::Make(GrResourceProvider* resourceProvider,
-                                                          sk_sp<GrTextureProxy> proxy,
-                                                          PMConversion pmConversion,
-                                                          const SkMatrix& matrix) {
-    if (kRGBA_8888_GrPixelConfig != proxy->config() &&
-        kBGRA_8888_GrPixelConfig != proxy->config()) {
-        // The PM conversions assume colors are 0..255
+sk_sp<GrFragmentProcessor> GrConfigConversionEffect::Make(sk_sp<GrFragmentProcessor> fp,
+                                                          PMConversion pmConversion) {
+    if (!fp) {
         return nullptr;
     }
-    return sk_sp<GrFragmentProcessor>(new GrConfigConversionEffect(resourceProvider,
-                                                                   std::move(proxy),
-                                                                   pmConversion, matrix));
+    sk_sp<GrFragmentProcessor> ccFP(new GrConfigConversionEffect(pmConversion));
+    sk_sp<GrFragmentProcessor> fpPipeline[] = { fp, ccFP };
+    return GrFragmentProcessor::RunInSeries(fpPipeline, 2);
 }
diff --git a/src/gpu/effects/GrConfigConversionEffect.h b/src/gpu/effects/GrConfigConversionEffect.h
index d3e40dd..e5fa10c 100644
--- a/src/gpu/effects/GrConfigConversionEffect.h
+++ b/src/gpu/effects/GrConfigConversionEffect.h
@@ -8,15 +8,13 @@
 #ifndef GrConfigConversionEffect_DEFINED
 #define GrConfigConversionEffect_DEFINED
 
-#include "GrSingleTextureEffect.h"
-
-class GrInvariantOutput;
+#include "GrFragmentProcessor.h"
 
 /**
  * This class is used to perform config conversions. Clients may want to read/write data that is
  * unpremultiplied.
  */
-class GrConfigConversionEffect : public GrSingleTextureEffect {
+class GrConfigConversionEffect : public GrFragmentProcessor {
 public:
     /**
      * The PM->UPM or UPM->PM conversions to apply.
@@ -30,8 +28,11 @@
         kPMConversionCnt
     };
 
-    static sk_sp<GrFragmentProcessor> Make(GrResourceProvider*, sk_sp<GrTextureProxy>,
-                                           PMConversion, const SkMatrix&);
+    /**
+     *  Returns a fragment processor that calls the passed in fragment processor, and then performs
+     *  the requested premul or unpremul conversion.
+     */
+    static sk_sp<GrFragmentProcessor> Make(sk_sp<GrFragmentProcessor>, PMConversion);
 
     const char* name() const override { return "Config Conversion"; }
 
@@ -46,8 +47,7 @@
                                                PMConversion* PMToUPMRule,
                                                PMConversion* UPMToPMRule);
 private:
-    GrConfigConversionEffect(GrResourceProvider*, sk_sp<GrTextureProxy>,
-                             PMConversion, const SkMatrix& matrix);
+    GrConfigConversionEffect(PMConversion);
 
     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
 
@@ -59,7 +59,7 @@
 
     GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
 
-    typedef GrSingleTextureEffect INHERITED;
+    typedef GrFragmentProcessor INHERITED;
 };
 
 #endif