Add GrColorSpaceInfo and use in place of GrRenderTargetContext in paint conversion.

This moves us closer to making GrAtlasTextContext and related classes usable without a GrRenderTargetContext.

Change-Id: Ife52d69a3f925e23da88043acb4d8dc9f672a025
Reviewed-on: https://skia-review.googlesource.com/63304
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/src/gpu/GrBlurUtils.cpp b/src/gpu/GrBlurUtils.cpp
index c085673..68fd9f3 100644
--- a/src/gpu/GrBlurUtils.cpp
+++ b/src/gpu/GrBlurUtils.cpp
@@ -291,7 +291,8 @@
     SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
 
     GrPaint grPaint;
-    if (!SkPaintToGrPaint(context, renderTargetContext, paint, viewMatrix, &grPaint)) {
+    if (!SkPaintToGrPaint(context, renderTargetContext->colorSpaceInfo(), paint, viewMatrix,
+                          &grPaint)) {
         return;
     }
     GrAA aa = GrBoolToAA(paint.isAntiAlias());
diff --git a/src/gpu/GrColorSpaceInfo.cpp b/src/gpu/GrColorSpaceInfo.cpp
new file mode 100644
index 0000000..1cb8430
--- /dev/null
+++ b/src/gpu/GrColorSpaceInfo.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrColorSpaceInfo.h"
+
+GrColorSpaceInfo::GrColorSpaceInfo(sk_sp<SkColorSpace> colorSpace, GrPixelConfig config)
+        : fColorSpace(std::move(colorSpace))
+        , fConfig(config)
+        , fInitializedColorSpaceXformFromSRGB(false) {}
+
+GrColorSpaceXform* GrColorSpaceInfo::colorSpaceXformFromSRGB() const {
+    // TODO: Make this atomic if we start accessing this on multiple threads.
+    if (!fInitializedColorSpaceXformFromSRGB) {
+        // sRGB sources are very common (SkColor, etc...), so we cache that gamut transformation
+        auto srgbColorSpace = SkColorSpace::MakeSRGB();
+        fColorXformFromSRGB = GrColorSpaceXform::Make(srgbColorSpace.get(), fColorSpace.get());
+        fInitializedColorSpaceXformFromSRGB = true;
+    }
+    return fColorXformFromSRGB.get();
+}
diff --git a/src/gpu/GrColorSpaceInfo.h b/src/gpu/GrColorSpaceInfo.h
new file mode 100644
index 0000000..42a61b0
--- /dev/null
+++ b/src/gpu/GrColorSpaceInfo.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrColorSpaceInfo_DEFINED
+#define GrColorSpaceInfo_DEFINED
+
+#include "GrColorSpaceXform.h"
+#include "GrTypes.h"
+#include "SkColorSpace.h"
+#include "SkRefCnt.h"
+
+/** Describes the color space properties of a surface context. */
+class GrColorSpaceInfo {
+public:
+    GrColorSpaceInfo(sk_sp<SkColorSpace>, GrPixelConfig);
+
+    bool isGammaCorrect() const { return static_cast<bool>(fColorSpace); }
+
+    SkColorSpace* colorSpace() const { return fColorSpace.get(); }
+    sk_sp<SkColorSpace> refColorSpace() const { return fColorSpace; }
+
+    GrColorSpaceXform* colorSpaceXformFromSRGB() const;
+    sk_sp<GrColorSpaceXform> refColorSpaceXformFromSRGB() const {
+        return sk_ref_sp(this->colorSpaceXformFromSRGB());
+    }
+
+    // TODO: Remove or replace with SkColorType
+    GrPixelConfig config() const { return fConfig; }
+
+private:
+    sk_sp<SkColorSpace> fColorSpace;
+    mutable sk_sp<GrColorSpaceXform> fColorXformFromSRGB;
+    GrPixelConfig fConfig;
+    mutable bool fInitializedColorSpaceXformFromSRGB;
+};
+
+#endif
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index ab57456..f4f1d6c 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -435,9 +435,8 @@
     // We need to guarantee round-trip conversion if we are reading and writing 8888 non-sRGB data,
     // without any color spaces attached, and the caller wants us to premul.
     bool useConfigConversionEffect =
-                        premul &&
-                        pm_upm_must_round_trip(srcConfig, srcColorSpace) &&
-                        pm_upm_must_round_trip(dstProxy->config(), dst->getColorSpace());
+            premul && pm_upm_must_round_trip(srcConfig, srcColorSpace) &&
+            pm_upm_must_round_trip(dstProxy->config(), dst->colorSpaceInfo().colorSpace());
 
     // Are we going to try to premul as part of a draw? For the non-legacy case, we always allow
     // this. GrConfigConversionEffect fails on some GPUs, so only allow this if it works perfectly.
@@ -524,8 +523,8 @@
         GrPaint paint;
         paint.addColorFragmentProcessor(std::move(fp));
         paint.setPorterDuffXPFactory(SkBlendMode::kSrc);
-        paint.setAllowSRGBInputs(SkToBool(dst->getColorSpace()) ||
-                                 GrPixelConfigIsSRGB(renderTargetContext->config()));
+        paint.setAllowSRGBInputs(dst->colorSpaceInfo().isGammaCorrect() ||
+                                 GrPixelConfigIsSRGB(dst->colorSpaceInfo().config()));
         SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
         renderTargetContext->drawRect(GrNoClip(), std::move(paint), GrAA::kNo, matrix, rect,
                                         nullptr);
@@ -569,9 +568,9 @@
     // We need to guarantee round-trip conversion if we are reading and writing 8888 non-sRGB data,
     // without any color spaces attached, and the caller wants us to unpremul.
     bool useConfigConversionEffect =
-                    unpremul &&
-                    pm_upm_must_round_trip(srcProxy->config(), src->getColorSpace()) &&
-                    pm_upm_must_round_trip(dstConfig, dstColorSpace);
+            unpremul &&
+            pm_upm_must_round_trip(srcProxy->config(), src->colorSpaceInfo().colorSpace()) &&
+            pm_upm_must_round_trip(dstConfig, dstColorSpace);
 
     // Are we going to try to unpremul as part of a draw? For the non-legacy case, we always allow
     // this. GrConfigConversionEffect fails on some GPUs, so only allow this if it works perfectly.
diff --git a/src/gpu/GrRenderTargetContext.cpp b/src/gpu/GrRenderTargetContext.cpp
index 1e13b8b..49d6474 100644
--- a/src/gpu/GrRenderTargetContext.cpp
+++ b/src/gpu/GrRenderTargetContext.cpp
@@ -113,19 +113,13 @@
                                              GrAuditTrail* auditTrail,
                                              GrSingleOwner* singleOwner,
                                              bool managedOpList)
