Make GrContextThreadSafeProxy not a GrContext_Base

Once this API is retracted, we can rename it to something more sane.
The code base has some `fContextInfo` ivars of this type, suggesting it
was previously named ContextInfo. It could be a ContextGroup or something else.

Bug: skia:10318
Change-Id: I3471e2172f46163f98a94780f0d7eb3431894cda
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/293556
Reviewed-by: Robert Phillips <robertphillips@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
Auto-Submit: Adlai Holler <adlai@google.com>
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index 63e3a7e..fd3ba2d 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -98,6 +98,7 @@
 
     ~GrContext() override;
 
+    // TODO: Remove this from public after migrating Chrome.
     sk_sp<GrContextThreadSafeProxy> threadSafeProxy();
 
     /**
@@ -689,9 +690,9 @@
 #endif
 
 protected:
-    GrContext(GrBackendApi, const GrContextOptions&, int32_t contextID = SK_InvalidGenID);
+    GrContext(sk_sp<GrContextThreadSafeProxy>);
 
-    bool init(sk_sp<const GrCaps>) override;
+    bool init() override;
 
     GrContext* asDirectContext() override { return this; }
 
diff --git a/include/gpu/GrContextThreadSafeProxy.h b/include/gpu/GrContextThreadSafeProxy.h
index 4058ae5..ca4cb31 100644
--- a/include/gpu/GrContextThreadSafeProxy.h
+++ b/include/gpu/GrContextThreadSafeProxy.h
@@ -8,26 +8,26 @@
 #ifndef GrContextThreadSafeProxy_DEFINED
 #define GrContextThreadSafeProxy_DEFINED
 
-#include "include/private/GrContext_Base.h"
+#include "include/core/SkImageInfo.h"
+#include "include/core/SkRefCnt.h"
+#include "include/gpu/GrContextOptions.h"
+#include "include/gpu/GrTypes.h"
 
 #include <atomic>
 
 class GrBackendFormat;
+class GrCaps;
 class GrContextThreadSafeProxyPriv;
-struct SkImageInfo;
 class SkSurfaceCharacterization;
 class SkSurfaceProps;
 
 /**
  * Can be used to perform actions related to the generating GrContext in a thread safe manner. The
  * proxy does not access the 3D API (e.g. OpenGL) that backs the generating GrContext.
- *
- * TODO: Once the guts of GrContext_Base are moved in here, this probably shouldn't derive
- * from GrContext_Base since it isn't actually a context.
  */
