Ganesh: Clamp blend inputs when using F16_Clamped pixel config

This ensures that we stay in [0,1], except for plus mode, which
requires a larger and more invasive change.

Bug: skia:
Change-Id: I97f6bcea8b10e70e55ba24bcff759ddbb1761794
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/201460
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/include/private/GrTypesPriv.h b/include/private/GrTypesPriv.h
index c7fe8f3..bda6e0d 100644
--- a/include/private/GrTypesPriv.h
+++ b/include/private/GrTypesPriv.h
@@ -1031,6 +1031,10 @@
     return false;
 }
 
+static inline bool GrPixelConfigNeedsClamp(GrPixelConfig config) {
+    return kRGBA_half_Clamped_GrPixelConfig == config;
+}
+
 /**
  * Returns true if the pixel config is a GPU-specific compressed format
  * representation.
diff --git a/src/gpu/GrProgramDesc.cpp b/src/gpu/GrProgramDesc.cpp
index 26b06f9..5401d4d 100644
--- a/src/gpu/GrProgramDesc.cpp
+++ b/src/gpu/GrProgramDesc.cpp
@@ -253,5 +253,6 @@
     SkASSERT(header->processorFeatures() == processorFeatures);  // Ensure enough bits.
     header->fSnapVerticesToPixelCenters = pipeline.snapVerticesToPixelCenters();
     header->fHasPointSize = hasPointSize ? 1 : 0;
+    header->fClampBlendInput = GrPixelConfigNeedsClamp(renderTarget->config()) ? 1 : 0;
     return true;
 }
diff --git a/src/gpu/GrProgramDesc.h b/src/gpu/GrProgramDesc.h
index e2fe270..af5ce80 100644
--- a/src/gpu/GrProgramDesc.h
+++ b/src/gpu/GrProgramDesc.h
@@ -103,7 +103,8 @@
         uint8_t fProcessorFeatures : 1;
         bool fSnapVerticesToPixelCenters : 1;
         bool fHasPointSize : 1;
-        uint8_t fPad : 3;
+        bool fClampBlendInput : 1;
+        uint8_t fPad : 2;
     };
     GR_STATIC_ASSERT(sizeof(KeyHeader) == 6);
 
diff --git a/src/gpu/glsl/GrGLSLProgramBuilder.cpp b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
index 09e2388..ff9ad86 100644
--- a/src/gpu/glsl/GrGLSLProgramBuilder.cpp
+++ b/src/gpu/glsl/GrGLSLProgramBuilder.cpp
@@ -253,11 +253,22 @@
         SkASSERT(dstTexture->texturePriv().textureType() != GrTextureType::kExternal);
     }
 
+    SkString finalInColor;
+    if (colorIn.size()) {
+        if (this->desc()->header().fClampBlendInput) {
+            finalInColor.printf("saturate(%s)", colorIn.c_str());
+        } else {
+            finalInColor = colorIn;
+        }
+    } else {
+        finalInColor = "float4(1)";
+    }
+
     GrGLSLXferProcessor::EmitArgs args(&fFS,
                                        this->uniformHandler(),
                                        this->shaderCaps(),
                                        xp,
-                                       colorIn.size() ? colorIn.c_str() : "float4(1)",
+                                       finalInColor.c_str(),
                                        coverageIn.size() ? coverageIn.c_str() : "float4(1)",
                                        fFS.getPrimaryColorOutputName(),
                                        fFS.getSecondaryColorOutputName(),