-    : GrSurfaceContext(context, drawingMgr, std::move(colorSpace), auditTrail, singleOwner)
-    , fRenderTargetProxy(std::move(rtp))
-    , fOpList(sk_ref_sp(fRenderTargetProxy->getLastRenderTargetOpList()))
-    , fInstancedPipelineInfo(fRenderTargetProxy.get())
-    , fColorXformFromSRGB(nullptr)
-    , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps))
-    , fManagedOpList(managedOpList) {
-    if (fColorSpace) {
-        // sRGB sources are very common (SkColor, etc...), so we cache that gamut transformation
-        auto srgbColorSpace = SkColorSpace::MakeSRGB();
-        fColorXformFromSRGB = GrColorSpaceXform::Make(srgbColorSpace.get(), fColorSpace.get());
-    }
-
+        : GrSurfaceContext(context, drawingMgr, rtp->config(), std::move(colorSpace), auditTrail,
+                           singleOwner)
+        , fRenderTargetProxy(std::move(rtp))
+        , fOpList(sk_ref_sp(fRenderTargetProxy->getLastRenderTargetOpList()))
+        , fInstancedPipelineInfo(fRenderTargetProxy.get())
+        , fSurfaceProps(SkSurfacePropsCopyOrDefault(surfaceProps))
+        , fManagedOpList(managedOpList) {
 #ifndef MDB_ALLOC_RESOURCES
     // MDB TODO: to ensure all resources still get allocated in the correct order in the hybrid
     // world we need to get the correct opList here so that it, in turn, can grab and hold
@@ -779,7 +773,7 @@
         return;
     }
 
-    bool allowSRGB = SkToBool(this->getColorSpace());
+    bool allowSRGB = SkToBool(this->colorSpaceInfo().colorSpace());
     this->addDrawOp(clip, GrTextureOp::Make(std::move(proxy), filter, color, clippedSrcRect,
                                             clippedDstRect, viewMatrix, std::move(colorSpaceXform),
                                             allowSRGB));
@@ -856,9 +850,10 @@
 
     SkASSERT(vertices);
     GrAAType aaType = this->chooseAAType(GrAA::kNo, GrAllowMixedSamples::kNo);
-    std::unique_ptr<GrDrawOp> op =
-            GrDrawVerticesOp::Make(std::move(paint), std::move(vertices), viewMatrix, aaType,
-                                   this->isGammaCorrect(), fColorXformFromSRGB, overridePrimType);
+    std::unique_ptr<GrDrawOp> op = GrDrawVerticesOp::Make(
+            std::move(paint), std::move(vertices), viewMatrix, aaType,
+            this->colorSpaceInfo().isGammaCorrect(),
+            this->colorSpaceInfo().refColorSpaceXformFromSRGB(), overridePrimType);
     this->addDrawOp(clip, std::move(op));
 }
 
@@ -1611,17 +1606,16 @@
     GrPaint paint;
     paint.setCoverageSetOpXPFactory(op, invert);
 
-    GrPathRenderer::DrawPathArgs args{
-            fRenderTargetContext->drawingManager()->getContext(),
-            std::move(paint),
-            ss,
-            fRenderTargetContext,
-            &clip,
-            &clipConservativeBounds,
-            &viewMatrix,
-            &shape,
-            aaType,
-            fRenderTargetContext->isGammaCorrect()};
+    GrPathRenderer::DrawPathArgs args{fRenderTargetContext->drawingManager()->getContext(),
+                                      std::move(paint),
+                                      ss,
+                                      fRenderTargetContext,
+                                      &clip,
+                                      &clipConservativeBounds,
+                                      &viewMatrix,
+                                      &shape,
+                                      aaType,
+                                      fRenderTargetContext->colorSpaceInfo().isGammaCorrect()};
     pr->drawPath(args);
     return true;
 }
@@ -1723,7 +1717,7 @@
                                       &viewMatrix,
                                       &shape,
                                       aaType,
-                                      this->isGammaCorrect()};
+                                      this->colorSpaceInfo().isGammaCorrect()};
     pr->drawPath(args);
 }
 
@@ -1779,7 +1773,8 @@
         this->setNeedsStencil();
     }
 
-    GrPixelConfigIsClamped dstIsClamped = GrGetPixelConfigIsClamped(this->config());
+    GrPixelConfigIsClamped dstIsClamped =
+            GrGetPixelConfigIsClamped(this->colorSpaceInfo().config());
     GrXferProcessor::DstProxy dstProxy;
     if (GrDrawOp::RequiresDstTexture::kYes == op->finalize(*this->caps(), &appliedClip,
                                                            dstIsClamped)) {
diff --git a/src/gpu/GrRenderTargetContext.h b/src/gpu/GrRenderTargetContext.h
index 0ab1ee0..ea705db 100644
--- a/src/gpu/GrRenderTargetContext.h
+++ b/src/gpu/GrRenderTargetContext.h
@@ -331,11 +331,9 @@
     const GrCaps* caps() const { return fContext->caps(); }
     int width() const { return fRenderTargetProxy->width(); }
     int height() const { return fRenderTargetProxy->height(); }
-    GrPixelConfig config() const { return fRenderTargetProxy->config(); }
     int numColorSamples() const { return fRenderTargetProxy->numColorSamples(); }
     int numStencilSamples() const { return fRenderTargetProxy->numStencilSamples(); }
     const SkSurfaceProps& surfaceProps() const { return fSurfaceProps; }
-    GrColorSpaceXform* getColorXformFromSRGB() const { return fColorXformFromSRGB.get(); }
     GrSurfaceOrigin origin() const { return fRenderTargetProxy->origin(); }
     GrMipMapped mipMapped() const;
 
@@ -451,7 +449,6 @@
     sk_sp<GrRenderTargetOpList>       fOpList;
     GrInstancedPipelineInfo           fInstancedPipelineInfo;
 
-    sk_sp<GrColorSpaceXform>          fColorXformFromSRGB;
     SkSurfaceProps                    fSurfaceProps;
     bool                              fManagedOpList;
 
diff --git a/src/gpu/GrSurfaceContext.cpp b/src/gpu/GrSurfaceContext.cpp
index 52ace3f..abd77b9 100644
--- a/src/gpu/GrSurfaceContext.cpp
+++ b/src/gpu/GrSurfaceContext.cpp
@@ -25,15 +25,16 @@
 // when the renderTargetContext attempts to use it (via getOpList).
 GrSurfaceContext::GrSurfaceContext(GrContext* context,
                                    GrDrawingManager* drawingMgr,
+                                   GrPixelConfig config,
                                    sk_sp<SkColorSpace> colorSpace,
                                    GrAuditTrail* auditTrail,
                                    GrSingleOwner* singleOwner)
-    : fContext(context)
-    , fColorSpace(std::move(colorSpace))
-    , fAuditTrail(auditTrail)
-    , fDrawingManager(drawingMgr)
+        : fContext(context)
+        , fAuditTrail(auditTrail)
+        , fColorSpaceInfo(std::move(colorSpace), config)
+        , fDrawingManager(drawingMgr)
 #ifdef SK_DEBUG
-    , fSingleOwner(singleOwner)
+        , fSingleOwner(singleOwner)
 #endif
 {
 }
diff --git a/src/gpu/GrSurfaceContext.h b/src/gpu/GrSurfaceContext.h
index 0511fb1..c499d09 100644
--- a/src/gpu/GrSurfaceContext.h
+++ b/src/gpu/GrSurfaceContext.h
@@ -9,7 +9,7 @@
 #define GrSurfaceContext_DEFINED
 
 #include "../private/GrSurfaceProxy.h"
-
+#include "GrColorSpaceInfo.h"
 #include "SkRefCnt.h"
 
 class GrAuditTrail;
@@ -33,9 +33,7 @@
 public:
     ~GrSurfaceContext() override {}
 
-    SkColorSpace* getColorSpace() const { return fColorSpace.get(); }
-    sk_sp<SkColorSpace> refColorSpace() const { return fColorSpace; }
-    bool isGammaCorrect() const { return static_cast<bool>(fColorSpace); }
+    const GrColorSpaceInfo& colorSpaceInfo() const { return fColorSpaceInfo; }
 
     // TODO: these two calls would be way cooler if this object had a GrSurfaceProxy pointer
     int width() const { return this->asSurfaceProxy()->width(); }
@@ -113,8 +111,8 @@
 protected:
     friend class GrSurfaceContextPriv;
 
-    GrSurfaceContext(GrContext*, GrDrawingManager*,
-                     sk_sp<SkColorSpace>, GrAuditTrail*, GrSingleOwner*);
+    GrSurfaceContext(GrContext*, GrDrawingManager*, GrPixelConfig, sk_sp<SkColorSpace>,
+                     GrAuditTrail*, GrSingleOwner*);
 
     GrDrawingManager* drawingManager() { return fDrawingManager; }
     const GrDrawingManager* drawingManager() const { return fDrawingManager; }
@@ -124,12 +122,13 @@
 
     SkDEBUGCODE(GrSingleOwner* singleOwner() { return fSingleOwner; })
 
-    GrContext*            fContext;
-    sk_sp<SkColorSpace>   fColorSpace;
-    GrAuditTrail*         fAuditTrail;
+    GrContext* fContext;
+    GrAuditTrail* fAuditTrail;
 
 private:
-    GrDrawingManager*     fDrawingManager;
+    GrColorSpaceInfo fColorSpaceInfo;
+
+    GrDrawingManager* fDrawingManager;
 
     // In debug builds we guard against improper thread handling
     SkDEBUGCODE(mutable GrSingleOwner* fSingleOwner;)
diff --git a/src/gpu/GrTextureContext.cpp b/src/gpu/GrTextureContext.cpp
index aa84e59..c5b3203 100644
--- a/src/gpu/GrTextureContext.cpp
+++ b/src/gpu/GrTextureContext.cpp
@@ -23,9 +23,10 @@
                                    sk_sp<SkColorSpace> colorSpace,
                                    GrAuditTrail* auditTrail,
                                    GrSingleOwner* singleOwner)