-class SK_API GrContextThreadSafeProxy : public GrContext_Base {
+class SK_API GrContextThreadSafeProxy final : public SkNVRefCnt<GrContextThreadSafeProxy> {
 public:
-    ~GrContextThreadSafeProxy() override;
+    ~GrContextThreadSafeProxy();
 
     /**
      *  Create a surface characterization for a DDL that will be replayed into the GrContext
@@ -78,13 +78,13 @@
      *
      * The caller should check that the returned format is valid.
      */
-    GrBackendFormat defaultBackendFormat(SkColorType ct, GrRenderable renderable) const {
-        return INHERITED::defaultBackendFormat(ct, renderable);
-    }
+    GrBackendFormat defaultBackendFormat(SkColorType ct, GrRenderable renderable) const;
+
+    bool isValid() const { return nullptr != fCaps; }
 
     bool operator==(const GrContextThreadSafeProxy& that) const {
         // Each GrContext should only ever have a single thread-safe proxy.
-        SkASSERT((this == &that) == (this->contextID() == that.contextID()));
+        SkASSERT((this == &that) == (this->fContextID == that.fContextID));
         return this == &that;
     }
 
@@ -94,24 +94,25 @@
     GrContextThreadSafeProxyPriv priv();
     const GrContextThreadSafeProxyPriv priv() const;
 
-protected:
-    // TODO: remove this once this class isn't derived from GrContext_Base
-    GrContextThreadSafeProxy* asThreadSafeProxy() override { return this; }
-
 private:
     friend class GrContextThreadSafeProxyPriv; // for ctor and hidden methods
 
     // DDL TODO: need to add unit tests for backend & maybe options
-    GrContextThreadSafeProxy(GrBackendApi, const GrContextOptions&, uint32_t contextID);
-
-    bool init(sk_sp<const GrCaps>) override;
+    GrContextThreadSafeProxy(GrBackendApi, const GrContextOptions&);
 
     void abandonContext();
     bool abandoned() const;
 
-    std::atomic<bool> fAbandoned{false};
+    // TODO: This should be part of the constructor but right now we have a chicken-and-egg problem
+    // with GrContext where we get the caps by creating a GPU which requires a context (see the
+    // `init` method on GrContext_Base).
+    void init(sk_sp<const GrCaps>);
 
-    typedef GrContext_Base INHERITED;
+    const GrBackendApi          fBackend;
+    const GrContextOptions      fOptions;
+    const uint32_t              fContextID;
+    sk_sp<const GrCaps>         fCaps;
+    std::atomic<bool>           fAbandoned{false};
 };
 
 #endif
diff --git a/include/private/GrContext_Base.h b/include/private/GrContext_Base.h
index 45bc72a..326c910 100644
--- a/include/private/GrContext_Base.h
+++ b/include/private/GrContext_Base.h
@@ -16,6 +16,7 @@
 class GrBaseContextPriv;
 class GrCaps;
 class GrContext;
+class GrContextThreadSafeProxy;
 class GrImageContext;
 class GrRecordingContext;
 
@@ -26,7 +27,7 @@
     /*
      * The 3D API backing this context
      */
-    SK_API GrBackendApi backend() const { return fBackend; }
+    SK_API GrBackendApi backend() const;
 
     /*
      * Retrieve the default GrBackendFormat for a given SkColorType and renderability.
@@ -39,6 +40,9 @@
 
     SK_API GrBackendFormat compressedBackendFormat(SkImage::CompressionType) const;
 
+    // TODO: When the public version is gone, rename to refThreadSafeProxy and add raw ptr ver.
+    sk_sp<GrContextThreadSafeProxy> threadSafeProxy();
+
     // Provides access to functions that aren't part of the public API.
     GrBaseContextPriv priv();
     const GrBaseContextPriv priv() const;
@@ -46,9 +50,9 @@
 protected:
     friend class GrBaseContextPriv; // for hidden functions
 
-    GrContext_Base(GrBackendApi backend, const GrContextOptions& options, uint32_t contextID);
+    GrContext_Base(sk_sp<GrContextThreadSafeProxy>);
 
-    virtual bool init(sk_sp<const GrCaps>);
+    virtual bool init();
 
     /**
      * An identifier for this context. The id is used by all compatible contexts. For example,
@@ -57,7 +61,7 @@
      * a third thread with a direct context, then all three contexts will report the same id.
      * It is an error for an image to be used with contexts that report different ids.
      */
-    uint32_t contextID() const { return fContextID; }
+    uint32_t contextID() const;
 
     bool matches(GrContext_Base* candidate) const {
         return candidate->contextID() == this->contextID();
@@ -66,7 +70,7 @@
     /*
      * The options in effect for this context
      */
-    const GrContextOptions& options() const { return fOptions; }
+    const GrContextOptions& options() const;
 
     const GrCaps* caps() const;
     sk_sp<const GrCaps> refCaps() const;
@@ -74,18 +78,10 @@
     virtual GrImageContext* asImageContext() { return nullptr; }
     virtual GrRecordingContext* asRecordingContext() { return nullptr; }
     virtual GrContext* asDirectContext() { return nullptr; }
-    // TODO: Remove this once the proxy object isn't itself a context.
-    virtual GrContextThreadSafeProxy* asThreadSafeProxy() { return nullptr; }
 
     sk_sp<GrContextThreadSafeProxy>         fThreadSafeProxy;
 
 private:
-    // TODO: Move these const vars into thread safe proxy.
-    const GrBackendApi          fBackend;
-    const GrContextOptions      fOptions;
-    const uint32_t              fContextID;
-    sk_sp<const GrCaps>         fCaps;
-
     typedef SkRefCnt INHERITED;
 };
 
diff --git a/include/private/GrImageContext.h b/include/private/GrImageContext.h
index 9dc0acb..65d3064 100644
--- a/include/private/GrImageContext.h
+++ b/include/private/GrImageContext.h
@@ -18,10 +18,6 @@
 public:
     ~GrImageContext() override;
 
-    SK_API GrBackendFormat defaultBackendFormat(SkColorType ct, GrRenderable renderable) const {
-        return INHERITED::defaultBackendFormat(ct, renderable);
-    }
-
     // Provides access to functions that aren't part of the public API.
     GrImageContextPriv priv();
     const GrImageContextPriv priv() const;
@@ -29,7 +25,7 @@
 protected:
     friend class GrImageContextPriv; // for hidden functions
 
-    GrImageContext(GrBackendApi, const GrContextOptions&, uint32_t contextID);
+    GrImageContext(sk_sp<GrContextThreadSafeProxy>);
 
     SK_API virtual void abandonContext();
     SK_API virtual bool abandoned();
@@ -44,7 +40,6 @@
 
 private:
     std::unique_ptr<GrProxyProvider> fProxyProvider;
-    bool                             fAbandoned = false;
 
     // In debug builds we guard against improper thread handling
     // This guard is passed to the GrDrawingManager and, from there to all the
diff --git a/include/private/GrRecordingContext.h b/include/private/GrRecordingContext.h
index 921731c..945ed3e 100644
--- a/include/private/GrRecordingContext.h
+++ b/include/private/GrRecordingContext.h
@@ -75,8 +75,8 @@
         std::unique_ptr<SkArenaAlloc>   fRecordTimeAllocator;
     };
 
