SkSurfaceProps now has a gamma-correct ("AllowSRGBInputs") flag. That's propagated in a few places so that the backend can do the right thing for L32 vs S32 mode.

Also added SkSurfaceProps to SkSpecialImage, so that Image -> Surface conversion can preserve the desired behavior during filtering.

Many small changes, including a bunch of comments about places where we may be losing information right now. My approach was to ensure that if anything fails, it will always fall back to "legacy" mode - gamma-correctness is opt-in, so I'll just have to feed things through as missing cases are exposed.
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1838953007

Review URL: https://codereview.chromium.org/1845283003
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 2f6477c..de69c36 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -1334,6 +1334,18 @@
     }
 }
 
+bool SkCanvas::getProps(SkSurfaceProps* props) const {
+    SkBaseDevice* dev = this->getDevice();
+    if (dev) {
+        if (props) {
+            *props = fProps;
+        }
+        return true;
+    } else {
+        return false;
+    }
+}
+
 #ifdef SK_SUPPORT_LEGACY_PEEKPIXELS_PARMS
 const void* SkCanvas::peekPixels(SkImageInfo* info, size_t* rowBytes) {
     SkPixmap pmap;
@@ -1406,7 +1418,8 @@
             SkAutoTUnref<SkImageFilter::Cache> cache(dstDev->getImageFilterCache());
             SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
 
-            sk_sp<SkSpecialImage> srcImg(SkSpecialImage::internal_fromBM(&proxy, srcBM));
+            sk_sp<SkSpecialImage> srcImg(SkSpecialImage::internal_fromBM(&proxy, srcBM,
+                                                                         &dstDev->surfaceProps()));
             if (!srcImg) {
                 continue; // something disastrous happened
             }
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index 3a4090e..1b22856 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -418,7 +418,8 @@
         SkAutoTUnref<SkImageFilter::Cache> cache(this->getImageFilterCache());
         SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
 
-        sk_sp<SkSpecialImage> srcImg(SkSpecialImage::internal_fromBM(&proxy, bitmap));
+        sk_sp<SkSpecialImage> srcImg(SkSpecialImage::internal_fromBM(&proxy, bitmap,
+                                                                     &this->surfaceProps()));
         if (!srcImg) {
             return; // something disastrous happened
         }
diff --git a/src/core/SkImageFilter.cpp b/src/core/SkImageFilter.cpp
index 0e0df36..743dc2a 100644
--- a/src/core/SkImageFilter.cpp
+++ b/src/core/SkImageFilter.cpp
@@ -295,7 +295,8 @@
         return true;
     }
 
-    sk_sp<SkSpecialImage> specialSrc(SkSpecialImage::internal_fromBM(proxy, src));
+    // SRGBTODO: Don't handle sRGB here, in anticipation of this code path being deleted.
+    sk_sp<SkSpecialImage> specialSrc(SkSpecialImage::internal_fromBM(proxy, src, nullptr));
     if (!specialSrc) {
         return false;
     }
@@ -377,7 +378,7 @@
         return nullptr;
     }
 