-    : GrSurfaceContext(context, drawingMgr, std::move(colorSpace), auditTrail, singleOwner)
-    , fTextureProxy(std::move(textureProxy))
-    , fOpList(sk_ref_sp(fTextureProxy->getLastTextureOpList())) {
+        : GrSurfaceContext(context, drawingMgr, textureProxy->config(), std::move(colorSpace),
+                           auditTrail, singleOwner)
+        , fTextureProxy(std::move(textureProxy))
+        , fOpList(sk_ref_sp(fTextureProxy->getLastTextureOpList())) {
     SkDEBUGCODE(this->validate();)
 }
 
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index eb9e8e8..93414ed 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -118,12 +118,11 @@
 
 static SkImageInfo make_info(GrRenderTargetContext* context, int w, int h, bool opaque) {
     SkColorType colorType;
-    if (!GrPixelConfigToColorType(context->config(), &colorType)) {
+    if (!GrPixelConfigToColorType(context->colorSpaceInfo().config(), &colorType)) {
         colorType = kUnknown_SkColorType;
     }
-    return SkImageInfo::Make(w, h, colorType,
-                             opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType,
-                             context->refColorSpace());
+    return SkImageInfo::Make(w, h, colorType, opaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType,
+                             context->colorSpaceInfo().refColorSpace());
 }
 
 SkGpuDevice::SkGpuDevice(GrContext* context, sk_sp<GrRenderTargetContext> renderTargetContext,
@@ -179,7 +178,8 @@
     matrix.postTranslate(SkIntToScalar(-left), SkIntToScalar(-top));
     const SkIRect clipBounds = this->devClipBounds().makeOffset(-left, -top);
     sk_sp<SkImageFilterCache> cache(this->getImageFilterCache());
-    SkImageFilter::OutputProperties outputProperties(fRenderTargetContext->getColorSpace());
+    SkImageFilter::OutputProperties outputProperties(
+            fRenderTargetContext->colorSpaceInfo().colorSpace());
     SkImageFilter::Context ctx(matrix, clipBounds, cache.get(), outputProperties);
 
     return filter->filterImage(srcImg, ctx, offset);
@@ -272,8 +272,8 @@
     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawPaint", fContext.get());
 
     GrPaint grPaint;
-    if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
-                          &grPaint)) {
+    if (!SkPaintToGrPaint(this->context(), fRenderTargetContext->colorSpaceInfo(), paint,
+                          this->ctm(), &grPaint)) {
         return;
     }
 
@@ -299,8 +299,8 @@
     if (paint.getPathEffect() && 2 == count && SkCanvas::kLines_PointMode == mode) {
         GrStyle style(paint, SkPaint::kStroke_Style);
         GrPaint grPaint;
-        if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
-                              &grPaint)) {
+        if (!SkPaintToGrPaint(this->context(), fRenderTargetContext->colorSpaceInfo(), paint,
+                              this->ctm(), &grPaint)) {
             return;
         }
         SkPath path;
@@ -344,8 +344,8 @@
 #endif
 
     GrPaint grPaint;
-    if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, *viewMatrix,
-                          &grPaint)) {
+    if (!SkPaintToGrPaint(this->context(), fRenderTargetContext->colorSpaceInfo(), paint,
+                          *viewMatrix, &grPaint)) {
         return;
     }
 
@@ -374,8 +374,8 @@
     }
 
     GrPaint grPaint;
-    if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
-                          &grPaint)) {
+    if (!SkPaintToGrPaint(this->context(), fRenderTargetContext->colorSpaceInfo(), paint,
+                          this->ctm(), &grPaint)) {
         return;
     }
 
@@ -390,8 +390,8 @@
     ASSERT_SINGLE_OWNER
     GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice", "drawRRect", fContext.get());
     GrPaint grPaint;
-    if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
-                          &grPaint)) {
+    if (!SkPaintToGrPaint(this->context(), fRenderTargetContext->colorSpaceInfo(), paint,
+                          this->ctm(), &grPaint)) {
         return;
     }
 
@@ -455,8 +455,8 @@
 
     if (stroke.isFillStyle() && !paint.getMaskFilter() && !paint.getPathEffect()) {
         GrPaint grPaint;
-        if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
-                              &grPaint)) {
+        if (!SkPaintToGrPaint(this->context(), fRenderTargetContext->colorSpaceInfo(), paint,
+                              this->ctm(), &grPaint)) {
             return;
         }
 
@@ -488,8 +488,8 @@
     }
 
     GrPaint grPaint;
-    if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
-                          &grPaint)) {
+    if (!SkPaintToGrPaint(this->context(), fRenderTargetContext->colorSpaceInfo(), paint,
+                          this->ctm(), &grPaint)) {
         return;
     }
 
@@ -517,8 +517,8 @@
     }
 
     GrPaint grPaint;
-    if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
-                          &grPaint)) {
+    if (!SkPaintToGrPaint(this->context(), fRenderTargetContext->colorSpaceInfo(), paint,
+                          this->ctm(), &grPaint)) {
         return;
     }
 
@@ -536,8 +536,8 @@
         return;
     }
     GrPaint grPaint;
-    if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), paint, this->ctm(),
-                          &grPaint)) {
+    if (!SkPaintToGrPaint(this->context(), fRenderTargetContext->colorSpaceInfo(), paint,
+                          this->ctm(), &grPaint)) {
         return;
     }
 
@@ -592,7 +592,8 @@
     m.postConcat(this->ctm());
 
     GrPaint grPaint;
-    if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), newPaint, m, &grPaint)) {
+    if (!SkPaintToGrPaint(this->context(), fRenderTargetContext->colorSpaceInfo(), newPaint, m,
+                          &grPaint)) {
         return;
     }
 
@@ -1022,11 +1023,11 @@
     }
 
     fp = GrColorSpaceXformEffect::Make(std::move(fp), bitmap.colorSpace(),
-                                       fRenderTargetContext->getColorSpace());
+                                       fRenderTargetContext->colorSpaceInfo().colorSpace());
     GrPaint grPaint;
