Simple GPU based dithering:

If dithering is turned on, apply an effect that filters the pixel through
the following pipeline:

for each channel c:
  1. Compute quantized colors [low, high] that c is between
  2. Pick high by flipping a coin weighted by (c - low)

R=bsalomon@google.com, egdaniel@google.com, robertphillips@google.com

Author: krajcevski@google.com

Review URL: https://codereview.chromium.org/321253002
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 8e7cea6..a1b379f 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -13,6 +13,7 @@
 #include "SkPixelRef.h"
 #include "GrResourceCache.h"
 #include "GrGpu.h"
+#include "effects/GrDitherEffect.h"
 #include "GrDrawTargetCaps.h"
 
 #ifndef SK_IGNORE_ETC1_SUPPORT
@@ -460,6 +461,29 @@
             }
         }
     }
+
+#ifndef SK_IGNORE_GPU_DITHER
+    // If the dither flag is set, then we need to see if the underlying context
+    // supports it. If not, then install a dither effect.
+    if (skPaint.isDither() && grPaint->numColorStages() > 0) {
+        // What are we rendering into?
+        const GrRenderTarget *target = context->getRenderTarget();
+        SkASSERT(NULL != target);
+
+        // Suspect the dithering flag has no effect on these configs, otherwise
+        // fall back on setting the appropriate state.
+        if (target->config() == kRGBA_8888_GrPixelConfig ||
+            target->config() == kBGRA_8888_GrPixelConfig) {
+            // The dither flag is set and the target is likely
+            // not going to be dithered by the GPU.
+            SkAutoTUnref<GrEffectRef> effect(GrDitherEffect::Create());
+            if (NULL != effect.get()) {
+                grPaint->addColorEffect(effect);
+                grPaint->setDither(false);
+            }
+        }
+    }
+#endif
 }
 
 /**
@@ -494,19 +518,26 @@
     // SkShader::asNewEffect() may do offscreen rendering. Save off the current RT, clip, and
     // matrix. We don't reset the matrix on the context because SkShader::asNewEffect may use
     // GrContext::getMatrix() to know the transformation from local coords to device space.
-    GrContext::AutoRenderTarget art(context, NULL);
-    GrContext::AutoClip ac(context, GrContext::AutoClip::kWideOpen_InitialClip);
-    AutoMatrix am(context);
-
-    // setup the shader as the first color effect on the paint
-    // the default grColor is the paint's color
     GrColor grColor = SkColor2GrColor(skPaint.getColor());
-    GrEffectRef* grEffect = NULL;
-    if (shader->asNewEffect(context, skPaint, NULL, &grColor, &grEffect) && NULL != grEffect) {
-        SkAutoTUnref<GrEffectRef> effect(grEffect);
-        grPaint->addColorEffect(effect);
-        constantColor = false;
+
+    // Start a new block here in order to preserve our context state after calling
+    // asNewEffect(). Since these calls get passed back to the client, we don't really
+    // want them messing around with the context.
+    {
+        GrContext::AutoRenderTarget art(context, NULL);
+        GrContext::AutoClip ac(context, GrContext::AutoClip::kWideOpen_InitialClip);
+        AutoMatrix am(context);
+
+        // setup the shader as the first color effect on the paint
+        // the default grColor is the paint's color
+        GrEffectRef* grEffect = NULL;
+        if (shader->asNewEffect(context, skPaint, NULL, &grColor, &grEffect) && NULL != grEffect) {
+            SkAutoTUnref<GrEffectRef> effect(grEffect);
+            grPaint->addColorEffect(effect);
+            constantColor = false;
+        }
     }
+
     // The grcolor is automatically set when calling asneweffect.
     // If the shader can be seen as an effect it returns true and adds its effect to the grpaint.
     SkPaint2GrPaintNoShader(context, skPaint, grColor, constantColor, grPaint);