-    return SkSpecialImage::internal_fromBM(src->internal_getProxy(), resultBM);
+    return SkSpecialImage::internal_fromBM(src->internal_getProxy(), resultBM, &src->props());
 }
 
 bool SkImageFilter::canFilterImageGPU() const {
@@ -418,6 +419,7 @@
     SkMatrix matrix(ctx.ctm());
     matrix.postTranslate(SkIntToScalar(-bounds.left()), SkIntToScalar(-bounds.top()));
     GrPaint paint;
+    // SRGBTODO: Don't handle sRGB here, in anticipation of this code path being deleted.
     if (this->asFragmentProcessor(&fp, srcTexture, matrix, bounds)) {
         SkASSERT(fp);
         paint.addColorFragmentProcessor(fp)->unref();
@@ -620,7 +622,8 @@
         return true;
     }
 
-    sk_sp<SkSpecialImage> specialSrc(SkSpecialImage::internal_fromBM(proxy, src));
+    // SRGBTODO: Don't handle sRGB here, in anticipation of this code path being deleted.
+    sk_sp<SkSpecialImage> specialSrc(SkSpecialImage::internal_fromBM(proxy, src, nullptr));
     if (!specialSrc) {
         return false;
     }
diff --git a/src/core/SkSpecialImage.cpp b/src/core/SkSpecialImage.cpp
index 681c224..abac947 100644
--- a/src/core/SkSpecialImage.cpp
+++ b/src/core/SkSpecialImage.cpp
@@ -15,12 +15,14 @@
 #include "SkCanvas.h"
 #include "SkImage_Base.h"
 #include "SkSpecialSurface.h"
+#include "SkSurfacePriv.h"
 
 ///////////////////////////////////////////////////////////////////////////////
 class SkSpecialImage_Base : public SkSpecialImage {
 public:
-    SkSpecialImage_Base(SkImageFilter::Proxy* proxy, const SkIRect& subset, uint32_t uniqueID)
-        : INHERITED(proxy, subset, uniqueID) {
+    SkSpecialImage_Base(SkImageFilter::Proxy* proxy, const SkIRect& subset, uint32_t uniqueID,
+                        const SkSurfaceProps* props)
+        : INHERITED(proxy, subset, uniqueID, props) {
     }
     virtual ~SkSpecialImage_Base() { }
 
@@ -52,6 +54,16 @@
     return static_cast<const SkSpecialImage_Base*>(image);
 }
 
+SkSpecialImage::SkSpecialImage(SkImageFilter::Proxy* proxy,
+                               const SkIRect& subset,
+                               uint32_t uniqueID,
+                               const SkSurfaceProps* props)
+    : fProps(SkSurfacePropsCopyOrDefault(props))
+    , fSubset(subset)
+    , fUniqueID(kNeedNewImageUniqueID_SpecialImage == uniqueID ? SkNextID::ImageID() : uniqueID)
+    , fProxy(proxy) {
+}
+
 sk_sp<SkSpecialImage> SkSpecialImage::makeTextureImage(SkImageFilter::Proxy* proxy,
                                                        GrContext* context) {
 #if SK_SUPPORT_GPU
@@ -68,7 +80,7 @@
     }
 
     if (bmp.empty()) {
-        return SkSpecialImage::MakeFromRaster(proxy, SkIRect::MakeEmpty(), bmp);
+        return SkSpecialImage::MakeFromRaster(proxy, SkIRect::MakeEmpty(), bmp, &this->props());
     }
 
     SkAutoTUnref<GrTexture> resultTex(
@@ -82,7 +94,7 @@
     return SkSpecialImage::MakeFromGpu(proxy,
                                        SkIRect::MakeWH(resultTex->width(), resultTex->height()),
                                        this->uniqueID(),
-                                       resultTex, at);
+                                       resultTex, &this->props(), at);
 #else
     return nullptr;
 #endif
@@ -126,16 +138,18 @@
 #endif
 
 sk_sp<SkSpecialImage> SkSpecialImage::internal_fromBM(SkImageFilter::Proxy* proxy,
-                                                       const SkBitmap& src) {
+                                                      const SkBitmap& src,
+                                                      const SkSurfaceProps* props) {
     // Need to test offset case! (see skbug.com/4967)
     if (src.getTexture()) {
         return SkSpecialImage::MakeFromGpu(proxy,
                                            src.bounds(),
                                            src.getGenerationID(),
-                                           src.getTexture());
+                                           src.getTexture(),
+                                           props);
     }
 
-    return SkSpecialImage::MakeFromRaster(proxy, src.bounds(), src);
+    return SkSpecialImage::MakeFromRaster(proxy, src.bounds(), src, props);
 }
 
 bool SkSpecialImage::internal_getBM(SkBitmap* result) {
@@ -160,8 +174,9 @@
 public:
     SkSpecialImage_Image(SkImageFilter::Proxy* proxy,
                          const SkIRect& subset,
-                         sk_sp<SkImage> image)
-        : INHERITED(proxy, subset, image->uniqueID())
+                         sk_sp<SkImage> image,
+                         const SkSurfaceProps* props)
+        : INHERITED(proxy, subset, image->uniqueID(), props)
         , fImage(image) {
     }
 
@@ -240,7 +255,8 @@
 
         return SkSpecialImage::MakeFromImage(this->internal_getProxy(),
                                              SkIRect::MakeWH(subset.width(), subset.height()),
-                                             subsetImg);
+                                             subsetImg,
+                                             &this->props());
     }
 
     sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const override {
@@ -279,10 +295,11 @@
 
 sk_sp<SkSpecialImage> SkSpecialImage::MakeFromImage(SkImageFilter::Proxy* proxy,
                                                     const SkIRect& subset,
-                                                    sk_sp<SkImage> image) {
+                                                    sk_sp<SkImage> image,
+                                                    const SkSurfaceProps* props) {
     SkASSERT(rect_fits(subset, image->width(), image->height()));
 
-    return sk_make_sp<SkSpecialImage_Image>(proxy, subset, image);
+    return sk_make_sp<SkSpecialImage_Image>(proxy, subset, image, props);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -292,8 +309,9 @@
 
 class SkSpecialImage_Raster : public SkSpecialImage_Base {
 public:
-    SkSpecialImage_Raster(SkImageFilter::Proxy* proxy, const SkIRect& subset, const SkBitmap& bm)
-        : INHERITED(proxy, subset, bm.getGenerationID())
+    SkSpecialImage_Raster(SkImageFilter::Proxy* proxy, const SkIRect& subset, const SkBitmap& bm,
+                          const SkSurfaceProps* props)
+        : INHERITED(proxy, subset, bm.getGenerationID(), props)
         , fBitmap(bm) {
         if (bm.pixelRef() && bm.pixelRef()->isPreLocked()) {
             // we only preemptively lock if there is no chance of triggering something expensive
@@ -306,8 +324,9 @@
                           const SkIRect& subset,
                           const SkPixmap& pixmap,
                           RasterReleaseProc releaseProc,
-                          ReleaseContext context)
-        : INHERITED(proxy, subset, kNeedNewImageUniqueID_SpecialImage) {
+                          ReleaseContext context,
+                          const SkSurfaceProps* props)
+        : INHERITED(proxy, subset, kNeedNewImageUniqueID_SpecialImage, props) {
         fBitmap.installPixels(pixmap.info(), pixmap.writable_addr(),
                               pixmap.rowBytes(), pixmap.ctable(),
                               releaseProc, context);
@@ -364,7 +383,8 @@
 
         return SkSpecialImage::MakeFromRaster(this->internal_getProxy(),
                                               SkIRect::MakeWH(subset.width(), subset.height()),
-                                              subsetBM);
+                                              subsetBM,
+                                              &this->props());
     }
 
     sk_sp<SkImage> onMakeTightSubset(const SkIRect& subset) const override {
@@ -389,23 +409,25 @@
 
 sk_sp<SkSpecialImage> SkSpecialImage::MakeFromRaster(SkImageFilter::Proxy* proxy,
                                                      const SkIRect& subset,
-                                                     const SkBitmap& bm) {
+                                                     const SkBitmap& bm,
+                                                     const SkSurfaceProps* props) {
     SkASSERT(nullptr == bm.getTexture());
     SkASSERT(rect_fits(subset, bm.width(), bm.height()));
 
-    return sk_make_sp<SkSpecialImage_Raster>(proxy, subset, bm);
+    return sk_make_sp<SkSpecialImage_Raster>(proxy, subset, bm, props);
 }
 
 sk_sp<SkSpecialImage> SkSpecialImage::MakeFromPixmap(SkImageFilter::Proxy* proxy,
                                                      const SkIRect& subset,
                                                      const SkPixmap& src,
                                                      RasterReleaseProc releaseProc,
-                                                     ReleaseContext context) {
+                                                     ReleaseContext context,
+                                                     const SkSurfaceProps* props) {
     if (!src.addr()) {
         return nullptr;
     }
 
-    return sk_make_sp<SkSpecialImage_Raster>(proxy, subset, src, releaseProc, context);
+    return sk_make_sp<SkSpecialImage_Raster>(proxy, subset, src, releaseProc, context, props);
 }
 
 
@@ -417,8 +439,9 @@
 class SkSpecialImage_Gpu : public SkSpecialImage_Base {
 public:
     SkSpecialImage_Gpu(SkImageFilter::Proxy* proxy, const SkIRect& subset,
-                       uint32_t uniqueID, GrTexture* tex, SkAlphaType at)
-        : INHERITED(proxy, subset, uniqueID)
+                       uint32_t uniqueID, GrTexture* tex, SkAlphaType at,
+                       const SkSurfaceProps* props)
+        : INHERITED(proxy, subset, uniqueID, props)
         , fTexture(SkRef(tex))
         , fAlphaType(at) {
     }
@@ -496,6 +519,7 @@
                                            subset,
                                            this->uniqueID(),
                                            fTexture,
+                                           &this->props(),
                                            fAlphaType);
     }
 
@@ -539,9 +563,10 @@
                                                   const SkIRect& subset,
                                                   uint32_t uniqueID,
                                                   GrTexture* tex,
+                                                  const SkSurfaceProps* props,
                                                   SkAlphaType at) {
     SkASSERT(rect_fits(subset, tex->width(), tex->height()));
-    return sk_make_sp<SkSpecialImage_Gpu>(proxy, subset, uniqueID, tex, at);
+    return sk_make_sp<SkSpecialImage_Gpu>(proxy, subset, uniqueID, tex, at, props);
 }
 
 #else
@@ -550,6 +575,7 @@
                                                   const SkIRect& subset,
                                                   uint32_t uniqueID,
                                                   GrTexture* tex,
+                                                  const SkSurfaceProps* props,
                                                   SkAlphaType at) {
     return nullptr;
 }
diff --git a/src/core/SkSpecialImage.h b/src/core/SkSpecialImage.h
index 4de28eb..57785fa 100644
--- a/src/core/SkSpecialImage.h
+++ b/src/core/SkSpecialImage.h
@@ -10,6 +10,7 @@
 
 #include "SkNextID.h"
 #include "SkRefCnt.h"