-    if (!SkPaintToGrPaintWithTexture(this->context(), fRenderTargetContext.get(), paint, viewMatrix,
-                                     std::move(fp), kAlpha_8_SkColorType == bitmap.colorType(),
-                                     &grPaint)) {
+    if (!SkPaintToGrPaintWithTexture(this->context(), fRenderTargetContext->colorSpaceInfo(), paint,
+                                     viewMatrix, std::move(fp),
+                                     kAlpha_8_SkColorType == bitmap.colorType(), &grPaint)) {
         return;
     }
 
@@ -1088,7 +1089,7 @@
 
     auto fp = GrSimpleTextureEffect::Make(std::move(proxy), SkMatrix::I());
     fp = GrColorSpaceXformEffect::Make(std::move(fp), result->getColorSpace(),
-                                       fRenderTargetContext->getColorSpace());
+                                       fRenderTargetContext->colorSpaceInfo().colorSpace());
     if (GrPixelConfigIsAlphaOnly(config)) {
         fp = GrFragmentProcessor::MakeInputPremulAndMulByOutput(std::move(fp));
     } else {
@@ -1096,8 +1097,8 @@
     }
 
     GrPaint grPaint;
-    if (!SkPaintToGrPaintReplaceShader(this->context(), fRenderTargetContext.get(), tmpUnfiltered,
-                                       std::move(fp), &grPaint)) {
+    if (!SkPaintToGrPaintReplaceShader(this->context(), fRenderTargetContext->colorSpaceInfo(),
+                                       tmpUnfiltered, std::move(fp), &grPaint)) {
         return;
     }
 
@@ -1287,7 +1288,7 @@
     if (this->shouldTileImage(image, nullptr, SkCanvas::kFast_SrcRectConstraint,
                               paint.getFilterQuality(), viewMatrix, SkMatrix::I())) {
         // only support tiling as bitmap at the moment, so force raster-version
-        if (!as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) {
+        if (!as_IB(image)->getROPixels(&bm, fRenderTargetContext->colorSpaceInfo().colorSpace())) {
             return;
         }
         this->drawBitmap(bm, x, y, paint);
@@ -1299,7 +1300,7 @@
                                SkCanvas::kFast_SrcRectConstraint, viewMatrix, paint);
         return;
     }
-    if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) {
+    if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->colorSpaceInfo().colorSpace())) {
         GrBitmapTextureMaker maker(fContext.get(), bm);
         this->drawTextureMaker(&maker, image->width(), image->height(), nullptr, nullptr,
                                SkCanvas::kFast_SrcRectConstraint, viewMatrix, paint);
@@ -1325,7 +1326,7 @@
     if (this->shouldTileImage(image, src, constraint, paint.getFilterQuality(), this->ctm(),
                               srcToDstRect)) {
         // only support tiling as bitmap at the moment, so force raster-version
-        if (!as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) {
+        if (!as_IB(image)->getROPixels(&bm, fRenderTargetContext->colorSpaceInfo().colorSpace())) {
             return;
         }
         this->drawBitmapRect(bm, src, dst, paint, constraint);
@@ -1337,7 +1338,7 @@
                                this->ctm(), paint);
         return;
     }
-    if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) {
+    if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->colorSpaceInfo().colorSpace())) {
         GrBitmapTextureMaker maker(fContext.get(), bm);
         this->drawTextureMaker(&maker, image->width(), image->height(), src, &dst, constraint,
                                this->ctm(), paint);
@@ -1368,12 +1369,12 @@
     auto fp = producer->createFragmentProcessor(
             SkMatrix::I(), SkRect::MakeIWH(producer->width(), producer->height()),
             GrTextureProducer::kNo_FilterConstraint, true, &kMode,
-            fRenderTargetContext->getColorSpace());
+            fRenderTargetContext->colorSpaceInfo().colorSpace());
     if (!fp) {
         return;
     }
     GrPaint grPaint;
-    if (!SkPaintToGrPaintWithTexture(this->context(), fRenderTargetContext.get(), paint,
+    if (!SkPaintToGrPaintWithTexture(this->context(), fRenderTargetContext->colorSpaceInfo(), paint,
                                      this->ctm(), std::move(fp), producer->isAlphaOnly(),
                                      &grPaint)) {
         return;
@@ -1400,7 +1401,8 @@
         if (image->isLazyGenerated()) {
             GrImageTextureMaker maker(fContext.get(), image, SkImage::kAllow_CachingHint);
             this->drawProducerNine(&maker, center, dst, paint);
-        } else if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) {
+        } else if (as_IB(image)->getROPixels(&bm,
+                                             fRenderTargetContext->colorSpaceInfo().colorSpace())) {
             this->drawBitmapNine(bm, center, dst, paint);
         }
     }
@@ -1422,12 +1424,12 @@
     std::unique_ptr<GrFragmentProcessor> fp(producer->createFragmentProcessor(
             SkMatrix::I(), SkRect::MakeIWH(producer->width(), producer->height()),
             GrTextureProducer::kNo_FilterConstraint, true, &kMode,
-            fRenderTargetContext->getColorSpace()));
+            fRenderTargetContext->colorSpaceInfo().colorSpace()));
     if (!fp) {
         return;
     }
     GrPaint grPaint;
