Add SkOverdrawColorFilter

Uses the value in the src alpha channel to choose how
to set the dst pixel.

This is a part of a multi-part change to detect and
display gpu overdraw on Android.

CQ_INCLUDE_TRYBOTS=master.client.skia.compile:Build-Ubuntu-GCC-x86_64-Debug-NoGPU-Trybot

BUG:32370375

GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=5113

Change-Id: I07040929d8a46bbadd499dccec75eebef0e11d11
Reviewed-on: https://skia-review.googlesource.com/5113
Commit-Queue: Matt Sarett <msarett@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/src/effects/SkOverdrawColorFilter.cpp b/src/effects/SkOverdrawColorFilter.cpp
new file mode 100644
index 0000000..c3bcd0e
--- /dev/null
+++ b/src/effects/SkOverdrawColorFilter.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkOverdrawColorFilter.h"
+
+void SkOverdrawColorFilter::filterSpan(const SkPMColor src[], int count, SkPMColor dst[]) const {
+    for (int x = 0; x < count; x++) {
+        uint8_t alpha = SkGetPackedA32(src[x]);
+        if (alpha >= kNumColors) {
+            alpha = kNumColors - 1;
+        }
+
+        dst[x] = fColors[alpha];
+    }
+}
+
+void SkOverdrawColorFilter::toString(SkString* str) const {
+    str->append("SkOverdrawColorFilter (");
+    for (int i = 0; i < kNumColors; i++) {
+        str->appendf("%d: %x\n", i, fColors[i]);
+    }
+    str->append(")");
+}
+
+void SkOverdrawColorFilter::flatten(SkWriteBuffer& buffer) const {
+    buffer.writeByteArray(fColors, kNumColors * sizeof(SkPMColor));
+}
+
+sk_sp<SkFlattenable> SkOverdrawColorFilter::CreateProc(SkReadBuffer& buffer) {
+    SkPMColor colors[kNumColors];
+    size_t size = buffer.getArrayCount();
+    if (!buffer.validate(size == sizeof(colors))) {
+        return nullptr;
+    }
+    if (!buffer.readByteArray(colors, sizeof(colors))) {
+        return nullptr;
+    }
+
+    return SkOverdrawColorFilter::Make(colors);
+}
+
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkOverdrawColorFilter)
+    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkOverdrawColorFilter)
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
+
+#if SK_SUPPORT_GPU
+
+#include "GrFragmentProcessor.h"
+#include "GrInvariantOutput.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+
+class OverdrawFragmentProcessor : public GrFragmentProcessor {
+public:
+    static sk_sp<GrFragmentProcessor> Make(const SkPMColor* colors);
+
+    const char* name() const override { return "Overdraw"; }
+
+private:
+    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+    void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override {}
+    bool onIsEqual(const GrFragmentProcessor&) const override;
+    void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
+
+    OverdrawFragmentProcessor(const GrColor4f* colors);
+
+    GrColor4f fColors[SkOverdrawColorFilter::kNumColors];
+
+    typedef GrFragmentProcessor INHERITED;
+};
+
+class GLOverdrawFragmentProcessor : public GrGLSLFragmentProcessor {
+public:
+    GLOverdrawFragmentProcessor(const GrColor4f* colors);
+
+    void emitCode(EmitArgs&) override;
+
+protected:
+    void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override {}
+
+private:
+    GrColor4f fColors[SkOverdrawColorFilter::kNumColors];
+
+    typedef GrGLSLFragmentProcessor INHERITED;
+};
+
+sk_sp<GrFragmentProcessor> SkOverdrawColorFilter::asFragmentProcessor(GrContext*,
+                                                                      SkColorSpace*) const {
+    return OverdrawFragmentProcessor::Make(fColors);
+}
+
+sk_sp<GrFragmentProcessor> OverdrawFragmentProcessor::Make(const SkPMColor* colors) {
+    GrColor4f grColors[SkOverdrawColorFilter::kNumColors];
+    for (int i = 0; i < SkOverdrawColorFilter::kNumColors; i++) {
+        grColors[i] = GrColor4f::FromGrColor(GrColorPackRGBA(SkGetPackedR32(colors[i]),
+                                                             SkGetPackedG32(colors[i]),
+                                                             SkGetPackedB32(colors[i]),
+                                                             SkGetPackedA32(colors[i])));
+    }
+
+    return sk_sp<OverdrawFragmentProcessor>(new OverdrawFragmentProcessor(grColors));
+}
+
+OverdrawFragmentProcessor::OverdrawFragmentProcessor(const GrColor4f* colors) {
+    this->initClassID<OverdrawFragmentProcessor>();
+    memcpy(fColors, colors, SkOverdrawColorFilter::kNumColors * sizeof(GrColor4f));
+}
+
+GrGLSLFragmentProcessor* OverdrawFragmentProcessor::onCreateGLSLInstance() const {
+    return new GLOverdrawFragmentProcessor(fColors);
+}
+
+bool OverdrawFragmentProcessor::onIsEqual(const GrFragmentProcessor& other) const {
+    const OverdrawFragmentProcessor& that = other.cast<OverdrawFragmentProcessor>();
+    return 0 == memcmp(fColors, that.fColors,
+                       sizeof(GrColor4f) * SkOverdrawColorFilter::kNumColors);
+}
+
+void OverdrawFragmentProcessor::onComputeInvariantOutput(GrInvariantOutput* inout) const {
+    inout->invalidateComponents(kRGBA_GrColorComponentFlags, GrInvariantOutput::kWill_ReadInput);
+}
+
+GLOverdrawFragmentProcessor::GLOverdrawFragmentProcessor(const GrColor4f* colors) {
+    memcpy(fColors, colors, SkOverdrawColorFilter::kNumColors * sizeof(GrColor4f));
+}
+
+void GLOverdrawFragmentProcessor::emitCode(EmitArgs& args) {
+    GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
+    if (nullptr == args.fInputColor) {
+        fragBuilder->codeAppendf("%s.rgba = vec4(%f, %f, %f, %f);", args.fOutputColor,
+                                                                    fColors[5].fRGBA[0],
+                                                                    fColors[5].fRGBA[1],
+                                                                    fColors[5].fRGBA[2],
+                                                                    fColors[5].fRGBA[3]);
+    } else {
+        fragBuilder->codeAppendf("float alpha = 255.0 * %s.a;", args.fInputColor);
+        fragBuilder->codeAppendf("if (alpha < 0.5) {");
+        fragBuilder->codeAppendf("    %s.rgba = vec4(%f, %f, %f, %f);", args.fOutputColor,
+                                                                        fColors[0].fRGBA[0],
+                                                                        fColors[0].fRGBA[1],
+                                                                        fColors[0].fRGBA[2],
+                                                                        fColors[0].fRGBA[3]);
+        fragBuilder->codeAppendf("} else if (alpha < 1.5) {");
+        fragBuilder->codeAppendf("    %s.rgba = vec4(%f, %f, %f, %f);", args.fOutputColor,
+                                                                        fColors[1].fRGBA[0],
+                                                                        fColors[1].fRGBA[1],
+                                                                        fColors[1].fRGBA[2],
+                                                                        fColors[1].fRGBA[3]);
+        fragBuilder->codeAppendf("} else if (alpha < 2.5) {");
+        fragBuilder->codeAppendf("    %s.rgba = vec4(%f, %f, %f, %f);", args.fOutputColor,
+                                                                        fColors[2].fRGBA[0],
+                                                                        fColors[2].fRGBA[1],
+                                                                        fColors[2].fRGBA[2],
+                                                                        fColors[2].fRGBA[3]);
+        fragBuilder->codeAppendf("} else if (alpha < 3.5) {");
+        fragBuilder->codeAppendf("    %s.rgba = vec4(%f, %f, %f, %f);", args.fOutputColor,
+                                                                        fColors[3].fRGBA[0],
+                                                                        fColors[3].fRGBA[1],
+                                                                        fColors[3].fRGBA[2],
+                                                                        fColors[3].fRGBA[3]);
+        fragBuilder->codeAppendf("} else if (alpha < 4.5) {");
+        fragBuilder->codeAppendf("    %s.rgba = vec4(%f, %f, %f, %f);", args.fOutputColor,
+                                                                        fColors[4].fRGBA[0],
+                                                                        fColors[4].fRGBA[1],
+                                                                        fColors[4].fRGBA[2],
+                                                                        fColors[4].fRGBA[3]);
+        fragBuilder->codeAppendf("} else {");
+        fragBuilder->codeAppendf("    %s.rgba = vec4(%f, %f, %f, %f);", args.fOutputColor,
+                                                                        fColors[5].fRGBA[0],
+                                                                        fColors[5].fRGBA[1],
+                                                                        fColors[5].fRGBA[2],
+                                                                        fColors[5].fRGBA[3]);
+        fragBuilder->codeAppendf("}");
+    }
+}
+
+#endif