+#include "SkSurfaceProps.h"
 
 // remove this when internal_getProxy goes away (see skbug.com/4965)
 #include "SkImageFilter.h"
@@ -47,6 +48,8 @@
     typedef void* ReleaseContext;
     typedef void(*RasterReleaseProc)(void* pixels, ReleaseContext);
 
+    const SkSurfaceProps& props() const { return fProps; }
+
     int width() const { return fSubset.width(); }
     int height() const { return fSubset.height(); }
     const SkIRect& subset() const { return fSubset; }
@@ -69,20 +72,24 @@
 
     static sk_sp<SkSpecialImage> MakeFromImage(SkImageFilter::Proxy*,
                                                const SkIRect& subset,
-                                               sk_sp<SkImage>);
+                                               sk_sp<SkImage>,
+                                               const SkSurfaceProps* = nullptr);
     static sk_sp<SkSpecialImage> MakeFromRaster(SkImageFilter::Proxy*,
                                                 const SkIRect& subset,
-                                                const SkBitmap&);
+                                                const SkBitmap&,
+                                                const SkSurfaceProps* = nullptr);
     static sk_sp<SkSpecialImage> MakeFromGpu(SkImageFilter::Proxy*,
                                              const SkIRect& subset,
                                              uint32_t uniqueID,
                                              GrTexture*,
+                                             const SkSurfaceProps* = nullptr,
                                              SkAlphaType at = kPremul_SkAlphaType);
     static sk_sp<SkSpecialImage> MakeFromPixmap(SkImageFilter::Proxy*,
                                                 const SkIRect& subset,
                                                 const SkPixmap&,
                                                 RasterReleaseProc,
-                                                ReleaseContext);
+                                                ReleaseContext,
+                                                const SkSurfaceProps* = nullptr);
 
     /**
      *  Create a new special surface with a backend that is compatible with this special image.
@@ -110,7 +117,8 @@
 
     // These three internal methods will go away (see skbug.com/4965)
     bool internal_getBM(SkBitmap* result);
-    static sk_sp<SkSpecialImage> internal_fromBM(SkImageFilter::Proxy*, const SkBitmap&);
+    static sk_sp<SkSpecialImage> internal_fromBM(SkImageFilter::Proxy*, const SkBitmap&,
+                                                 const SkSurfaceProps*);
     SkImageFilter::Proxy* internal_getProxy() const;
 
     // TODO: hide this when GrLayerHoister uses SkSpecialImages more fully (see skbug.com/5063)
@@ -135,12 +143,8 @@
     bool peekPixels(SkPixmap*) const;
 
 protected:
-    SkSpecialImage(SkImageFilter::Proxy* proxy, const SkIRect& subset, uint32_t uniqueID)
-        : fSubset(subset)
-        , fUniqueID(kNeedNewImageUniqueID_SpecialImage == uniqueID ? SkNextID::ImageID()
-                                                                   : uniqueID)
-        , fProxy(proxy) {
-    }
+    SkSpecialImage(SkImageFilter::Proxy*, const SkIRect& subset, uint32_t uniqueID,
+                   const SkSurfaceProps*);
 
     // The following 2 are for testing and shouldn't be used.
     friend class TestingSpecialImageAccess;
@@ -154,8 +158,9 @@
     SkImageFilter::Proxy* proxy() const { return fProxy; }
 
 private:
-    const SkIRect   fSubset;
-    const uint32_t  fUniqueID;
+    const SkSurfaceProps fProps;
+    const SkIRect        fSubset;
+    const uint32_t       fUniqueID;
 
     // TODO: remove this ASAP (see skbug.com/4965)
     SkImageFilter::Proxy* fProxy;
diff --git a/src/core/SkSpecialSurface.cpp b/src/core/SkSpecialSurface.cpp
index 2ac71ff..7dced71 100644
--- a/src/core/SkSpecialSurface.cpp
+++ b/src/core/SkSpecialSurface.cpp
@@ -82,7 +82,8 @@
     ~SkSpecialSurface_Raster() override { }
 
     sk_sp<SkSpecialImage> onMakeImageSnapshot() override {
-        return SkSpecialImage::MakeFromRaster(this->proxy(), this->subset(), fBitmap);
+        return SkSpecialImage::MakeFromRaster(this->proxy(), this->subset(), fBitmap,
+                                              &this->props());
     }
 
 private:
@@ -139,7 +140,8 @@
 
     sk_sp<SkSpecialImage> onMakeImageSnapshot() override {
         return SkSpecialImage::MakeFromGpu(this->proxy(), this->subset(),
-                                           kNeedNewImageUniqueID_SpecialImage, fTexture);
+                                           kNeedNewImageUniqueID_SpecialImage, fTexture,
+                                           &this->props());
     }
 
 private:
diff --git a/src/effects/SkBlurImageFilter.cpp b/src/effects/SkBlurImageFilter.cpp
index b7745e2..10c8a0b 100644
--- a/src/effects/SkBlurImageFilter.cpp
+++ b/src/effects/SkBlurImageFilter.cpp
@@ -113,6 +113,7 @@
         SkAutoTUnref<GrTexture> tex(SkGpuBlurUtils::GaussianBlur(inputTexture->getContext(),
                                                                  inputTexture,
                                                                  false,
+                                                                 source->props().allowSRGBInputs(),
                                                                  SkRect::Make(dstBounds),
                                                                  &inputBoundsF,
                                                                  sigma.x(),
@@ -124,7 +125,7 @@
         return SkSpecialImage::MakeFromGpu(source->internal_getProxy(),
                                            SkIRect::MakeWH(dstBounds.width(), dstBounds.height()),
                                            kNeedNewImageUniqueID_SpecialImage,
-                                           tex);
+                                           tex, &source->props());
     }
 #endif
 
@@ -216,7 +217,7 @@
     return SkSpecialImage::MakeFromRaster(source->internal_getProxy(),
                                           SkIRect::MakeWH(dstBounds.width(),
                                                           dstBounds.height()),
-                                          dst);
+                                          dst, &source->props());
 }
 
 
diff --git a/src/effects/SkBlurMaskFilter.cpp b/src/effects/SkBlurMaskFilter.cpp
index bb6a8a5..609e168 100644
--- a/src/effects/SkBlurMaskFilter.cpp
+++ b/src/effects/SkBlurMaskFilter.cpp
@@ -1243,7 +1243,8 @@
     // gaussianBlur.  Otherwise, we need to save it for later compositing.
     bool isNormalBlur = (kNormal_SkBlurStyle == fBlurStyle);
     *result = SkGpuBlurUtils::GaussianBlur(context, src, isNormalBlur && canOverwriteSrc,
-                                           clipRect, nullptr, xformedSigma, xformedSigma);
+                                           false, clipRect, nullptr,
+                                           xformedSigma, xformedSigma);
     if (nullptr == *result) {
         return false;
     }
diff --git a/src/effects/SkDisplacementMapEffect.cpp b/src/effects/SkDisplacementMapEffect.cpp
index 447a20b..6debea1 100644
--- a/src/effects/SkDisplacementMapEffect.cpp
+++ b/src/effects/SkDisplacementMapEffect.cpp
@@ -431,6 +431,7 @@
     ctx.ctm().mapVectors(&scale, 1);
 
     GrPaint paint;
+    // SRGBTODO: AllowSRGBInputs?
     SkMatrix offsetMatrix = GrCoordTransform::MakeDivByTextureWHMatrix(displacement);
     offsetMatrix.preTranslate(SkIntToScalar(colorOffset.fX - displacementOffset.fX),
                               SkIntToScalar(colorOffset.fY - displacementOffset.fY));
diff --git a/src/effects/SkGpuBlurUtils.cpp b/src/effects/SkGpuBlurUtils.cpp
index c43f273..90619f9 100644
--- a/src/effects/SkGpuBlurUtils.cpp
+++ b/src/effects/SkGpuBlurUtils.cpp
@@ -56,6 +56,7 @@
                                  bool useBounds,
                                  float bounds[2]) {
     GrPaint paint;
+    paint.setAllowSRGBInputs(drawContext->allowSRGBInputs());
     SkAutoTUnref<GrFragmentProcessor> conv(GrConvolutionEffect::CreateGaussian(
         texture, direction, radius, sigma, useBounds, bounds));
     paint.addColorFragmentProcessor(conv);
@@ -78,6 +79,7 @@
     SkISize size = SkISize::Make(2 * radiusX + 1,  2 * radiusY + 1);
     SkIPoint kernelOffset = SkIPoint::Make(radiusX, radiusY);
     GrPaint paint;
+    paint.setAllowSRGBInputs(drawContext->allowSRGBInputs());
     SkIRect bounds;
     if (srcBounds) {
         srcBounds->roundOut(&bounds);
@@ -164,6 +166,7 @@
 GrTexture* GaussianBlur(GrContext* context,
                         GrTexture* srcTexture,
                         bool canClobberSrc,
+                        bool allowSRGBInputs,
                         const SkRect& dstBounds,
                         const SkRect* srcBounds,
                         float sigmaX,
@@ -229,6 +232,7 @@
 
     for (int i = 1; i < scaleFactorX || i < scaleFactorY; i *= 2) {
         GrPaint paint;
+        paint.setAllowSRGBInputs(allowSRGBInputs);
         SkMatrix matrix;
         matrix.setIDiv(srcTexture->width(), srcTexture->height());
         SkRect dstRect(srcRect);
@@ -268,6 +272,9 @@
         localSrcBounds = srcRect;
     }
 
+    SkSurfaceProps props(allowSRGBInputs ? SkSurfaceProps::kAllowSRGBInputs_Flag : 0,
+                         SkSurfaceProps::kLegacyFontHost_InitType);
+
     // For really small blurs (certainly no wider than 5x5 on desktop gpus) it is faster to just
     // launch a single non separable kernel vs two launches
     srcRect = localDstBounds;
@@ -277,7 +284,7 @@
         SkASSERT((1 == scaleFactorX) && (1 == scaleFactorY));
 
         SkAutoTUnref<GrDrawContext> dstDrawContext(
-                                             context->drawContext(dstTexture->asRenderTarget()));
+            context->drawContext(dstTexture->asRenderTarget(), &props));
         if (!dstDrawContext) {
             return nullptr;
         }
@@ -311,7 +318,7 @@
             }
 
             SkAutoTUnref<GrDrawContext> dstDrawContext(
-                                             context->drawContext(dstTexture->asRenderTarget()));
+                context->drawContext(dstTexture->asRenderTarget(), &props));
             if (!dstDrawContext) {
                 return nullptr;
             }
@@ -344,7 +351,7 @@
             }
 
             SkAutoTUnref<GrDrawContext> dstDrawContext(
-                                               context->drawContext(dstTexture->asRenderTarget()));
+                context->drawContext(dstTexture->asRenderTarget(), &props));
             if (!dstDrawContext) {
                 return nullptr;
             }
@@ -375,6 +382,7 @@
         matrix.setIDiv(srcTexture->width(), srcTexture->height());
 
         GrPaint paint;
+        paint.setAllowSRGBInputs(allowSRGBInputs);
         // FIXME:  this should be mitchell, not bilinear.
         GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_FilterMode);
         paint.addColorTextureProcessor(srcTexture, matrix, params);
diff --git a/src/effects/SkGpuBlurUtils.h b/src/effects/SkGpuBlurUtils.h
index 013d11b..e81e5da 100644
--- a/src/effects/SkGpuBlurUtils.h
+++ b/src/effects/SkGpuBlurUtils.h
@@ -26,6 +26,7 @@
     * @param srcTexture      The source texture to be blurred.
     * @param canClobberSrc   If true, srcTexture may be overwritten, and
     *                        may be returned as the result.
+    * @param allowSRGBInputs Should sRGB inputs be allowed to perform sRGB to linear conversion.
     * @param dstBounds       The destination bounds, relative to the source texture.
     * @param srcBounds       The source bounds, relative to the source texture. If non-null,
     *                        no pixels will be sampled outside of this rectangle.
@@ -37,6 +38,7 @@
     GrTexture* GaussianBlur(GrContext* context,
                             GrTexture* srcTexture,
                             bool canClobberSrc,
+                            bool allowSRGBInputs,
                             const SkRect& dstBounds,
                             const SkRect* srcBounds,
                             float sigmaX,
diff --git a/src/effects/SkImageSource.cpp b/src/effects/SkImageSource.cpp
index cf8cae2..6a4eb8d 100644
--- a/src/effects/SkImageSource.cpp
+++ b/src/effects/SkImageSource.cpp
@@ -68,11 +68,13 @@
         offset->fX = offset->fY = 0;
         return SkSpecialImage::MakeFromImage(source->internal_getProxy(),
                                              SkIRect::MakeWH(fImage->width(), fImage->height()),
-                                             fImage);
+                                             fImage,
+                                             &source->props());
     }
 
     const SkIRect dstIRect = dstRect.roundOut();
 
+    // SRGBTODO: Propagate SkColorType?
     const SkImageInfo info = SkImageInfo::MakeN32(dstIRect.width(), dstIRect.height(),
                                                   kPremul_SkAlphaType);
 
diff --git a/src/effects/SkLightingImageFilter.cpp b/src/effects/SkLightingImageFilter.cpp
index c27a554..e276dc0 100644
--- a/src/effects/SkLightingImageFilter.cpp
+++ b/src/effects/SkLightingImageFilter.cpp
@@ -387,6 +387,7 @@
                                              const SkIRect& bounds) const {
     SkRect srcRect = dstRect.makeOffset(SkIntToScalar(bounds.x()), SkIntToScalar(bounds.y()));
     GrPaint paint;
+    // SRGBTODO: AllowSRGBInputs?
     GrFragmentProcessor* fp = this->getFragmentProcessor(src, matrix, srcBounds, boundaryMode);
     paint.addColorFragmentProcessor(fp)->unref();
     paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
diff --git a/src/effects/SkMorphologyImageFilter.cpp b/src/effects/SkMorphologyImageFilter.cpp
index ea714e5..616c0d2 100644
--- a/src/effects/SkMorphologyImageFilter.cpp
+++ b/src/effects/SkMorphologyImageFilter.cpp
@@ -370,6 +370,7 @@
                                   float bounds[2],
                                   Gr1DKernelEffect::Direction direction) {
     GrPaint paint;
+    // SRGBTODO: AllowSRGBInputs?
     paint.addColorFragmentProcessor(GrMorphologyEffect::Create(texture,
                                                                direction,
                                                                radius,
@@ -389,6 +390,7 @@
                                             GrMorphologyEffect::MorphologyType morphType,
                                             Gr1DKernelEffect::Direction direction) {
     GrPaint paint;
+    // SRGBTODO: AllowSRGBInputs?
     paint.addColorFragmentProcessor(GrMorphologyEffect::Create(texture,
                                                                direction,
                                                                radius,
@@ -511,7 +513,7 @@
     return SkSpecialImage::MakeFromGpu(input->internal_getProxy(),
                                        SkIRect::MakeWH(rect.width(), rect.height()),
                                        kNeedNewImageUniqueID_SpecialImage,
-                                       srcTexture);
+                                       srcTexture, &input->props());
 }
 #endif
 
@@ -619,5 +621,5 @@
 
     return SkSpecialImage::MakeFromRaster(source->internal_getProxy(),
                                           SkIRect::MakeWH(bounds.width(), bounds.height()),
-                                          dst);
+                                          dst, &source->props());
 }
diff --git a/src/effects/SkXfermodeImageFilter.cpp b/src/effects/SkXfermodeImageFilter.cpp
index a29136a..330f839 100644
--- a/src/effects/SkXfermodeImageFilter.cpp
+++ b/src/effects/SkXfermodeImageFilter.cpp
@@ -174,6 +174,7 @@
     }
 
     GrPaint paint;
+    // SRGBTODO: AllowSRGBInputs?
     SkAutoTUnref<const GrFragmentProcessor> bgFP;
 
     if (backgroundTex) {
diff --git a/src/gpu/GrBlurUtils.cpp b/src/gpu/GrBlurUtils.cpp
index 65b18a5..0dd518f 100644
--- a/src/gpu/GrBlurUtils.cpp
+++ b/src/gpu/GrBlurUtils.cpp
@@ -335,7 +335,8 @@
     }
 
     GrPaint grPaint;
-    if (!SkPaintToGrPaint(context, paint, viewMatrix, &grPaint)) {
+    if (!SkPaintToGrPaint(context, paint, viewMatrix, drawContext->allowSRGBInputs(),
+                          &grPaint)) {
         return;
     }
 
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 1d6bb32..c223a60 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -366,6 +366,8 @@
             if (!drawContext) {
                 return false;
             }
+            // SRGBTODO: AllowSRGBInputs? (We could force it on here, so we don't need the
+            // per-texture override in config conversion effect?)
             GrPaint paint;
             paint.addColorFragmentProcessor(fp);
             paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
@@ -476,6 +478,8 @@
                     GrConfigConversionEffect::kNone_PMConversion, textureMatrix));
             }
             if (fp) {
+                // SRGBTODO: AllowSRGBInputs? (We could force it on here, so we don't need the
+                // per-texture override in config conversion effect?)
                 GrPaint paint;
                 paint.addColorFragmentProcessor(fp);
                 paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
diff --git a/src/gpu/GrLayerHoister.cpp b/src/gpu/GrLayerHoister.cpp
index 80ea3cd..dd8a485 100644
--- a/src/gpu/GrLayerHoister.cpp
+++ b/src/gpu/GrLayerHoister.cpp
@@ -306,7 +306,8 @@
     const SkIRect subset = SkIRect::MakeWH(layer->texture()->width(), layer->texture()->height());
     sk_sp<SkSpecialImage> img(SkSpecialImage::MakeFromGpu(&proxy, subset,
                                                           kNeedNewImageUniqueID_SpecialImage,
-                                                          layer->texture()));
+                                                          layer->texture(),
+                                                          &device->surfaceProps()));
 
     SkIPoint offset = SkIPoint::Make(0, 0);
     sk_sp<SkSpecialImage> result(layer->filter()->filterImage(img.get(),
diff --git a/src/gpu/GrPaint.cpp b/src/gpu/GrPaint.cpp
index af93e8f..f41469e 100644
--- a/src/gpu/GrPaint.cpp
+++ b/src/gpu/GrPaint.cpp
@@ -15,6 +15,7 @@
 GrPaint::GrPaint()
     : fAntiAlias(false)
     , fDisableOutputConversionToSRGB(false)
+    , fAllowSRGBInputs(false)
     , fColor(GrColor_WHITE) {}
 
 void GrPaint::setCoverageSetOpXPFactory(SkRegion::Op regionOp, bool invertCoverage) {
diff --git a/src/gpu/GrPipeline.cpp b/src/gpu/GrPipeline.cpp
index d8e2e5d..55cbf34 100644
--- a/src/gpu/GrPipeline.cpp
+++ b/src/gpu/GrPipeline.cpp
@@ -84,6 +84,9 @@
     if (builder.getDisableOutputConversionToSRGB()) {
         pipeline->fFlags |= kDisableOutputConversionToSRGB_Flag;
     }
+    if (builder.getAllowSRGBInputs()) {
+        pipeline->fFlags |= kAllowSRGBInputs_Flag;
+    }
 
     int firstColorProcessorIdx = args.fOpts.fColorPOI.firstEffectiveProcessorIndex();
 
diff --git a/src/gpu/GrPipeline.h b/src/gpu/GrPipeline.h
index bdcc7d9..f64b875 100644
--- a/src/gpu/GrPipeline.h
+++ b/src/gpu/GrPipeline.h
@@ -148,6 +148,9 @@
     bool getDisableOutputConversionToSRGB() const {
         return SkToBool(fFlags & kDisableOutputConversionToSRGB_Flag);
     }
+    bool getAllowSRGBInputs() const {
+        return SkToBool(fFlags & kAllowSRGBInputs_Flag);
+    }
 
     GrXferBarrierType xferBarrierType(const GrCaps& caps) const {
         return this->getXferProcessor().xferBarrierType(fRenderTarget.get(), caps);
@@ -190,6 +193,7 @@
         kHWAA_Flag                          = 0x1,
         kSnapVertices_Flag                  = 0x2,
         kDisableOutputConversionToSRGB_Flag = 0x4,
+        kAllowSRGBInputs_Flag               = 0x8,
     };
 
     typedef GrPendingIOResource<GrRenderTarget, kWrite_GrIOType> RenderTarget;
diff --git a/src/gpu/GrPipelineBuilder.cpp b/src/gpu/GrPipelineBuilder.cpp
index d82ee1c..252c265 100644
--- a/src/gpu/GrPipelineBuilder.cpp
+++ b/src/gpu/GrPipelineBuilder.cpp
@@ -46,6 +46,8 @@
                    rt->isUnifiedMultisampled() && paint.isAntiAlias());
     this->setState(GrPipelineBuilder::kDisableOutputConversionToSRGB_Flag,
                    paint.getDisableOutputConversionToSRGB());
+    this->setState(GrPipelineBuilder::kAllowSRGBInputs_Flag,
+                   paint.getAllowSRGBInputs());
 }
 
 //////////////////////////////////////////////////////////////////////////////s
diff --git a/src/gpu/GrPipelineBuilder.h b/src/gpu/GrPipelineBuilder.h
index 4190070..08ac5db 100644
--- a/src/gpu/GrPipelineBuilder.h
+++ b/src/gpu/GrPipelineBuilder.h
@@ -288,7 +288,12 @@
          */
         kDisableOutputConversionToSRGB_Flag = 0x04,
 