-    if (!SkPaintToGrPaintWithTexture(this->context(), fRenderTargetContext.get(), paint,
+    if (!SkPaintToGrPaintWithTexture(this->context(), fRenderTargetContext->colorSpaceInfo(), paint,
                                      this->ctm(), std::move(fp), producer->isAlphaOnly(),
                                      &grPaint)) {
         return;
@@ -1455,7 +1457,8 @@
         if (image->isLazyGenerated()) {
             GrImageTextureMaker maker(fContext.get(), image, SkImage::kAllow_CachingHint);
             this->drawProducerLattice(&maker, lattice, dst, paint);
-        } else if (as_IB(image)->getROPixels(&bm, fRenderTargetContext->getColorSpace())) {
+        } else if (as_IB(image)->getROPixels(&bm,
+                                             fRenderTargetContext->colorSpaceInfo().colorSpace())) {
             this->drawBitmapLattice(bm, lattice, dst, paint);
         }
     }
@@ -1469,26 +1472,26 @@
     this->drawProducerLattice(&maker, lattice, dst, paint);
 }
 
-static bool init_vertices_paint(GrContext* context, GrRenderTargetContext* rtc,
-                                const SkPaint& skPaint,
-                                const SkMatrix& matrix, SkBlendMode bmode,
+static bool init_vertices_paint(GrContext* context, const GrColorSpaceInfo& colorSpaceInfo,
+                                const SkPaint& skPaint, const SkMatrix& matrix, SkBlendMode bmode,
                                 bool hasTexs, bool hasColors, GrPaint* grPaint) {
     if (hasTexs && skPaint.getShader()) {
         if (hasColors) {
             // When there are texs and colors the shader and colors are combined using bmode.
-            return SkPaintToGrPaintWithXfermode(context, rtc, skPaint, matrix, bmode, grPaint);
+            return SkPaintToGrPaintWithXfermode(context, colorSpaceInfo, skPaint, matrix, bmode,
+                                                grPaint);
         } else {
             // We have a shader, but no colors to blend it against.
-            return SkPaintToGrPaint(context, rtc, skPaint, matrix, grPaint);
+            return SkPaintToGrPaint(context, colorSpaceInfo, skPaint, matrix, grPaint);
         }
     } else {
         if (hasColors) {
             // We have colors, but either have no shader or no texture coords (which implies that
             // we should ignore the shader).
-            return SkPaintToGrPaintWithPrimitiveColor(context, rtc, skPaint, grPaint);
+            return SkPaintToGrPaintWithPrimitiveColor(context, colorSpaceInfo, skPaint, grPaint);
         } else {
             // No colors and no shaders. Just draw with the paint color.
-            return SkPaintToGrPaintNoShader(context, rtc, skPaint, grPaint);
+            return SkPaintToGrPaintNoShader(context, colorSpaceInfo, skPaint, grPaint);
         }
     }
 }
@@ -1506,7 +1509,8 @@
 
     GrPaint grPaint;
     // we ignore the shader since we have no texture coordinates.
-    if (!SkPaintToGrPaintNoShader(this->context(), fRenderTargetContext.get(), copy, &grPaint)) {
+    if (!SkPaintToGrPaintNoShader(this->context(), fRenderTargetContext->colorSpaceInfo(), copy,
+                                  &grPaint)) {
         return;
     }
 
@@ -1566,8 +1570,8 @@
                                 mode, vertices->indices(), vertices->indexCount(), paint);
         return;
     }
-    if (!init_vertices_paint(fContext.get(), fRenderTargetContext.get(), paint, this->ctm(),
-                             mode, hasTexs, hasColors, &grPaint)) {
+    if (!init_vertices_paint(fContext.get(), fRenderTargetContext->colorSpaceInfo(), paint,
+                             this->ctm(), mode, hasTexs, hasColors, &grPaint)) {
         return;
     }
     fRenderTargetContext->drawVertices(this->clip(), std::move(grPaint), this->ctm(),
@@ -1606,13 +1610,13 @@
 
     GrPaint grPaint;
     if (colors) {
-        if (!SkPaintToGrPaintWithXfermode(this->context(), fRenderTargetContext.get(), p,
-                                          this->ctm(), (SkBlendMode)mode, &grPaint)) {
+        if (!SkPaintToGrPaintWithXfermode(this->context(), fRenderTargetContext->colorSpaceInfo(),
+                                          p, this->ctm(), (SkBlendMode)mode, &grPaint)) {
             return;
         }
     } else {
-        if (!SkPaintToGrPaint(this->context(), fRenderTargetContext.get(), p, this->ctm(),
-                              &grPaint)) {
+        if (!SkPaintToGrPaint(this->context(), fRenderTargetContext->colorSpaceInfo(), p,
+                              this->ctm(), &grPaint)) {
             return;
         }
     }
@@ -1695,14 +1699,10 @@
                                                             : SkBackingFit::kExact;
 
     sk_sp<GrRenderTargetContext> rtc(fContext->makeDeferredRenderTargetContext(
-                                                   fit,
-                                                   cinfo.fInfo.width(), cinfo.fInfo.height(),
-                                                   fRenderTargetContext->config(),
-                                                   fRenderTargetContext->refColorSpace(),
-                                                   fRenderTargetContext->numStencilSamples(),
-                                                   false,
-                                                   kBottomLeft_GrSurfaceOrigin,
-                                                   &props));
+            fit, cinfo.fInfo.width(), cinfo.fInfo.height(),
+            fRenderTargetContext->colorSpaceInfo().config(),
+            fRenderTargetContext->colorSpaceInfo().refColorSpace(),
+            fRenderTargetContext->numStencilSamples(), false, kBottomLeft_GrSurfaceOrigin, &props));
     if (!rtc) {
         return nullptr;
     }
diff --git a/src/gpu/SkGpuDevice_drawTexture.cpp b/src/gpu/SkGpuDevice_drawTexture.cpp
index ad69413..8d0ed6e 100644
--- a/src/gpu/SkGpuDevice_drawTexture.cpp
+++ b/src/gpu/SkGpuDevice_drawTexture.cpp
@@ -114,7 +114,7 @@
         SkAssertResult(srcRect.intersect(SkRect::MakeIWH(proxy->width(), proxy->height())));
         srcToDst.mapRect(&dstRect, srcRect);
     }
-    auto csxf = GrColorSpaceXform::Make(colorSpace, rtc->getColorSpace());
+    auto csxf = GrColorSpaceXform::Make(colorSpace, rtc->colorSpaceInfo().colorSpace());
     GrSamplerState::Filter filter;
     switch (paint.getFilterQuality()) {
         case kNone_SkFilterQuality:
@@ -160,9 +160,9 @@
         sk_sp<SkColorSpace> cs;
         // We've done enough checks above to allow us to pass ClampNearest() and not check for
         // scaling adjustments.
-        auto proxy = maker->refTextureProxyForParams(GrSamplerState::ClampNearest(),
-                                                     fRenderTargetContext->getColorSpace(), &cs,
-                                                     nullptr);
+        auto proxy = maker->refTextureProxyForParams(
+                GrSamplerState::ClampNearest(), fRenderTargetContext->colorSpaceInfo().colorSpace(),
+                &cs, nullptr);
         if (!proxy) {
             return;
         }
@@ -284,16 +284,17 @@
         }
         textureMatrix = &tempMatrix;
     }
-    auto fp = producer->createFragmentProcessor(*textureMatrix, clippedSrcRect, constraintMode,
-                                                coordsAllInsideSrcRect, filterMode,
-                                                fRenderTargetContext->getColorSpace());
+    auto fp = producer->createFragmentProcessor(
+            *textureMatrix, clippedSrcRect, constraintMode, coordsAllInsideSrcRect, filterMode,
+            fRenderTargetContext->colorSpaceInfo().colorSpace());
     if (!fp) {
         return;
     }
 
     GrPaint grPaint;
-    if (!SkPaintToGrPaintWithTexture(fContext.get(), fRenderTargetContext.get(), paint, viewMatrix,
-                                     std::move(fp), producer->isAlphaOnly(), &grPaint)) {
+    if (!SkPaintToGrPaintWithTexture(fContext.get(), fRenderTargetContext->colorSpaceInfo(), paint,
+                                     viewMatrix, std::move(fp), producer->isAlphaOnly(),
+                                     &grPaint)) {
         return;
     }
     GrAA aa = GrBoolToAA(paint.isAntiAlias());
diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp
index fe34aa1..983bb5b 100644
--- a/src/gpu/SkGr.cpp
+++ b/src/gpu/SkGr.cpp
@@ -6,19 +6,17 @@
  */
 
 #include "SkGr.h"
-
 #include "GrBitmapTextureMaker.h"
 #include "GrCaps.h"
 #include "GrColorSpaceXform.h"
 #include "GrContext.h"
 #include "GrContextPriv.h"
 #include "GrGpuResourcePriv.h"
-#include "GrRenderTargetContext.h"
+#include "GrPaint.h"
 #include "GrResourceProvider.h"
 #include "GrTextureProxy.h"
 #include "GrTypes.h"
 #include "GrXferProcessor.h"
-
 #include "SkAutoMalloc.h"
 #include "SkBlendModePriv.h"
 #include "SkCanvas.h"
@@ -307,6 +305,8 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+// TODO(bsalomon): Pass GrColorSpaceInfo to these conversion functions?
+
 GrColor4f SkColorToPremulGrColor4f(SkColor c, SkColorSpace* dstColorSpace) {
     // We want to premultiply after linearizing, so this is easy:
     return SkColorToUnpremulGrColor4f(c, dstColorSpace).premul();
@@ -442,17 +442,18 @@
 }
 
 static inline bool skpaint_to_grpaint_impl(GrContext* context,
-                                           GrRenderTargetContext* rtc,
+                                           const GrColorSpaceInfo& colorSpaceInfo,
                                            const SkPaint& skPaint,
                                            const SkMatrix& viewM,
                                            std::unique_ptr<GrFragmentProcessor>* shaderProcessor,
                                            SkBlendMode* primColorMode,
                                            GrPaint* grPaint) {
-    grPaint->setAllowSRGBInputs(rtc->isGammaCorrect());
+    grPaint->setAllowSRGBInputs(colorSpaceInfo.isGammaCorrect());
 
     // Convert SkPaint color to 4f format, including optional linearizing and gamut conversion.
-    GrColor4f origColor = SkColorToUnpremulGrColor4f(skPaint.getColor(), rtc->getColorSpace(),
-                                                     rtc->getColorXformFromSRGB());
+    GrColor4f origColor =
+            SkColorToUnpremulGrColor4f(skPaint.getColor(), colorSpaceInfo.colorSpace(),
+                                       colorSpaceInfo.colorSpaceXformFromSRGB());
 
     // Setup the initial color considering the shader, the SkPaint color, and the presence or not
     // of per-vertex colors.
@@ -462,8 +463,8 @@
             shaderFP = std::move(*shaderProcessor);
         } else if (const auto* shader = as_SB(skPaint.getShader())) {
             shaderFP = shader->asFragmentProcessor(
-                SkShaderBase::AsFPArgs(context, &viewM, nullptr, skPaint.getFilterQuality(),
-                                       rtc->getColorSpace()));
+                    SkShaderBase::AsFPArgs(context, &viewM, nullptr, skPaint.getFilterQuality(),
+                                           colorSpaceInfo.colorSpace()));
             if (!shaderFP) {
                 return false;
             }
@@ -542,7 +543,7 @@
         if (applyColorFilterToPaintColor) {
             // If we're in legacy mode, we *must* avoid using the 4f version of the color filter,
             // because that will combine with the linearized version of the stored color.
-            if (rtc->isGammaCorrect()) {
+            if (colorSpaceInfo.isGammaCorrect()) {
                 grPaint->setColor4f(GrColor4f::FromSkColor4f(
                     colorFilter->filterColor4f(origColor.toSkColor4f())).premul());
             } else {
@@ -550,7 +551,7 @@
                     colorFilter->filterColor(skPaint.getColor()), nullptr, nullptr));
             }
         } else {
-            auto cfFP = colorFilter->asFragmentProcessor(context, rtc->getColorSpace());
+            auto cfFP = colorFilter->asFragmentProcessor(context, colorSpaceInfo.colorSpace());
             if (cfFP) {
                 grPaint->addColorFragmentProcessor(std::move(cfFP));
             } else {
@@ -577,10 +578,10 @@
 #ifndef SK_IGNORE_GPU_DITHER
     // Conservative default, in case GrPixelConfigToColorType() fails.
     SkColorType ct = SkColorType::kRGB_565_SkColorType;
-    GrPixelConfigToColorType(rtc->config(), &ct);
-    if (SkPaintPriv::ShouldDither(skPaint, ct) && grPaint->numColorFragmentProcessors() > 0
-        && !rtc->isGammaCorrect()) {
-        auto ditherFP = GrDitherEffect::Make(rtc->config());
+    GrPixelConfigToColorType(colorSpaceInfo.config(), &ct);
+    if (SkPaintPriv::ShouldDither(skPaint, ct) && grPaint->numColorFragmentProcessors() > 0 &&
+        !colorSpaceInfo.isGammaCorrect()) {
+        auto ditherFP = GrDitherEffect::Make(colorSpaceInfo.config());
         if (ditherFP) {
             grPaint->addColorFragmentProcessor(std::move(ditherFP));
         }
@@ -589,50 +590,51 @@
     return true;
 }
 
-bool SkPaintToGrPaint(GrContext* context, GrRenderTargetContext* rtc, const SkPaint& skPaint,
-                      const SkMatrix& viewM, GrPaint* grPaint) {
-    return skpaint_to_grpaint_impl(context, rtc, skPaint, viewM, nullptr, nullptr, grPaint);
+bool SkPaintToGrPaint(GrContext* context, const GrColorSpaceInfo& colorSpaceInfo,
+                      const SkPaint& skPaint, const SkMatrix& viewM, GrPaint* grPaint) {
+    return skpaint_to_grpaint_impl(context, colorSpaceInfo, skPaint, viewM, nullptr, nullptr,
+                                   grPaint);
 }
 
 /** Replaces the SkShader (if any) on skPaint with the passed in GrFragmentProcessor. */
 bool SkPaintToGrPaintReplaceShader(GrContext* context,
-                                   GrRenderTargetContext* rtc,
+                                   const GrColorSpaceInfo& colorSpaceInfo,
                                    const SkPaint& skPaint,
                                    std::unique_ptr<GrFragmentProcessor> shaderFP,
                                    GrPaint* grPaint) {
     if (!shaderFP) {
         return false;
     }
-    return skpaint_to_grpaint_impl(context, rtc, skPaint, SkMatrix::I(), &shaderFP, nullptr,
-                                   grPaint);
+    return skpaint_to_grpaint_impl(context, colorSpaceInfo, skPaint, SkMatrix::I(), &shaderFP,
+                                   nullptr, grPaint);
 }
 
 /** Ignores the SkShader (if any) on skPaint. */
 bool SkPaintToGrPaintNoShader(GrContext* context,
-                              GrRenderTargetContext* rtc,
+                              const GrColorSpaceInfo& colorSpaceInfo,
                               const SkPaint& skPaint,
                               GrPaint* grPaint) {
     // Use a ptr to a nullptr to to indicate that the SkShader is ignored and not replaced.
     static std::unique_ptr<GrFragmentProcessor> kNullShaderFP(nullptr);
     static std::unique_ptr<GrFragmentProcessor>* kIgnoreShader = &kNullShaderFP;
-    return skpaint_to_grpaint_impl(context, rtc, skPaint, SkMatrix::I(), kIgnoreShader, nullptr,
-                                   grPaint);
+    return skpaint_to_grpaint_impl(context, colorSpaceInfo, skPaint, SkMatrix::I(), kIgnoreShader,
+                                   nullptr, grPaint);
 }
 
 /** Blends the SkPaint's shader (or color if no shader) with a per-primitive color which must
 be setup as a vertex attribute using the specified SkBlendMode. */
 bool SkPaintToGrPaintWithXfermode(GrContext* context,
-                                  GrRenderTargetContext* rtc,
+                                  const GrColorSpaceInfo& colorSpaceInfo,
                                   const SkPaint& skPaint,
                                   const SkMatrix& viewM,
                                   SkBlendMode primColorMode,
                                   GrPaint* grPaint) {
-    return skpaint_to_grpaint_impl(context, rtc, skPaint, viewM, nullptr, &primColorMode,
+    return skpaint_to_grpaint_impl(context, colorSpaceInfo, skPaint, viewM, nullptr, &primColorMode,
                                    grPaint);
 }
 
 bool SkPaintToGrPaintWithTexture(GrContext* context,
-                                 GrRenderTargetContext* rtc,
+                                 const GrColorSpaceInfo& colorSpaceInfo,
                                  const SkPaint& paint,
                                  const SkMatrix& viewM,
                                  std::unique_ptr<GrFragmentProcessor> fp,
@@ -642,8 +644,8 @@
     if (textureIsAlphaOnly) {
         if (const auto* shader = as_SB(paint.getShader())) {
             shaderFP = shader->asFragmentProcessor(
-                SkShaderBase::AsFPArgs(context, &viewM, nullptr, paint.getFilterQuality(),
-                                       rtc->getColorSpace()));
+                    SkShaderBase::AsFPArgs(context, &viewM, nullptr, paint.getFilterQuality(),
+                                           colorSpaceInfo.colorSpace()));
             if (!shaderFP) {
                 return false;
             }
@@ -656,7 +658,8 @@
         shaderFP = GrFragmentProcessor::MulOutputByInputAlpha(std::move(fp));
     }
 
-    return SkPaintToGrPaintReplaceShader(context, rtc, paint, std::move(shaderFP), grPaint);
+    return SkPaintToGrPaintReplaceShader(context, colorSpaceInfo, paint, std::move(shaderFP),
+                                         grPaint);
 }
 
 
diff --git a/src/gpu/SkGr.h b/src/gpu/SkGr.h
index f4f4d07..2fedc06 100644
--- a/src/gpu/SkGr.h
+++ b/src/gpu/SkGr.h
@@ -23,9 +23,9 @@
 #include "SkVertices.h"
 
 class GrCaps;
+class GrColorSpaceInfo;
 class GrColorSpaceXform;
 class GrContext;
-class GrRenderTargetContext;
 class GrFragmentProcessor;
 class GrPaint;
 class GrResourceProvider;
@@ -98,14 +98,14 @@
 /** Converts an SkPaint to a GrPaint for a given GrContext. The matrix is required in order
     to convert the SkShader (if any) on the SkPaint. The primitive itself has no color. */
 bool SkPaintToGrPaint(GrContext*,
-                      GrRenderTargetContext*,
+                      const GrColorSpaceInfo& dstColorSpaceInfo,
                       const SkPaint& skPaint,
                       const SkMatrix& viewM,
                       GrPaint* grPaint);
 
 /** Same as above but ignores the SkShader (if any) on skPaint. */
 bool SkPaintToGrPaintNoShader(GrContext* context,
-                              GrRenderTargetContext* rtc,
+                              const GrColorSpaceInfo& dstColorSpaceInfo,
                               const SkPaint& skPaint,
                               GrPaint* grPaint);
 
@@ -113,7 +113,7 @@
     should expect an unpremul input color and produce a premultiplied output color. There is
     no primitive color. */
 bool SkPaintToGrPaintReplaceShader(GrContext*,
-                                   GrRenderTargetContext*,
+                                   const GrColorSpaceInfo& dstColorSpaceInfo,
                                    const SkPaint& skPaint,
                                    std::unique_ptr<GrFragmentProcessor> shaderFP,
                                    GrPaint* grPaint);
@@ -121,7 +121,7 @@
 /** Blends the SkPaint's shader (or color if no shader) with the color which specified via a
     GrOp's GrPrimitiveProcesssor. */
 bool SkPaintToGrPaintWithXfermode(GrContext* context,
-                                  GrRenderTargetContext* rtc,
+                                  const GrColorSpaceInfo& dstColorSpaceInfo,
                                   const SkPaint& skPaint,
                                   const SkMatrix& viewM,
                                   SkBlendMode primColorMode,
@@ -131,16 +131,17 @@
     the expectation is that the primitive color will be premultiplied, though it really should be
     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, GrRenderTargetContext* rtc,
+inline bool SkPaintToGrPaintWithPrimitiveColor(GrContext* context,
+                                               const GrColorSpaceInfo& dstColorSpaceInfo,
                                                const SkPaint& skPaint, GrPaint* grPaint) {
-    return SkPaintToGrPaintWithXfermode(context, rtc, skPaint, SkMatrix::I(), SkBlendMode::kDst,
-                                        grPaint);
+    return SkPaintToGrPaintWithXfermode(context, dstColorSpaceInfo, skPaint, SkMatrix::I(),
+                                        SkBlendMode::kDst, grPaint);
 }
 
 /** This is used when there may or may not be a shader, and the caller wants to plugin a texture
     lookup.  If there is a shader, then its output will only be used if the texture is alpha8. */
 bool SkPaintToGrPaintWithTexture(GrContext* context,
-                                 GrRenderTargetContext* rtc,
+                                 const GrColorSpaceInfo& dstColorSpaceInfo,
                                  const SkPaint& paint,
                                  const SkMatrix& viewM,
                                  std::unique_ptr<GrFragmentProcessor> fp,
diff --git a/src/gpu/text/GrAtlasTextBlob.cpp b/src/gpu/text/GrAtlasTextBlob.cpp
index 339ae6d..be83dc1 100644
--- a/src/gpu/text/GrAtlasTextBlob.cpp
+++ b/src/gpu/text/GrAtlasTextBlob.cpp
@@ -274,8 +274,8 @@
         bool useBGR = SkPixelGeometryIsBGR(props.pixelGeometry());
         op = GrAtlasTextOp::MakeDistanceField(
                 std::move(grPaint), glyphCount, cache, distanceAdjustTable,
-                renderTargetContext->isGammaCorrect(), paint.luminanceColor(), info.hasUseLCDText(),
-                useBGR, info.isAntiAliased());
+                renderTargetContext->colorSpaceInfo().isGammaCorrect(), paint.luminanceColor(),
+                info.hasUseLCDText(), useBGR, info.isAntiAliased());
     } else {
         op = GrAtlasTextOp::MakeBitmap(std::move(grPaint), format, glyphCount, cache);
     }
diff --git a/src/gpu/text/GrAtlasTextContext.cpp b/src/gpu/text/GrAtlasTextContext.cpp
index 8f310d0..4f8748b 100644
--- a/src/gpu/text/GrAtlasTextContext.cpp
+++ b/src/gpu/text/GrAtlasTextContext.cpp
@@ -50,10 +50,10 @@
     return canonicalColor;
 }
 
-uint32_t GrAtlasTextContext::ComputeScalerContextFlags(GrRenderTargetContext* rtc) {
+uint32_t GrAtlasTextContext::ComputeScalerContextFlags(const GrColorSpaceInfo& colorSpaceInfo) {
     // If we're doing gamma-correct rendering, then we can disable the gamma hacks.
     // Otherwise, leave them on. In either case, we still want the contrast boost:
-    if (rtc->isGammaCorrect()) {
+    if (colorSpaceInfo.isGammaCorrect()) {
         return SkPaint::kBoostContrast_ScalerContextFlag;
     } else {
         return SkPaint::kFakeGammaAndBoostContrast_ScalerContextFlags;
@@ -93,7 +93,7 @@
     bool canCache = !(skPaint.getPathEffect() ||
                       (mf && !mf->asABlur(&blurRec)) ||
                       drawFilter);
-    uint32_t scalerContextFlags = ComputeScalerContextFlags(rtc);
+    uint32_t scalerContextFlags = ComputeScalerContextFlags(rtc->colorSpaceInfo());
 
     GrTextBlobCache* cache = context->getTextBlobCache();
     if (canCache) {
@@ -118,7 +118,7 @@
         cacheBlob = cache->find(key);
     }
 
-    GrTextUtils::Paint paint(&skPaint, rtc->getColorSpace(), rtc->getColorXformFromSRGB());
+    GrTextUtils::Paint paint(&skPaint, rtc->colorSpaceInfo());
     if (cacheBlob) {
         if (cacheBlob->mustRegenerate(paint, blurRec, viewMatrix, x, y)) {
             // We have to remake the blob because changes may invalidate our masks.
@@ -295,14 +295,13 @@
     if (context->abandoned()) {
         return;
     }
-    GrTextUtils::Paint paint(&skPaint, rtc->getColorSpace(), rtc->getColorXformFromSRGB());
+    GrTextUtils::Paint paint(&skPaint, rtc->colorSpaceInfo());
     if (this->canDraw(skPaint, viewMatrix, props, *context->caps()->shaderCaps())) {
         sk_sp<GrAtlasTextBlob> blob(
-            MakeDrawTextBlob(context->getTextBlobCache(), context->getAtlasGlyphCache(),
-                             *context->caps()->shaderCaps(),
-                             paint, ComputeScalerContextFlags(rtc),
-                             viewMatrix, props,
-                             text, byteLength, x, y));
+                MakeDrawTextBlob(context->getTextBlobCache(), context->getAtlasGlyphCache(),
+                                 *context->caps()->shaderCaps(), paint,
+                                 ComputeScalerContextFlags(rtc->colorSpaceInfo()), viewMatrix,
+                                 props, text, byteLength, x, y));
         if (blob) {
             blob->flushThrowaway(context, rtc, props, fDistanceAdjustTable.get(), paint, clip,
                                  viewMatrix, regionClipBounds, x, y);
@@ -321,18 +320,15 @@
                                      const char text[], size_t byteLength, const SkScalar pos[],
                                      int scalarsPerPosition, const SkPoint& offset,
                                      const SkIRect& regionClipBounds) {
-    GrTextUtils::Paint paint(&skPaint, rtc->getColorSpace(), rtc->getColorXformFromSRGB());
+    GrTextUtils::Paint paint(&skPaint, rtc->colorSpaceInfo());
     if (context->abandoned()) {
         return;
     } else if (this->canDraw(skPaint, viewMatrix, props, *context->caps()->shaderCaps())) {
         sk_sp<GrAtlasTextBlob> blob(
-            MakeDrawPosTextBlob(context->getTextBlobCache(), context->getAtlasGlyphCache(),
-                                *context->caps()->shaderCaps(),
-                                paint, ComputeScalerContextFlags(rtc),
-                                viewMatrix, props,
-                                text, byteLength,
-                                pos, scalarsPerPosition,
-                                offset));
+                MakeDrawPosTextBlob(context->getTextBlobCache(), context->getAtlasGlyphCache(),
+                                    *context->caps()->shaderCaps(), paint,
+                                    ComputeScalerContextFlags(rtc->colorSpaceInfo()), viewMatrix,
+                                    props, text, byteLength, pos, scalarsPerPosition, offset));
         if (blob) {
             blob->flushThrowaway(context, rtc, props, fDistanceAdjustTable.get(), paint, clip,
                                  viewMatrix, regionClipBounds, offset.fX, offset.fY);
@@ -374,7 +370,7 @@
     skPaint.setLCDRenderText(random->nextBool());
     skPaint.setAntiAlias(skPaint.isLCDRenderText() ? true : random->nextBool());
     skPaint.setSubpixelText(random->nextBool());
-    GrTextUtils::Paint utilsPaint(&skPaint, rtc->getColorSpace(), rtc->getColorXformFromSRGB());
+    GrTextUtils::Paint utilsPaint(&skPaint, rtc->colorSpaceInfo());
 
     const char* text = "The quick brown fox jumps over the lazy dog.";
     int textLen = (int)strlen(text);
diff --git a/src/gpu/text/GrAtlasTextContext.h b/src/gpu/text/GrAtlasTextContext.h
index 458a365..f9540de 100644
--- a/src/gpu/text/GrAtlasTextContext.h
+++ b/src/gpu/text/GrAtlasTextContext.h
@@ -51,7 +51,7 @@
     // sets up the descriptor on the blob and returns a detached cache.  Client must attach
     inline static SkColor ComputeCanonicalColor(const SkPaint&, bool lcd);
     // Determines if we need to use fake gamma (and contrast boost):
-    inline static uint32_t ComputeScalerContextFlags(GrRenderTargetContext*);
+    inline static uint32_t ComputeScalerContextFlags(const GrColorSpaceInfo&);
     static void RegenerateTextBlob(GrAtlasTextBlob* bmp,
                                    GrAtlasGlyphCache*,
                                    const GrShaderCaps&,
diff --git a/src/gpu/text/GrStencilAndCoverTextContext.cpp b/src/gpu/text/GrStencilAndCoverTextContext.cpp
index 854945e..502f4ad 100644
--- a/src/gpu/text/GrStencilAndCoverTextContext.cpp
+++ b/src/gpu/text/GrStencilAndCoverTextContext.cpp
@@ -133,7 +133,7 @@
                                                         SkScalar x, SkScalar y,
                                                         SkDrawFilter* drawFilter,
                                                         const SkIRect& clipBounds) {
-    GrTextUtils::Paint paint(&skPaint, rtc->getColorSpace(), rtc->getColorXformFromSRGB());
+    GrTextUtils::Paint paint(&skPaint, rtc->colorSpaceInfo());
     GrTextUtils::RunPaint runPaint(&paint, drawFilter, props);
     SkTextBlobRunIterator it(blob);
     for (;!it.done(); it.next()) {
@@ -580,7 +580,8 @@
         }
 
         GrPaint grPaint;
-        if (!SkPaintToGrPaint(ctx, renderTargetContext, originalSkPaint, viewMatrix, &grPaint)) {
+        if (!SkPaintToGrPaint(ctx, renderTargetContext->colorSpaceInfo(), originalSkPaint,
+                              viewMatrix, &grPaint)) {
             return;
         }
 
diff --git a/src/gpu/text/GrTextUtils.cpp b/src/gpu/text/GrTextUtils.cpp
index 7ad4b4a..f920ec4 100644
--- a/src/gpu/text/GrTextUtils.cpp
+++ b/src/gpu/text/GrTextUtils.cpp
@@ -44,9 +44,11 @@
     // TODO: this is the last use of GrSurfaceContextPriv
     GrContext* context = rtc->surfPriv().getContext();
     if (kARGB_GrMaskFormat == maskFormat) {
-        return SkPaintToGrPaintWithPrimitiveColor(context, rtc, this->skPaint(), grPaint);
+        return SkPaintToGrPaintWithPrimitiveColor(context, rtc->colorSpaceInfo(), this->skPaint(),
+                                                  grPaint);
     } else {
-        return SkPaintToGrPaint(context, rtc, this->skPaint(), viewMatrix, grPaint);
+        return SkPaintToGrPaint(context, rtc->colorSpaceInfo(), this->skPaint(), viewMatrix,
+                                grPaint);
     }
 }
 
diff --git a/src/gpu/text/GrTextUtils.h b/src/gpu/text/GrTextUtils.h
index bbf3ca4..0a6b2cc 100644
--- a/src/gpu/text/GrTextUtils.h
+++ b/src/gpu/text/GrTextUtils.h
@@ -9,6 +9,7 @@
 #define GrTextUtils_DEFINED
 
 #include "GrColor.h"
+#include "GrColorSpaceInfo.h"
 #include "SkColorFilter.h"
 #include "SkGr.h"
 #include "SkPaint.h"
@@ -47,12 +48,10 @@
      */
     class Paint {
     public:
-        explicit Paint(const SkPaint* paint,
-                       SkColorSpace* dstColorSpace,
-                       GrColorSpaceXform* colorXformFromSRGB)
+        explicit Paint(const SkPaint* paint, const GrColorSpaceInfo& dstColorSpaceInfo)
                 : fPaint(paint)
-                , fDstColorSpace(dstColorSpace)
-                , fColorXformFromSRGB(colorXformFromSRGB) {
+                , fDstColorSpace(dstColorSpaceInfo.colorSpace())
+                , fColorXformFromSRGB(dstColorSpaceInfo.colorSpaceXformFromSRGB()) {
             this->initFilteredColor();
         }