Add outline of new GrContext hierarchy

This begins the process of splitting GrContext into:

GrContext_Base, GrImageContext, GrRecordingContext and GrDirectContext.

Change-Id: I3c43045f2a5549b049e95791d65f74d4e16de36f
Reviewed-on: https://skia-review.googlesource.com/c/186878
Commit-Queue: Robert Phillips <robertphillips@google.com>
Reviewed-by: Brian Salomon <bsalomon@google.com>
diff --git a/gn/gpu.gni b/gn/gpu.gni
index 47106aa..75fda8f 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -34,13 +34,16 @@
   # Private includes
   "$_include/private/GrAuditTrail.h",
   "$_include/private/GrColor.h",
+  "$_include/private/GrContext_Base.h",
   "$_include/private/GrCCClipPath.h",
   "$_include/private/GrCCPerOpListPaths.h",
+  "$_include/private/GrImageContext.h",
   "$_include/private/GrOpList.h",
   "$_include/private/GrProxyRef.h",
-  "$_include/private/GrSingleOwner.h",
+  "$_include/private/GrRecordingContext.h",
   "$_include/private/GrRenderTargetProxy.h",
   "$_include/private/GrResourceKey.h",
+  "$_include/private/GrSingleOwner.h",
   "$_include/private/GrSurfaceProxy.h",
   "$_include/private/GrTextureProxy.h",
   "$_include/private/GrTypesPriv.h",
@@ -54,6 +57,7 @@
   "$_src/gpu/GrBackendTextureImageGenerator.h",
   "$_src/gpu/GrAHardwareBufferImageGenerator.cpp",
   "$_src/gpu/GrAHardwareBufferImageGenerator.h",
+  "$_src/gpu/GrBaseContextPriv.h",
   "$_src/gpu/GrBitmapTextureMaker.cpp",
   "$_src/gpu/GrBitmapTextureMaker.h",
   "$_src/gpu/GrBlurUtils.cpp",
@@ -71,6 +75,7 @@
   "$_src/gpu/GrColorSpaceXform.cpp",
   "$_src/gpu/GrColorSpaceXform.h",
   "$_src/gpu/GrContext.cpp",
+  "$_src/gpu/GrContext_Base.cpp",
   "$_src/gpu/GrContextPriv.h",
   "$_src/gpu/GrContextThreadSafeProxy.cpp",
   "$_src/gpu/GrContextThreadSafeProxyPriv.h",
@@ -105,6 +110,8 @@
   "$_src/gpu/GrGpuCommandBuffer.h",
   "$_src/gpu/GrGpuResourcePriv.h",
   "$_src/gpu/GrGpuResource.cpp",
+  "$_src/gpu/GrImageContext.cpp",
+  "$_src/gpu/GrImageContextPriv.h",
   "$_src/gpu/GrImageTextureMaker.cpp",
   "$_src/gpu/GrImageTextureMaker.h",
   "$_src/gpu/GrMemoryPool.cpp",
@@ -143,6 +150,8 @@
   "$_src/gpu/GrProxyProvider.h",
   "$_src/gpu/GrQuad.cpp",
   "$_src/gpu/GrQuad.h",
+  "$_src/gpu/GrRecordingContext.cpp",
+  "$_src/gpu/GrRecordingContextPriv.h",
   "$_src/gpu/GrRect.h",
   "$_src/gpu/GrRectanizer.h",
   "$_src/gpu/GrRectanizer_pow2.cpp",
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index 54564ae..709ec22 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -12,6 +12,7 @@
 #include "SkPathEffect.h"
 #include "SkTypes.h"
 #include "../private/GrAuditTrail.h"
+#include "../private/GrRecordingContext.h"
 #include "../private/GrSingleOwner.h"
 #include "GrContextOptions.h"
 
@@ -50,7 +51,7 @@
 class SkTaskGroup;
 class SkTraceMemoryDump;
 