-    GrRecordingContext(GrBackendApi, const GrContextOptions&, uint32_t contextID);
-    bool init(sk_sp<const GrCaps>) override;
+    GrRecordingContext(sk_sp<GrContextThreadSafeProxy>);
+    bool init() override;
     void setupDrawingManager(bool sortOpsTasks, bool reduceOpsTaskSplitting);
 
     void abandonContext() override;
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 956a2e5..5bff036 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -48,8 +48,7 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-GrContext::GrContext(GrBackendApi backend, const GrContextOptions& options, int32_t contextID)
-        : INHERITED(backend, options, contextID) {
+GrContext::GrContext(sk_sp<GrContextThreadSafeProxy> proxy) : INHERITED(std::move(proxy)) {
     fResourceCache = nullptr;
     fResourceProvider = nullptr;
 }
@@ -64,15 +63,14 @@
     delete fResourceCache;
 }
 
-bool GrContext::init(sk_sp<const GrCaps> caps) {
+bool GrContext::init() {
     ASSERT_SINGLE_OWNER
     SkASSERT(this->proxyProvider());
 
-    if (!INHERITED::init(std::move(caps))) {
+    if (!INHERITED::init()) {
         return false;
     }
 
-    SkASSERT(this->caps());
     SkASSERT(this->getTextBlobCache());
 
     if (fGpu) {
@@ -104,7 +102,7 @@
 }
 
 sk_sp<GrContextThreadSafeProxy> GrContext::threadSafeProxy() {
-    return fThreadSafeProxy;
+    return INHERITED::threadSafeProxy();
 }
 
 //////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/GrContextPriv.h b/src/gpu/GrContextPriv.h
index d97f7ad..c5d3f72 100644
--- a/src/gpu/GrContextPriv.h
+++ b/src/gpu/GrContextPriv.h
@@ -74,7 +74,7 @@
     /**
      * Create a GrContext without a resource cache
      */
-    static sk_sp<GrContext> MakeDDL(const sk_sp<GrContextThreadSafeProxy>&);
+    static sk_sp<GrContext> MakeDDL(sk_sp<GrContextThreadSafeProxy>);
 
     /**
      * Finalizes all pending reads and writes to the surfaces and also performs an MSAA resolves
diff --git a/src/gpu/GrContextThreadSafeProxy.cpp b/src/gpu/GrContextThreadSafeProxy.cpp
index af92057..6fd86bd 100644
--- a/src/gpu/GrContextThreadSafeProxy.cpp
+++ b/src/gpu/GrContextThreadSafeProxy.cpp
@@ -19,16 +19,24 @@
 #include "src/gpu/vk/GrVkCaps.h"
 #endif
 
+static int32_t next_id() {
+    static std::atomic<int32_t> nextID{1};
+    int32_t id;
+    do {
+        id = nextID++;
+    } while (id == SK_InvalidGenID);
+    return id;
+}
+
 GrContextThreadSafeProxy::GrContextThreadSafeProxy(GrBackendApi backend,
-                                                   const GrContextOptions& options,
-                                                   uint32_t contextID)
-        : INHERITED(backend, options, contextID) {
+                                                   const GrContextOptions& options)
+        : fBackend(backend), fOptions(options), fContextID(next_id()) {
 }
 
 GrContextThreadSafeProxy::~GrContextThreadSafeProxy() = default;
 
-bool GrContextThreadSafeProxy::init(sk_sp<const GrCaps> caps) {
-    return INHERITED::init(std::move(caps));
+void GrContextThreadSafeProxy::init(sk_sp<const GrCaps> caps) {
+    fCaps = std::move(caps);
 }
 
 SkSurfaceCharacterization GrContextThreadSafeProxy::createCharacterization(
@@ -38,6 +46,7 @@
                                      const SkSurfaceProps& surfaceProps,
                                      bool isMipMapped, bool willUseGLFBO0, bool isTextureable,
                                      GrProtected isProtected) {
+    SkASSERT(fCaps);
     if (!backendFormat.isValid()) {
         return SkSurfaceCharacterization(); // return an invalid characterization
     }
@@ -49,39 +58,39 @@
         return SkSurfaceCharacterization(); // return an invalid characterization
     }
 
-    if (!this->caps()->mipMapSupport()) {
+    if (!fCaps->mipMapSupport()) {
         isMipMapped = false;
     }
 
     GrColorType grColorType = SkColorTypeToGrColorType(ii.colorType());
 
-    if (!this->caps()->areColorTypeAndFormatCompatible(grColorType, backendFormat)) {
+    if (!fCaps->areColorTypeAndFormatCompatible(grColorType, backendFormat)) {
         return SkSurfaceCharacterization(); // return an invalid characterization
     }
 
-    if (!this->caps()->isFormatAsColorTypeRenderable(grColorType, backendFormat, sampleCnt)) {
+    if (!fCaps->isFormatAsColorTypeRenderable(grColorType, backendFormat, sampleCnt)) {
         return SkSurfaceCharacterization(); // return an invalid characterization
     }
 
-    sampleCnt = this->caps()->getRenderTargetSampleCount(sampleCnt, backendFormat);
+    sampleCnt = fCaps->getRenderTargetSampleCount(sampleCnt, backendFormat);
     SkASSERT(sampleCnt);
 
     if (willUseGLFBO0 && isTextureable) {
         return SkSurfaceCharacterization(); // return an invalid characterization
     }
 
-    if (isTextureable && !this->caps()->isFormatTexturable(backendFormat)) {
+    if (isTextureable && !fCaps->isFormatTexturable(backendFormat)) {
         // Skia doesn't agree that this is textureable.
         return SkSurfaceCharacterization(); // return an invalid characterization
     }
 
     if (GrBackendApi::kVulkan == backendFormat.backend()) {
-        if (GrBackendApi::kVulkan != this->backend()) {
+        if (GrBackendApi::kVulkan != fBackend) {
             return SkSurfaceCharacterization(); // return an invalid characterization
         }
 
 #ifdef SK_VULKAN
-        const GrVkCaps* vkCaps = (const GrVkCaps*) this->caps();
+        const GrVkCaps* vkCaps = (const GrVkCaps*) fCaps.get();
 
         // The protection status of the characterization and the context need to match
         if (isProtected != GrProtected(vkCaps->supportsProtectedMemory())) {
@@ -101,6 +110,22 @@
                                      surfaceProps);
 }
 
+GrBackendFormat GrContextThreadSafeProxy::defaultBackendFormat(SkColorType skColorType,
+                                                               GrRenderable renderable) const {
+    SkASSERT(fCaps);
+    GrColorType grColorType = SkColorTypeToGrColorType(skColorType);
+
+    GrBackendFormat format = fCaps->getDefaultBackendFormat(grColorType, renderable);
+    if (!format.isValid()) {
+        return GrBackendFormat();
+    }
+
+    SkASSERT(renderable == GrRenderable::kNo ||
+             fCaps->isFormatAsColorTypeRenderable(grColorType, format));
+
+    return format;
+}
+
 void GrContextThreadSafeProxy::abandonContext() {
     fAbandoned.store(true, std::memory_order_relaxed);
 }
@@ -112,15 +137,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 sk_sp<GrContextThreadSafeProxy> GrContextThreadSafeProxyPriv::Make(
                              GrBackendApi backend,
-                             const GrContextOptions& options,
-                             uint32_t contextID,
-                             sk_sp<const GrCaps> caps) {
-    sk_sp<GrContextThreadSafeProxy> proxy(new GrContextThreadSafeProxy(backend, options,
-                                                                       contextID));
-
-    if (!proxy->init(std::move(caps))) {
-        return nullptr;
-    }
-    return proxy;
+                             const GrContextOptions& options) {
+    return sk_sp<GrContextThreadSafeProxy>(new GrContextThreadSafeProxy(backend, options));
 }
 
diff --git a/src/gpu/GrContextThreadSafeProxyPriv.h b/src/gpu/GrContextThreadSafeProxyPriv.h
index 00662b7..c4873bb 100644
--- a/src/gpu/GrContextThreadSafeProxyPriv.h
+++ b/src/gpu/GrContextThreadSafeProxyPriv.h
@@ -9,6 +9,7 @@
 #define GrContextThreadSafeProxyPriv_DEFINED
 
 #include "include/gpu/GrContextThreadSafeProxy.h"
+#include "include/private/GrContext_Base.h"
 
 #include "src/gpu/GrCaps.h"
 
@@ -19,24 +20,24 @@
  */
 class GrContextThreadSafeProxyPriv {
 public:
-    // from GrContext_Base
-    uint32_t contextID() const { return fProxy->contextID(); }
+    void init(sk_sp<const GrCaps> caps) const { fProxy->init(std::move(caps)); }
 
-    bool matches(GrContext_Base* candidate) const { return fProxy->matches(candidate); }
+    bool matches(GrContext_Base* candidate) const {
+        return fProxy == candidate->threadSafeProxy().get();
+    }
 
-    const GrContextOptions& options() const { return fProxy->options(); }
+    GrBackend backend() const { return fProxy->fBackend; }
+    const GrContextOptions& options() const { return fProxy->fOptions; }
+    uint32_t contextID() const { return fProxy->fContextID; }
 
-    const GrCaps* caps() const { return fProxy->caps(); }
-    sk_sp<const GrCaps> refCaps() const { return fProxy->refCaps(); }
+    const GrCaps* caps() const { return fProxy->fCaps.get(); }
+    sk_sp<const GrCaps> refCaps() const { return fProxy->fCaps; }
 
     void abandonContext() { fProxy->abandonContext(); }
     bool abandoned() const { return fProxy->abandoned(); }
 
     // GrContextThreadSafeProxyPriv
-    static sk_sp<GrContextThreadSafeProxy> Make(GrBackendApi,
-                                                const GrContextOptions&,
-                                                uint32_t contextID,
-                                                sk_sp<const GrCaps>);
+    static sk_sp<GrContextThreadSafeProxy> Make(GrBackendApi, const GrContextOptions&);
 
 private:
     explicit GrContextThreadSafeProxyPriv(GrContextThreadSafeProxy* proxy) : fProxy(proxy) {}
diff --git a/src/gpu/GrContext_Base.cpp b/src/gpu/GrContext_Base.cpp
index 24a7f20..3426299 100644
--- a/src/gpu/GrContext_Base.cpp
+++ b/src/gpu/GrContext_Base.cpp
@@ -13,52 +13,31 @@
 #include "src/gpu/GrShaderUtils.h"
 #include "src/gpu/effects/GrSkSLFP.h"
 
-static int32_t next_id() {
-    static std::atomic<int32_t> nextID{1};
-    int32_t id;
-    do {
-        id = nextID++;
-    } while (id == SK_InvalidGenID);
-    return id;
-}
-
-GrContext_Base::GrContext_Base(GrBackendApi backend,
-                               const GrContextOptions& options,
-                               uint32_t contextID)
-        : fBackend(backend)
-        , fOptions(options)
-        , fContextID(SK_InvalidGenID == contextID ? next_id() : contextID) {
+GrContext_Base::GrContext_Base(sk_sp<GrContextThreadSafeProxy> proxy)
+        : fThreadSafeProxy(std::move(proxy)) {
 }
 
 GrContext_Base::~GrContext_Base() { }
 
-bool GrContext_Base::init(sk_sp<const GrCaps> caps) {
-    SkASSERT(caps);
-    // We either are a thread safe proxy and we don't have one, or we aren't and we do.
-    SkASSERT((nullptr == this->asThreadSafeProxy()) != (nullptr == fThreadSafeProxy));
+bool GrContext_Base::init() {
+    SkASSERT(fThreadSafeProxy->isValid());
 
-    fCaps = std::move(caps);
     return true;
 }
 
-const GrCaps* GrContext_Base::caps() const { return fCaps.get(); }
-sk_sp<const GrCaps> GrContext_Base::refCaps() const { return fCaps; }
+uint32_t GrContext_Base::contextID() const { return fThreadSafeProxy->priv().contextID(); }
+GrBackendApi GrContext_Base::backend() const { return fThreadSafeProxy->priv().backend(); }
+
+const GrContextOptions& GrContext_Base::options() const {
+    return fThreadSafeProxy->priv().options();
+}
+
+const GrCaps* GrContext_Base::caps() const { return fThreadSafeProxy->priv().caps(); }
+sk_sp<const GrCaps> GrContext_Base::refCaps() const { return fThreadSafeProxy->priv().refCaps(); }
 
 GrBackendFormat GrContext_Base::defaultBackendFormat(SkColorType skColorType,
                                                      GrRenderable renderable) const {
-    const GrCaps* caps = this->caps();
-
-    GrColorType grColorType = SkColorTypeToGrColorType(skColorType);
-
-    GrBackendFormat format = caps->getDefaultBackendFormat(grColorType, renderable);
-    if (!format.isValid()) {
-        return GrBackendFormat();
-    }
-
-    SkASSERT(renderable == GrRenderable::kNo ||
-             caps->isFormatAsColorTypeRenderable(grColorType, format));
-
-    return format;
+    return fThreadSafeProxy->defaultBackendFormat(skColorType, renderable);
 }
 
 GrBackendFormat GrContext_Base::compressedBackendFormat(SkImage::CompressionType c) const {
@@ -70,6 +49,8 @@
     return format;
 }
 
+sk_sp<GrContextThreadSafeProxy> GrContext_Base::threadSafeProxy() { return fThreadSafeProxy; }
+
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 sk_sp<const GrCaps> GrBaseContextPriv::refCaps() const {
     return fContext->refCaps();
diff --git a/src/gpu/GrDDLContext.cpp b/src/gpu/GrDDLContext.cpp
index 09f7f4f..159d99d 100644
--- a/src/gpu/GrDDLContext.cpp
+++ b/src/gpu/GrDDLContext.cpp
@@ -21,8 +21,7 @@
 class GrDDLContext final : public GrContext {
 public:
     GrDDLContext(sk_sp<GrContextThreadSafeProxy> proxy)
-            : INHERITED(proxy->backend(), proxy->priv().options(), proxy->priv().contextID()) {
-        fThreadSafeProxy = std::move(proxy);
+        : INHERITED(std::move(proxy)) {
     }
 
     ~GrDDLContext() override {}
@@ -47,10 +46,8 @@
     // GrRecordingContext!
     GrContext* asDirectContext() override { return nullptr; }
 
-    bool init(sk_sp<const GrCaps> caps) override {
-        SkASSERT(caps);
-
-        if (!INHERITED::init(std::move(caps))) {
+    bool init() override {
+        if (!INHERITED::init()) {
             return false;
         }
 
@@ -58,8 +55,6 @@
         // splitting.
         this->setupDrawingManager(true, true);
 
-        SkASSERT(this->caps());
-
         return true;
     }
 
@@ -152,10 +147,10 @@
     typedef GrContext INHERITED;
 };
 
-sk_sp<GrContext> GrContextPriv::MakeDDL(const sk_sp<GrContextThreadSafeProxy>& proxy) {
-    sk_sp<GrContext> context(new GrDDLContext(proxy));
+sk_sp<GrContext> GrContextPriv::MakeDDL(sk_sp<GrContextThreadSafeProxy> proxy) {
+    sk_sp<GrContext> context(new GrDDLContext(std::move(proxy)));
 
-    if (!context->init(proxy->priv().refCaps())) {
+    if (!context->init()) {
         return nullptr;
     }
     return context;
diff --git a/src/gpu/GrImageContext.cpp b/src/gpu/GrImageContext.cpp
index 560ca6c..8993a38 100644
--- a/src/gpu/GrImageContext.cpp
+++ b/src/gpu/GrImageContext.cpp
@@ -14,10 +14,8 @@
 #include "src/gpu/effects/GrSkSLFP.h"
 
 ///////////////////////////////////////////////////////////////////////////////////////////////////
-GrImageContext::GrImageContext(GrBackendApi backend,
-                               const GrContextOptions& options,
-                               uint32_t contextID)
-            : INHERITED(backend, options, contextID) {
+GrImageContext::GrImageContext(sk_sp<GrContextThreadSafeProxy> proxy)
+            : INHERITED(std::move(proxy)) {
     fProxyProvider.reset(new GrProxyProvider(this));
 }
 
diff --git a/src/gpu/GrLegacyDirectContext.cpp b/src/gpu/GrLegacyDirectContext.cpp
index 595807e..07be4fb 100644
--- a/src/gpu/GrLegacyDirectContext.cpp
+++ b/src/gpu/GrLegacyDirectContext.cpp
@@ -40,7 +40,7 @@
 class GrLegacyDirectContext : public GrContext {
 public:
     GrLegacyDirectContext(GrBackendApi backend, const GrContextOptions& options)
-            : INHERITED(backend, options)
+            : INHERITED(GrContextThreadSafeProxyPriv::Make(backend, options))
             , fAtlasManager(nullptr) {
     }
 
@@ -72,16 +72,14 @@
     }
 
 protected:
-    bool init(sk_sp<const GrCaps> caps) override {
-        SkASSERT(caps);
-        SkASSERT(!fThreadSafeProxy);
+    bool init() override {
+        const GrGpu* gpu = this->priv().getGpu();
+        if (!gpu) {
+            return false;
+        }
 
-        fThreadSafeProxy = GrContextThreadSafeProxyPriv::Make(this->backend(),
-                                                              this->options(),
-                                                              this->contextID(),
-                                                              caps);
-
-        if (!INHERITED::init(std::move(caps))) {
+        fThreadSafeProxy->priv().init(gpu->refCaps());
+        if (!INHERITED::init()) {
             return false;
         }
 
@@ -94,8 +92,6 @@
 
         this->setupDrawingManager(true, reduceOpsTaskSplitting);
 
-        SkASSERT(this->caps());
-
         GrDrawOpAtlas::AllowMultitexturing allowMultitexturing;
         if (GrContextOptions::Enable::kNo == this->options().fAllowMultipleGlyphCacheTextures ||
             // multitexturing supported only if range can represent the index + texcoords fully
@@ -144,11 +140,7 @@
     sk_sp<GrContext> context(new GrLegacyDirectContext(GrBackendApi::kOpenGL, options));
 
     context->fGpu = GrGLGpu::Make(std::move(glInterface), options, context.get());
-    if (!context->fGpu) {
-        return nullptr;
-    }
-
-    if (!context->init(context->fGpu->refCaps())) {
+    if (!context->init()) {
         return nullptr;
     }
     return context;
@@ -165,11 +157,7 @@
     sk_sp<GrContext> context(new GrLegacyDirectContext(GrBackendApi::kMock, options));
 
     context->fGpu = GrMockGpu::Make(mockOptions, options, context.get());
-    if (!context->fGpu) {
-        return nullptr;
-    }
-
-    if (!context->init(context->fGpu->refCaps())) {
+    if (!context->init()) {
         return nullptr;
     }
 
@@ -191,13 +179,10 @@
     sk_sp<GrContext> context(new GrLegacyDirectContext(GrBackendApi::kVulkan, options));
 
     context->fGpu = GrVkGpu::Make(backendContext, options, context.get());
-    if (!context->fGpu) {
+    if (!context->init()) {
         return nullptr;
     }
 
-    if (!context->init(context->fGpu->refCaps())) {
-        return nullptr;
-    }
     return context;
 #else
     return nullptr;
@@ -214,13 +199,10 @@
     sk_sp<GrContext> context(new GrLegacyDirectContext(GrBackendApi::kMetal, options));
 
     context->fGpu = GrMtlTrampoline::MakeGpu(context.get(), options, device, queue);
-    if (!context->fGpu) {
+    if (!context->init()) {
         return nullptr;
     }
 
-    if (!context->init(context->fGpu->refCaps())) {
-        return nullptr;
-    }
     return context;
 }
 #endif
@@ -236,13 +218,10 @@
     sk_sp<GrContext> context(new GrLegacyDirectContext(GrBackendApi::kDirect3D, options));
 
     context->fGpu = GrD3DGpu::Make(backendContext, options, context.get());
-    if (!context->fGpu) {
+    if (!context->init()) {
         return nullptr;
     }
 
-    if (!context->init(context->fGpu->refCaps())) {
-        return nullptr;
-    }
     return context;
 }
 #endif
@@ -257,13 +236,10 @@
     sk_sp<GrContext> context(new GrLegacyDirectContext(GrBackendApi::kDawn, options));
 
     context->fGpu = GrDawnGpu::Make(device, options, context.get());
-    if (!context->fGpu) {
+    if (!context->init()) {
         return nullptr;
     }
 
-    if (!context->init(context->fGpu->refCaps())) {
-        return nullptr;
-    }
     return context;
 }
 #endif
diff --git a/src/gpu/GrRecordingContext.cpp b/src/gpu/GrRecordingContext.cpp
index a588ebc..1743c04 100644
--- a/src/gpu/GrRecordingContext.cpp
+++ b/src/gpu/GrRecordingContext.cpp
@@ -8,6 +8,7 @@
 #include "include/private/GrRecordingContext.h"
 
 #include "include/gpu/GrContext.h"
+#include "include/gpu/GrContextThreadSafeProxy.h"
 #include "src/core/SkArenaAlloc.h"
 #include "src/gpu/GrAuditTrail.h"
 #include "src/gpu/GrCaps.h"
@@ -35,18 +36,16 @@
 
 GrRecordingContext::ProgramData::~ProgramData() = default;
 
-GrRecordingContext::GrRecordingContext(GrBackendApi backend,
-                                       const GrContextOptions& options,
-                                       uint32_t contextID)
-        : INHERITED(backend, options, contextID)
+GrRecordingContext::GrRecordingContext(sk_sp<GrContextThreadSafeProxy> proxy)
+        : INHERITED(std::move(proxy))
         , fAuditTrail(new GrAuditTrail()) {
 }
 
 GrRecordingContext::~GrRecordingContext() = default;
 
-bool GrRecordingContext::init(sk_sp<const GrCaps> caps) {
+bool GrRecordingContext::init() {
 
-    if (!INHERITED::init(std::move(caps))) {
+    if (!INHERITED::init()) {
         return false;
     }