-        kLast_Flag = kDisableOutputConversionToSRGB_Flag,
+        /**
+         * Allow sRGB -> linear conversion when reading from sRGB inputs.
+         */
+        kAllowSRGBInputs_Flag = 0x08,
+
+        kLast_Flag = kAllowSRGBInputs_Flag,
     };
 
     bool isHWAntialias() const { return SkToBool(fFlags & kHWAntialias_Flag); }
@@ -296,6 +301,8 @@
         return SkToBool(fFlags & kSnapVerticesToPixelCenters_Flag); }
     bool getDisableOutputConversionToSRGB() const {
         return SkToBool(fFlags & kDisableOutputConversionToSRGB_Flag); }
+    bool getAllowSRGBInputs() const {
+        return SkToBool(fFlags & kAllowSRGBInputs_Flag); }
 
     /**
      * Enable render state settings.
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index d0c526b..d972741 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -396,7 +396,8 @@
     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPaint", fContext);
 
     GrPaint grPaint;
-    if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) {
+    if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix,
+                          this->surfaceProps().allowSRGBInputs(), &grPaint)) {
         return;
     }
 
@@ -446,7 +447,8 @@
     if (paint.getPathEffect() && 2 == count && SkCanvas::kLines_PointMode == mode) {
         GrStrokeInfo strokeInfo(paint, SkPaint::kStroke_Style);
         GrPaint grPaint;
-        if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) {
+        if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix,
+                              this->surfaceProps().allowSRGBInputs(), &grPaint)) {
             return;
         }
         SkPath path;
@@ -466,7 +468,8 @@
     }
 
     GrPaint grPaint;
-    if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) {
+    if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix,
+                          this->surfaceProps().allowSRGBInputs(), &grPaint)) {
         return;
     }
 
@@ -518,7 +521,8 @@
     }
 
     GrPaint grPaint;
-    if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) {
+    if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix,
+                          this->surfaceProps().allowSRGBInputs(), &grPaint)) {
         return;
     }
 
@@ -536,7 +540,8 @@
     CHECK_SHOULD_DRAW(draw);
 
     GrPaint grPaint;
-    if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) {
+    if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix,
+                          this->surfaceProps().allowSRGBInputs(), &grPaint)) {
         return;
     }
 
@@ -611,7 +616,8 @@
 
     if (stroke.isFillStyle() && !paint.getMaskFilter() && !paint.getPathEffect()) {
         GrPaint grPaint;
-        if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) {
+        if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix,
+                              this->surfaceProps().allowSRGBInputs(), &grPaint)) {
             return;
         }
 
@@ -655,7 +661,8 @@
     }
 
     GrPaint grPaint;
-    if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) {
+    if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix,
+                          this->surfaceProps().allowSRGBInputs(), &grPaint)) {
         return;
     }
 
@@ -1139,7 +1146,8 @@
 
     GrPaint grPaint;
     if (!SkPaintToGrPaintWithTexture(this->context(), paint, viewMatrix, fp,
-                                     kAlpha_8_SkColorType == bitmap.colorType(), &grPaint)) {
+                                     kAlpha_8_SkColorType == bitmap.colorType(),
+                                     this->surfaceProps().allowSRGBInputs(), &grPaint)) {
         return;
     }
 
@@ -1233,7 +1241,8 @@
     } else {
         fp.reset(GrFragmentProcessor::MulOutputByInputAlpha(fp));
     }
-    if (!SkPaintToGrPaintReplaceShader(this->context(), paint, fp, &grPaint)) {
+    if (!SkPaintToGrPaintReplaceShader(this->context(), paint, fp,
+                                       this->surfaceProps().allowSRGBInputs(), &grPaint)) {
         return;
     }
 
@@ -1393,7 +1402,8 @@
         fp.reset(GrFragmentProcessor::MulOutputByInputAlpha(fp));
     }
 
-    if (!SkPaintToGrPaintReplaceShader(this->context(), paint, fp, &grPaint)) {
+    if (!SkPaintToGrPaintReplaceShader(this->context(), paint, fp,
+                                       this->surfaceProps().allowSRGBInputs(), &grPaint)) {
         return;
     }
 
@@ -1532,7 +1542,8 @@
                                           &kMode));
     GrPaint grPaint;
     if (!SkPaintToGrPaintWithTexture(this->context(), paint, *draw.fMatrix, fp,
-                                     producer->isAlphaOnly(), &grPaint)) {
+                                     producer->isAlphaOnly(),
+                                     this->surfaceProps().allowSRGBInputs(), &grPaint)) {
         return;
     }
 
@@ -1599,7 +1610,8 @@
 
         GrPaint grPaint;
         // we ignore the shader if texs is null.
-        if (!SkPaintToGrPaintNoShader(this->context(), copy, &grPaint)) {
+        if (!SkPaintToGrPaintNoShader(this->context(), copy,
+                                      this->surfaceProps().allowSRGBInputs(), &grPaint)) {
             return;
         }
 
@@ -1671,12 +1683,14 @@
                 colorMode = SkXfermode::kModulate_Mode;
             }
             if (!SkPaintToGrPaintWithXfermode(this->context(), paint, *draw.fMatrix, colorMode,
-                                              false, &grPaint)) {
+                                              false, this->surfaceProps().allowSRGBInputs(),
+                                              &grPaint)) {
                 return;
             }
         } else {
             // We have a shader, but no colors to blend it against.
-            if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) {
+            if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix,
+                                  this->surfaceProps().allowSRGBInputs(), &grPaint)) {
                 return;
             }
         }
@@ -1684,12 +1698,15 @@
         if (colors) {
             // We have colors, but either have no shader or no texture coords (which implies that
             // we should ignore the shader).
-            if (!SkPaintToGrPaintWithPrimitiveColor(this->context(), paint, &grPaint)) {
+            if (!SkPaintToGrPaintWithPrimitiveColor(this->context(), paint,
+                                                    this->surfaceProps().allowSRGBInputs(),
+                                                    &grPaint)) {
                 return;
             }
         } else {
             // No colors and no shaders. Just draw with the paint color.
-            if (!SkPaintToGrPaintNoShader(this->context(), paint, &grPaint)) {
+            if (!SkPaintToGrPaintNoShader(this->context(), paint,
+                                          this->surfaceProps().allowSRGBInputs(), &grPaint)) {
                 return;
             }
         }
@@ -1727,11 +1744,12 @@
     GrPaint grPaint;
     if (colors) {
         if (!SkPaintToGrPaintWithXfermode(this->context(), p, *draw.fMatrix, mode, true,
-                                          &grPaint)) {
+                                          this->surfaceProps().allowSRGBInputs(), &grPaint)) {
             return;
         }
     } else {
-        if (!SkPaintToGrPaint(this->context(), p, *draw.fMatrix, &grPaint)) {
+        if (!SkPaintToGrPaint(this->context(), p, *draw.fMatrix,
+                              this->surfaceProps().allowSRGBInputs(), &grPaint)) {
             return;
         }
     }
@@ -1750,7 +1768,8 @@
     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawText", fContext);
 
     GrPaint grPaint;
-    if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) {
+    if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix,
+                          this->surfaceProps().allowSRGBInputs(), &grPaint)) {
         return;
     }
 
@@ -1768,7 +1787,8 @@
     CHECK_SHOULD_DRAW(draw);
 
     GrPaint grPaint;
-    if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix, &grPaint)) {
+    if (!SkPaintToGrPaint(this->context(), paint, *draw.fMatrix,
+                          this->surfaceProps().allowSRGBInputs(), &grPaint)) {
         return;
     }
 
diff --git a/src/gpu/SkGpuDevice_drawTexture.cpp b/src/gpu/SkGpuDevice_drawTexture.cpp
index 1be2dd5..8464895 100644
--- a/src/gpu/SkGpuDevice_drawTexture.cpp
+++ b/src/gpu/SkGpuDevice_drawTexture.cpp
@@ -206,7 +206,7 @@
 
     GrPaint grPaint;
     if (!SkPaintToGrPaintWithTexture(fContext, paint, viewMatrix, fp, producer->isAlphaOnly(),
-                                     &grPaint)) {
+                                     this->surfaceProps().allowSRGBInputs(), &grPaint)) {
         return;
     }
 
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index 905af81..7169091 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -495,8 +495,10 @@
                                            const GrFragmentProcessor** shaderProcessor,
                                            SkXfermode::Mode* primColorMode,
                                            bool primitiveIsSrc,
+                                           bool allowSRGBInputs,
                                            GrPaint* grPaint) {
     grPaint->setAntiAlias(skPaint.isAntiAlias());
+    grPaint->setAllowSRGBInputs(allowSRGBInputs);
 
     // Setup the initial color considering the shader, the SkPaint color, and the presence or not
     // of per-vertex colors.
@@ -623,31 +625,34 @@
 }
 
 bool SkPaintToGrPaint(GrContext* context, const SkPaint& skPaint, const SkMatrix& viewM,
-                      GrPaint* grPaint) {
-    return skpaint_to_grpaint_impl(context, skPaint, viewM, nullptr, nullptr, false, grPaint);
+                      bool allowSRGBInputs, GrPaint* grPaint) {
+    return skpaint_to_grpaint_impl(context, skPaint, viewM, nullptr, nullptr, false,
+                                   allowSRGBInputs, grPaint);
 }
 
 /** Replaces the SkShader (if any) on skPaint with the passed in GrFragmentProcessor. */
 bool SkPaintToGrPaintReplaceShader(GrContext* context,
                                    const SkPaint& skPaint,
                                    const GrFragmentProcessor* shaderFP,
+                                   bool allowSRGBInputs,
                                    GrPaint* grPaint) {
     if (!shaderFP) {
         return false;
     }
     return skpaint_to_grpaint_impl(context, skPaint, SkMatrix::I(), &shaderFP, nullptr, false,
-                                   grPaint);
+                                   allowSRGBInputs, grPaint);
 }
 
 /** Ignores the SkShader (if any) on skPaint. */
 bool SkPaintToGrPaintNoShader(GrContext* context,
                               const SkPaint& skPaint,
+                              bool allowSRGBInputs,
                               GrPaint* grPaint) {
     // Use a ptr to a nullptr to to indicate that the SkShader is ignored and not replaced.
     static const GrFragmentProcessor* kNullShaderFP = nullptr;
     static const GrFragmentProcessor** kIgnoreShader = &kNullShaderFP;
     return skpaint_to_grpaint_impl(context, skPaint, SkMatrix::I(), kIgnoreShader, nullptr, false,
-                                   grPaint);
+                                   allowSRGBInputs, grPaint);
 }
 
 /** Blends the SkPaint's shader (or color if no shader) with a per-primitive color which must
@@ -657,9 +662,10 @@
                                   const SkMatrix& viewM,
                                   SkXfermode::Mode primColorMode,
                                   bool primitiveIsSrc,
+                                  bool allowSRGBInputs,
                                   GrPaint* grPaint) {
     return skpaint_to_grpaint_impl(context, skPaint, viewM, nullptr, &primColorMode, primitiveIsSrc,
-                                   grPaint);
+                                   allowSRGBInputs, grPaint);
 }
 
 bool SkPaintToGrPaintWithTexture(GrContext* context,
@@ -667,6 +673,7 @@
                                  const SkMatrix& viewM,
                                  const GrFragmentProcessor* fp,
                                  bool textureIsAlphaOnly,
+                                 bool allowSRGBInputs,
                                  GrPaint* grPaint) {
     SkAutoTUnref<const GrFragmentProcessor> shaderFP;
     if (textureIsAlphaOnly) {
@@ -687,7 +694,7 @@
         shaderFP.reset(GrFragmentProcessor::MulOutputByInputAlpha(fp));
     }
 
-    return SkPaintToGrPaintReplaceShader(context, paint, shaderFP.get(), grPaint);
+    return SkPaintToGrPaintReplaceShader(context, paint, shaderFP.get(), allowSRGBInputs, grPaint);
 }
 
 
diff --git a/src/gpu/SkGrPriv.h b/src/gpu/SkGrPriv.h
index f43a4e9..46be3a5 100644
--- a/src/gpu/SkGrPriv.h
+++ b/src/gpu/SkGrPriv.h
@@ -48,11 +48,13 @@
 bool SkPaintToGrPaint(GrContext*,
                       const SkPaint& skPaint,
                       const SkMatrix& viewM,
+                      bool allowSRGBInputs,
                       GrPaint* grPaint);
 
 /** Same as above but ignores the SkShader (if any) on skPaint. */
 bool SkPaintToGrPaintNoShader(GrContext* context,
                               const SkPaint& skPaint,
+                              bool allowSRGBInputs,
                               GrPaint* grPaint);
 
 /** Replaces the SkShader (if any) on skPaint with the passed in GrFragmentProcessor. The processor
@@ -61,6 +63,7 @@
 bool SkPaintToGrPaintReplaceShader(GrContext*,
                                    const SkPaint& skPaint,
                                    const GrFragmentProcessor* shaderFP,
+                                   bool allowSRGBInputs,
                                    GrPaint* grPaint);
 
 /** Blends the SkPaint's shader (or color if no shader) with the color which specified via a
@@ -72,6 +75,7 @@
                                   const SkMatrix& viewM,
                                   SkXfermode::Mode primColorMode,
                                   bool primitiveIsSrc,
+                                  bool allowSRGBInputs,
                                   GrPaint* grPaint);
 
 /** This is used when there is a primitive color, but the shader should be ignored. Currently,
@@ -79,9 +83,9 @@
     unpremultiplied so that interpolation is done in unpremul space. The paint's alpha will be
     applied to the primitive color after interpolation. */
 inline bool SkPaintToGrPaintWithPrimitiveColor(GrContext* context, const SkPaint& skPaint,
-                                               GrPaint* grPaint) {
+                                               bool allowSRGBInputs, GrPaint* grPaint) {
     return SkPaintToGrPaintWithXfermode(context, skPaint, SkMatrix::I(), SkXfermode::kDst_Mode,
-                                        false, grPaint);
+                                        false, allowSRGBInputs, grPaint);
 }
 
 /** This is used when there may or may not be a shader, and the caller wants to plugin a texture
@@ -91,6 +95,7 @@
                                  const SkMatrix& viewM,
                                  const GrFragmentProcessor* fp,
                                  bool textureIsAlphaOnly,
+                                 bool allowSRGBInputs,
                                  GrPaint* grPaint);
 
 //////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/gl/GrGLGpu.cpp b/src/gpu/gl/GrGLGpu.cpp
index c8c12a3..0063b3d 100644
--- a/src/gpu/gl/GrGLGpu.cpp
+++ b/src/gpu/gl/GrGLGpu.cpp
@@ -2051,15 +2051,13 @@
     SkSTArray<8, const GrTextureAccess*> textureAccesses;
     program->setData(primProc, pipeline, &textureAccesses);
 
-    GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(pipeline.getRenderTarget());
-    bool allowSRGB = GrAllowSRGBForDestinationPixelConfig(glRT->config());
-
     int numTextureAccesses = textureAccesses.count();
     for (int i = 0; i < numTextureAccesses; i++) {
-        this->bindTexture(i, textureAccesses[i]->getParams(), allowSRGB,
+        this->bindTexture(i, textureAccesses[i]->getParams(), pipeline.getAllowSRGBInputs(),
                           static_cast<GrGLTexture*>(textureAccesses[i]->getTexture()));
     }
 
+    GrGLRenderTarget* glRT = static_cast<GrGLRenderTarget*>(pipeline.getRenderTarget());
     this->flushStencil(pipeline.getStencil());
     this->flushScissor(pipeline.getScissorState(), glRT->getViewport(), glRT->origin());
     this->flushHWAAState(glRT, pipeline.isHWAntialiasState(), !pipeline.getStencil().isDisabled());
diff --git a/src/gpu/text/GrAtlasTextContext.cpp b/src/gpu/text/GrAtlasTextContext.cpp
index ec9e40c..918d6d2 100644
--- a/src/gpu/text/GrAtlasTextContext.cpp
+++ b/src/gpu/text/GrAtlasTextContext.cpp
@@ -112,7 +112,7 @@
     // Though for the time being runs in the textblob can override the paint, they only touch font
     // info.
     GrPaint grPaint;
-    if (!SkPaintToGrPaint(context, skPaint, viewMatrix, &grPaint)) {
+    if (!SkPaintToGrPaint(context, skPaint, viewMatrix, props.allowSRGBInputs(), &grPaint)) {
         return;
     }
 
@@ -382,7 +382,8 @@
     skPaint.setSubpixelText(random->nextBool());
 
     GrPaint grPaint;
-    if (!SkPaintToGrPaint(context, skPaint, viewMatrix, &grPaint)) {
+    if (!SkPaintToGrPaint(context, skPaint, viewMatrix, gSurfaceProps.allowSRGBInputs(),
+                          &grPaint)) {
         SkFAIL("couldn't convert paint\n");
     }
 
diff --git a/src/gpu/text/GrStencilAndCoverTextContext.cpp b/src/gpu/text/GrStencilAndCoverTextContext.cpp
index 4c2a615..151858b 100644
--- a/src/gpu/text/GrStencilAndCoverTextContext.cpp
+++ b/src/gpu/text/GrStencilAndCoverTextContext.cpp
@@ -165,7 +165,7 @@
         runPaint.setFlags(GrTextUtils::FilterTextFlags(props, runPaint));
 
         GrPaint grPaint;
-        if (!SkPaintToGrPaint(context, runPaint, viewMatrix, &grPaint)) {
+        if (!SkPaintToGrPaint(context, runPaint, viewMatrix, dc->allowSRGBInputs(), &grPaint)) {
             return;
         }
 
@@ -220,7 +220,7 @@
     }
 
     GrPaint paint;
-    if (!SkPaintToGrPaint(context, skPaint, viewMatrix, &paint)) {
+    if (!SkPaintToGrPaint(context, skPaint, viewMatrix, dc->allowSRGBInputs(), &paint)) {
         return;
     }
 
diff --git a/src/views/SkWindow.cpp b/src/views/SkWindow.cpp
index 481a1f9..bcc7b02 100644
--- a/src/views/SkWindow.cpp
+++ b/src/views/SkWindow.cpp
@@ -70,6 +70,13 @@
 void SkWindow::setColorType(SkColorType ct, SkColorProfileType pt) {
     const SkImageInfo& info = fBitmap.info();
     this->resize(SkImageInfo::Make(info.width(), info.height(), ct, kPremul_SkAlphaType, pt));
+
+    // Set the global flag that enables or disables "legacy" mode, depending on our format.
+    // With sRGB 32-bit or linear FP 16, we turn on gamma-correct handling of inputs:
+    SkSurfaceProps props = this->getSurfaceProps();
+    uint32_t flags = (props.flags() & ~SkSurfaceProps::kAllowSRGBInputs_Flag) |
+        (SkColorAndProfileAreGammaCorrect(ct, pt) ? SkSurfaceProps::kAllowSRGBInputs_Flag : 0);
+    this->setSurfaceProps(SkSurfaceProps(flags, props.pixelGeometry()));
 }
 
 bool SkWindow::handleInval(const SkRect* localR) {
@@ -333,9 +340,7 @@
     //
     // Also, we may not have real sRGB support (ANGLE, in particular), so check for
     // that, and fall back to L32:
-    desc.fConfig = grContext->caps()->srgbSupport() &&
-                   (info().profileType() == kSRGB_SkColorProfileType ||
-                    info().colorType() == kRGBA_F16_SkColorType)
+    desc.fConfig = grContext->caps()->srgbSupport() && SkImageInfoIsGammaCorrect(info())
         ? kSkiaGamma8888_GrPixelConfig
         : kSkia8888_GrPixelConfig;
     desc.fOrigin = kBottomLeft_GrSurfaceOrigin;