-class SK_API GrContext : public SkRefCnt {
+class SK_API GrContext : public GrRecordingContext {
 public:
     /**
      * Creates a GrContext for a backend context. If no GrGLInterface is provided then the result of
@@ -266,11 +267,6 @@
     GrSemaphoresSubmitted flushAndSignalSemaphores(int numSemaphores,
                                                    GrBackendSemaphore signalSemaphores[]);
 
-    /**
-     * An ID associated with this context, guaranteed to be unique.
-     */
-    uint32_t uniqueID() { return fUniqueID; }
-
     // Provides access to functions that aren't part of the public API.
     GrContextPriv contextPriv();
     const GrContextPriv contextPriv() const;
@@ -291,7 +287,6 @@
 
     virtual GrAtlasManager* onGetAtlasManager() = 0;
 
-    const GrBackendApi                         fBackend;
     sk_sp<const GrCaps>                     fCaps;
     sk_sp<GrContextThreadSafeProxy>         fThreadSafeProxy;
     sk_sp<GrSkSLFPFactoryCache>             fFPFactoryCache;
@@ -324,8 +319,6 @@
     // GrRenderTargetContexts.  It is also passed to the GrResourceProvider and SkGpuDevice.
     mutable GrSingleOwner                   fSingleOwner;
 
-    const uint32_t                          fUniqueID;
-
     std::unique_ptr<GrDrawingManager>       fDrawingManager;
 
     GrAuditTrail                            fAuditTrail;
@@ -354,7 +347,7 @@
      */
     static void TextBlobCacheOverBudgetCB(void* data);
 
-    typedef SkRefCnt INHERITED;
+    typedef GrRecordingContext INHERITED;
 };
 
 #endif
diff --git a/include/private/GrContext_Base.h b/include/private/GrContext_Base.h
new file mode 100644
index 0000000..545a504
--- /dev/null
+++ b/include/private/GrContext_Base.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrContext_Base_DEFINED
+#define GrContext_Base_DEFINED
+
+#include "SkRefCnt.h"
+#include "GrTypes.h"
+
+class GrBaseContextPriv;
+class GrContext;
+class GrImageContext;
+class GrRecordingContext;
+
+class SK_API GrContext_Base : public SkRefCnt {
+public:
+    virtual ~GrContext_Base();
+
+    /*
+     * The 3D API backing this context
+     */
+    GrBackendApi backend() const { return fBackend; }
+
+    /**
+     * An identifier for this context. The id is used by all compatible contexts. For example,
+     * if SkImages are created on one thread using an image creation context, then fed into a
+     * DDL Recorder on second thread (which has a recording context) and finally replayed on
+     * 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 uniqueID() const { return fUniqueID; }
+
+    // Provides access to functions that aren't part of the public API.
+    GrBaseContextPriv priv();
+    const GrBaseContextPriv priv() const;
+
+protected:
+    friend class GrBaseContextPriv; // for hidden functions
+
+    GrContext_Base(GrBackendApi backend, uint32_t uniqueID);
+
+    GrContext_Base* asBaseContext() { return this; }
+    virtual GrImageContext* asImageContext() { return nullptr; }
+    virtual GrRecordingContext* asRecordingContext() { return nullptr; }
+    virtual GrContext* asDirectContext() { return nullptr; }
+
+private:
+    const GrBackendApi fBackend;
+    const uint32_t     fUniqueID;
+
+    typedef SkRefCnt INHERITED;
+};
+
+#endif
diff --git a/include/private/GrImageContext.h b/include/private/GrImageContext.h
new file mode 100644
index 0000000..54395e2
--- /dev/null
+++ b/include/private/GrImageContext.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrImageContext_DEFINED
+#define GrImageContext_DEFINED
+
+#include "GrContext_Base.h"
+
+class GrImageContextPriv;
+
+class SK_API GrImageContext : public GrContext_Base {
+public:
+    ~GrImageContext() override;
+
+    // Provides access to functions that aren't part of the public API.
+    GrImageContextPriv priv();
+    const GrImageContextPriv priv() const;
+
+protected:
+    friend class GrImageContextPriv; // for hidden functions
+
+    GrImageContext(GrBackendApi backend, uint32_t uniqueID);
+
+    GrImageContext* asImageContext() override { return this; }
+
+private:
+    typedef GrContext_Base INHERITED;
+};
+
+#endif
diff --git a/include/private/GrRecordingContext.h b/include/private/GrRecordingContext.h
new file mode 100644
index 0000000..abe6d7e
--- /dev/null
+++ b/include/private/GrRecordingContext.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrRecordingContext_DEFINED
+#define GrRecordingContext_DEFINED
+
+#include "GrImageContext.h"
+
+class GrRecordingContextPriv;
+
+class SK_API GrRecordingContext : public GrImageContext {
+public:
+    ~GrRecordingContext() override;
+
+    // Provides access to functions that aren't part of the public API.
+    GrRecordingContextPriv priv();
+    const GrRecordingContextPriv priv() const;
+
+protected:
+    friend class GrRecordingContextPriv; // for hidden functions
+
+    GrRecordingContext(GrBackendApi backend, uint32_t uniqueID);
+
+    GrRecordingContext* asRecordingContext() override { return this; }
+
+private:
+    typedef GrImageContext INHERITED;
+};
+
+#endif
diff --git a/samplecode/SampleCCPRGeometry.cpp b/samplecode/SampleCCPRGeometry.cpp
index 6de506f..8969b5a 100644
--- a/samplecode/SampleCCPRGeometry.cpp
+++ b/samplecode/SampleCCPRGeometry.cpp
@@ -324,7 +324,7 @@
                                                       const SkRect& chainBounds) {
     GrResourceProvider* rp = state->resourceProvider();
     GrContext* context = state->gpu()->getContext();
-    GrGLGpu* glGpu = GrBackendApi::kOpenGL == context->contextPriv().getBackend()
+    GrGLGpu* glGpu = GrBackendApi::kOpenGL == context->backend()
                              ? static_cast<GrGLGpu*>(state->gpu())
                              : nullptr;
     if (glGpu) {
diff --git a/src/core/SkDeferredDisplayListRecorder.cpp b/src/core/SkDeferredDisplayListRecorder.cpp
index 34026e8..6aadf30 100644
--- a/src/core/SkDeferredDisplayListRecorder.cpp
+++ b/src/core/SkDeferredDisplayListRecorder.cpp
@@ -109,7 +109,7 @@
 
     bool usesGLFBO0 = fCharacterization.usesGLFBO0();
     if (usesGLFBO0) {
-        if (GrBackendApi::kOpenGL != fContext->contextPriv().getBackend() ||
+        if (GrBackendApi::kOpenGL != fContext->backend() ||
             fCharacterization.isTextureable()) {
             return false;
         }
diff --git a/src/gpu/GrAHardwareBufferImageGenerator.cpp b/src/gpu/GrAHardwareBufferImageGenerator.cpp
index 55eab91..c90e090 100644
--- a/src/gpu/GrAHardwareBufferImageGenerator.cpp
+++ b/src/gpu/GrAHardwareBufferImageGenerator.cpp
@@ -57,7 +57,7 @@
 }
 
 static bool can_import_protected_content(GrContext* context) {
-    if (GrBackendApi::kOpenGL == context->contextPriv().getBackend()) {
+    if (GrBackendApi::kOpenGL == context->backend()) {
         // Only compute whether the extension is present once the first time this
         // function is called.
         static bool hasIt = can_import_protected_content_eglimpl();
@@ -158,7 +158,7 @@
         GrAHardwareBufferImageGenerator::DeleteImageCtx* deleteCtx,
         bool isProtectedContent,
         const GrBackendFormat& backendFormat) {
-    SkASSERT(context->contextPriv().getBackend() == GrBackendApi::kVulkan);
+    SkASSERT(context->backend() == GrBackendApi::kVulkan);
     GrVkGpu* gpu = static_cast<GrVkGpu*>(context->contextPriv().getGpu());
 
     VkPhysicalDevice physicalDevice = gpu->physicalDevice();
@@ -434,11 +434,11 @@
     }
     bool createProtectedImage = isProtectedContent && can_import_protected_content(context);
 
-    if (GrBackendApi::kOpenGL == context->contextPriv().getBackend()) {
+    if (GrBackendApi::kOpenGL == context->backend()) {
         return make_gl_backend_texture(context, hardwareBuffer, width, height, config, deleteProc,
                                        deleteCtx, createProtectedImage, backendFormat);
     } else {
-        SkASSERT(GrBackendApi::kVulkan == context->contextPriv().getBackend());
+        SkASSERT(GrBackendApi::kVulkan == context->backend());
 #ifdef SK_VULKAN
         // Currently we don't support protected images on vulkan
         SkASSERT(!createProtectedImage);
@@ -542,7 +542,7 @@
     }
 
     GrBackendFormat backendFormat = get_backend_format(context, fHardwareBuffer,
-                                                       context->contextPriv().getBackend(),
+                                                       context->backend(),
                                                        fBufferFormat);
     GrPixelConfig pixelConfig = context->contextPriv().caps()->getConfigFromBackendFormat(
             backendFormat, this->getInfo().colorType());
@@ -560,9 +560,9 @@
     desc.fConfig = pixelConfig;
 
     GrTextureType textureType = GrTextureType::k2D;
-    if (context->contextPriv().getBackend() == GrBackendApi::kOpenGL) {
+    if (context->backend() == GrBackendApi::kOpenGL) {
         textureType = GrTextureType::kExternal;
-    } else if (context->contextPriv().getBackend() == GrBackendApi::kVulkan) {
+    } else if (context->backend() == GrBackendApi::kVulkan) {
         const VkFormat* format = backendFormat.getVkFormat();
         SkASSERT(format);
         if (*format == VK_FORMAT_UNDEFINED) {
@@ -653,8 +653,8 @@
     if (nullptr == context) {
         return false; //CPU backend is not supported, because hardware buffer can be swizzled
     }
-    return GrBackendApi::kOpenGL == context->contextPriv().getBackend() ||
-           GrBackendApi::kVulkan == context->contextPriv().getBackend();
+    return GrBackendApi::kOpenGL == context->backend() ||
+           GrBackendApi::kVulkan == context->backend();
 }
 
 #endif //SK_BUILD_FOR_ANDROID_FRAMEWORK
diff --git a/src/gpu/GrBackendTextureImageGenerator.cpp b/src/gpu/GrBackendTextureImageGenerator.cpp
index 674ca05..8f2dcd6 100644
--- a/src/gpu/GrBackendTextureImageGenerator.cpp
+++ b/src/gpu/GrBackendTextureImageGenerator.cpp
@@ -92,7 +92,7 @@
         GrContext* context, const SkImageInfo& info, const SkIPoint& origin, bool willNeedMipMaps) {
     SkASSERT(context);
 
-    if (context->contextPriv().getBackend() != fBackendTexture.backend()) {
+    if (context->backend() != fBackendTexture.backend()) {
         return nullptr;
     }
     if (info.colorType() != this->getInfo().colorType()) {
diff --git a/src/gpu/GrBaseContextPriv.h b/src/gpu/GrBaseContextPriv.h
new file mode 100644
index 0000000..c706082
--- /dev/null
+++ b/src/gpu/GrBaseContextPriv.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrBaseContextPriv_DEFINED
+#define GrBaseContextPriv_DEFINED
+
+#include "GrContext_Base.h"
+
+/** Class that exposes methods on GrContext_Base that are only intended for use internal to Skia.
+    This class is purely a privileged window into GrContext_Base. It should never have
+    additional data members or virtual methods. */
+class GrBaseContextPriv {
+public:
+    // from GrContext_Base
+
+private:
+    explicit GrBaseContextPriv(GrContext_Base* context) : fContext(context) {}
+    GrBaseContextPriv(const GrBaseContextPriv&); // unimpl
+    GrBaseContextPriv& operator=(const GrBaseContextPriv&); // unimpl
+
+    // No taking addresses of this type.
+    const GrBaseContextPriv* operator&() const;
+    GrBaseContextPriv* operator&();
+
+    GrContext_Base* fContext;
+
+    friend class GrContext_Base; // to construct/copy this type.
+};
+
+inline GrBaseContextPriv GrContext_Base::priv() { return GrBaseContextPriv(this); }
+
+inline const GrBaseContextPriv GrContext_Base::priv () const {
+    return GrBaseContextPriv(const_cast<GrContext_Base*>(this));
+}
+
+#endif
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index 657b7da..b6c8b93 100644
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -59,18 +59,8 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-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::GrContext(GrBackendApi backend, int32_t id)
-        : fBackend(backend)
-        , fUniqueID(SK_InvalidGenID == id ? next_id() : id) {
+        : INHERITED(backend, id) {
     fResourceCache = nullptr;
     fResourceProvider = nullptr;
     fProxyProvider = nullptr;
@@ -84,7 +74,7 @@
 
     if (fGpu) {
         fCaps = fGpu->refCaps();
-        fResourceCache = new GrResourceCache(fCaps.get(), &fSingleOwner, fUniqueID);
+        fResourceCache = new GrResourceCache(fCaps.get(), &fSingleOwner, this->uniqueID());
         fResourceProvider = new GrResourceProvider(fGpu.get(), fResourceCache, &fSingleOwner,
                                                    options.fExplicitlyAllocateGPUResources);
         fProxyProvider =
@@ -167,6 +157,10 @@
     delete fGlyphCache;
 }
 
+sk_sp<GrContextThreadSafeProxy> GrContext::threadSafeProxy() {
+    return fThreadSafeProxy;
+}
+
 //////////////////////////////////////////////////////////////////////////////
 
 void GrContext::abandonContext() {
@@ -1153,7 +1147,7 @@
     GR_STATIC_ASSERT(1 == (unsigned)GrBackendApi::kOpenGL);
     GR_STATIC_ASSERT(2 == (unsigned)GrBackendApi::kVulkan);
     GR_STATIC_ASSERT(3 == (unsigned)GrBackendApi::kMock);
-    writer.appendString("backend", kBackendStr[(unsigned)fContext->fBackend]);
+    writer.appendString("backend", kBackendStr[(unsigned)fContext->backend()]);
 
     writer.appendName("caps");
     fContext->fCaps->dumpJSON(&writer);
diff --git a/src/gpu/GrContextPriv.h b/src/gpu/GrContextPriv.h
index 24309ec..3ae9a9c 100644
--- a/src/gpu/GrContextPriv.h
+++ b/src/gpu/GrContextPriv.h
@@ -28,6 +28,13 @@
     data members or virtual methods. */
 class GrContextPriv {
 public:
+
+    // from GrContext_Base
+
+    // from GrImageContext
+
+    // from GrRecordingContext
+
     /**
      * Create a GrContext without a resource cache
      */
@@ -182,8 +189,6 @@
                             GrColorType srcColorType, SkColorSpace* srcColorSpace,
                             const void* buffer, size_t rowBytes, uint32_t pixelOpsFlags = 0);
 
-    GrBackendApi getBackend() const { return fContext->fBackend; }
-
     SkTaskGroup* getTaskGroup() { return fContext->fTaskGroup.get(); }
 
     GrProxyProvider* proxyProvider() { return fContext->fProxyProvider; }
diff --git a/src/gpu/GrContextThreadSafeProxy.cpp b/src/gpu/GrContextThreadSafeProxy.cpp
index cfa4b33..c9ba5c4 100644
--- a/src/gpu/GrContextThreadSafeProxy.cpp
+++ b/src/gpu/GrContextThreadSafeProxy.cpp
@@ -26,10 +26,6 @@
 
 GrContextThreadSafeProxy::~GrContextThreadSafeProxy() = default;
 
-sk_sp<GrContextThreadSafeProxy> GrContext::threadSafeProxy() {
-    return fThreadSafeProxy;
-}
-
 bool GrContextThreadSafeProxy::matches(GrContext* context) const {
     return context->uniqueID() == fContextUniqueID;
 }
diff --git a/src/gpu/GrContext_Base.cpp b/src/gpu/GrContext_Base.cpp
new file mode 100644
index 0000000..80e7a80
--- /dev/null
+++ b/src/gpu/GrContext_Base.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrContext_Base.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,
+                               uint32_t uniqueID)
+        : fBackend(backend)
+        , fUniqueID(SK_InvalidGenID == uniqueID ? next_id() : uniqueID) {
+}
+
+GrContext_Base::~GrContext_Base() {
+}
+
+
diff --git a/src/gpu/GrDirectContext.cpp b/src/gpu/GrDirectContext.cpp
index 9e6075c..688278d 100644
--- a/src/gpu/GrDirectContext.cpp
+++ b/src/gpu/GrDirectContext.cpp
@@ -64,7 +64,8 @@
         SkASSERT(!fFPFactoryCache);
         fFPFactoryCache.reset(new GrSkSLFPFactoryCache());
         fThreadSafeProxy.reset(new GrContextThreadSafeProxy(fCaps, this->uniqueID(),
-                                                            fBackend, options, fFPFactoryCache));
+                                                            this->backend(),
+                                                            options, fFPFactoryCache));
 
         if (!INHERITED::initCommon(options)) {
             return false;
diff --git a/src/gpu/GrImageContext.cpp b/src/gpu/GrImageContext.cpp
new file mode 100644
index 0000000..2b7c5b1
--- /dev/null
+++ b/src/gpu/GrImageContext.cpp
@@ -0,0 +1,14 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrImageContext.h"
+
+GrImageContext::GrImageContext(GrBackendApi backend, uint32_t uniqueID)
+            : INHERITED(backend, uniqueID) {
+}
+
+GrImageContext::~GrImageContext() {}
diff --git a/src/gpu/GrImageContextPriv.h b/src/gpu/GrImageContextPriv.h
new file mode 100644
index 0000000..2a49de9
--- /dev/null
+++ b/src/gpu/GrImageContextPriv.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrImageContextPriv_DEFINED
+#define GrImageContextPriv_DEFINED
+
+#include "GrImageContext.h"
+
+/** Class that exposes methods on GrImageContext that are only intended for use internal to Skia.
+    This class is purely a privileged window into GrImageContext. It should never have
+    additional data members or virtual methods. */
+class GrImageContextPriv {
+public:
+    // from GrContext_Base
+
+    // from GrImageContext
+
+private:
+    explicit GrImageContextPriv(GrImageContext* context) : fContext(context) {}
+    GrImageContextPriv(const GrImageContextPriv&); // unimpl
+    GrImageContextPriv& operator=(const GrImageContextPriv&); // unimpl
+
+    // No taking addresses of this type.
+    const GrImageContextPriv* operator&() const;
+    GrImageContextPriv* operator&();
+
+    GrImageContext* fContext;
+
+    friend class GrImageContext; // to construct/copy this type.
+};
+
+inline GrImageContextPriv GrImageContext::priv() { return GrImageContextPriv(this); }
+
+inline const GrImageContextPriv GrImageContext::priv () const {
+    return GrImageContextPriv(const_cast<GrImageContext*>(this));
+}
+
+#endif
diff --git a/src/gpu/GrRecordingContext.cpp b/src/gpu/GrRecordingContext.cpp
new file mode 100644
index 0000000..9c8f7a4
--- /dev/null
+++ b/src/gpu/GrRecordingContext.cpp
@@ -0,0 +1,15 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrRecordingContext.h"
+
+GrRecordingContext::GrRecordingContext(GrBackendApi backend, uint32_t uniqueID)
+        : INHERITED(backend, uniqueID) {
+}
+
+GrRecordingContext::~GrRecordingContext() { }
+
diff --git a/src/gpu/GrRecordingContextPriv.h b/src/gpu/GrRecordingContextPriv.h
new file mode 100644
index 0000000..0002b27
--- /dev/null
+++ b/src/gpu/GrRecordingContextPriv.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrRecordingContextPriv_DEFINED
+#define GrRecordingContextPriv_DEFINED
+
+#include "GrRecordingContext.h"
+
+/** Class that exposes methods to GrRecordingContext that are only intended for use internal to
+    Skia. This class is purely a privileged window into GrRecordingContext. It should never have
+    additional data members or virtual methods. */
+class GrRecordingContextPriv {
+public:
+    // from GrContext_Base
+
+    // from GrImageContext
+
+    // from GrRecordingContext
+
+private:
+    explicit GrRecordingContextPriv(GrRecordingContext* context) : fContext(context) {}
+    GrRecordingContextPriv(const GrRecordingContextPriv&); // unimpl
+    GrRecordingContextPriv& operator=(const GrRecordingContextPriv&); // unimpl
+
+    // No taking addresses of this type.
+    const GrRecordingContextPriv* operator&() const;
+    GrRecordingContextPriv* operator&();
+
+    GrRecordingContext* fContext;
+
+    friend class GrRecordingContext; // to construct/copy this type.
+};
+
+inline GrRecordingContextPriv GrRecordingContext::priv() { return GrRecordingContextPriv(this); }
+
+inline const GrRecordingContextPriv GrRecordingContext::priv () const {
+    return GrRecordingContextPriv(const_cast<GrRecordingContext*>(this));
+}
+
+#endif
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index d7c2d5e..6d2721b 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1757,7 +1757,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 void SkGpuDevice::drawDrawable(SkDrawable* drawable, const SkMatrix* matrix, SkCanvas* canvas) {
-    GrBackendApi api = this->context()->contextPriv().getBackend();
+    GrBackendApi api = this->context()->backend();
     if (GrBackendApi::kVulkan == api) {
         const SkMatrix& ctm = canvas->getTotalMatrix();
         const SkMatrix& combinedMatrix = matrix ? SkMatrix::Concat(ctm, *matrix) : ctm;
diff --git a/src/gpu/vk/GrVkSecondaryCBDrawContext.cpp b/src/gpu/vk/GrVkSecondaryCBDrawContext.cpp
index 83de36d..35d6353 100644
--- a/src/gpu/vk/GrVkSecondaryCBDrawContext.cpp
+++ b/src/gpu/vk/GrVkSecondaryCBDrawContext.cpp
@@ -23,7 +23,7 @@
         return nullptr;
     }
 
-    if (ctx->contextPriv().getBackend() != GrBackendApi::kVulkan) {
+    if (ctx->backend() != GrBackendApi::kVulkan) {
         return nullptr;
     }
 
diff --git a/tests/DeferredDisplayListTest.cpp b/tests/DeferredDisplayListTest.cpp
index e20bc82..dfaa33a 100644
--- a/tests/DeferredDisplayListTest.cpp
+++ b/tests/DeferredDisplayListTest.cpp
@@ -53,7 +53,7 @@
                                              GrPixelConfig config) {
     const GrCaps* caps = context->contextPriv().caps();
 
-    switch (context->contextPriv().getBackend()) {
+    switch (context->backend()) {
     case GrBackendApi::kOpenGL: {
         const GrGLCaps* glCaps = static_cast<const GrGLCaps*>(caps);
         GrGLStandard standard = glCaps->standard();
diff --git a/tests/PromiseImageTest.cpp b/tests/PromiseImageTest.cpp
index 78a3778..a542ef5 100644
--- a/tests/PromiseImageTest.cpp
+++ b/tests/PromiseImageTest.cpp
@@ -173,7 +173,7 @@
                                                                  expectedDoneCnt,
                                                                  reporter));
 
-        bool isVulkan = GrBackendApi::kVulkan == ctx->contextPriv().getBackend();
+        bool isVulkan = GrBackendApi::kVulkan == ctx->backend();
         canvas->flush();
         expectedFulfillCnt++;
         expectedReleaseCnt++;
@@ -328,7 +328,7 @@
                                                              expectedDoneCnt,
                                                              reporter));
 
-    bool isVulkan = GrBackendApi::kVulkan == ctx->contextPriv().getBackend();
+    bool isVulkan = GrBackendApi::kVulkan == ctx->backend();
     canvas->flush();
     expectedFulfillCnt++;
     expectedReleaseCnt++;
diff --git a/tests/TransferPixelsTest.cpp b/tests/TransferPixelsTest.cpp
index 5dd360d..7840480 100644
--- a/tests/TransferPixelsTest.cpp
+++ b/tests/TransferPixelsTest.cpp
@@ -70,7 +70,7 @@
     const int kTextureHeight = 16;
 #ifdef SK_BUILD_FOR_IOS
     // UNPACK_ROW_LENGTH is broken on iOS so rowBytes needs to match data width
-    const int kBufferWidth = GrBackendApi::kOpenGL == context->contextPriv().getBackend() ? 16 : 20;
+    const int kBufferWidth = GrBackendApi::kOpenGL == context->backend() ? 16 : 20;
 #else
     const int kBufferWidth = 20;
 #endif
@@ -144,7 +144,7 @@
         // transfer partial data
 #ifdef SK_BUILD_FOR_IOS
         // UNPACK_ROW_LENGTH is broken on iOS so we can't do partial transfers
-        if (GrBackendApi::kOpenGL == context->contextPriv().getBackend()) {
+        if (GrBackendApi::kOpenGL == context->backend()) {
             continue;
         }
 #endif