Revert "Revert "Make mock GrContext unit testable.""

This reverts commit c867a89b012c07e7e5cb719a31ed90e61f4a4901.

Reason for revert: test

Original change's description:
> Revert "Make mock GrContext unit testable."
> 
> This reverts commit 993e7e25217df05d63c3354c817e8bd18ea3738b.
> 
> Reason for revert: Seeing if this fixes the NexusPlayer bots
> 
> Original change's description:
> > Make mock GrContext unit testable.
> > 
> > Bug: skia:
> > Change-Id: I959122f1f2c390832ab1033bcdbdd2ca6cfc0419
> > Reviewed-on: https://skia-review.googlesource.com/20699
> > Reviewed-by: Greg Daniel <egdaniel@google.com>
> > Commit-Queue: Brian Salomon <bsalomon@google.com>
> 
> TBR=egdaniel@google.com,bsalomon@google.com
> 
> Change-Id: I25ed9329962d930fe38108f779ff7083e0e4847e
> No-Presubmit: true
> No-Tree-Checks: true
> No-Try: true
> Bug: skia:
> Reviewed-on: https://skia-review.googlesource.com/21731
> Reviewed-by: Brian Salomon <bsalomon@google.com>
> Commit-Queue: Brian Salomon <bsalomon@google.com>

TBR=egdaniel@google.com,bsalomon@google.com

Change-Id: I62c579e087db1ff9891cf6c41b3eb40f47561887
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: skia:
Reviewed-on: https://skia-review.googlesource.com/21733
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Salomon <bsalomon@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 9b2859c..d0bfa57 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -956,6 +956,7 @@
         "tools/gpu/gl/debug/GrTextureObj.cpp",
         "tools/gpu/gl/debug/GrTextureUnitObj.cpp",
         "tools/gpu/gl/null/NullGLTestContext.cpp",
+        "tools/gpu/mock/MockTestContext.cpp",
       ]
       libs = []
 
diff --git a/gn/gpu.gni b/gn/gpu.gni
index 622d8d1..253cf74 100644
--- a/gn/gpu.gni
+++ b/gn/gpu.gni
@@ -459,7 +459,13 @@
   "$_src/gpu/glsl/GrGLSLXferProcessor.h",
 
   # Mock
+  "$_src/gpu/mock/GrMockBuffer.h",
+  "$_src/gpu/mock/GrMockCaps.h",
+  "$_src/gpu/mock/GrMockGpu.cpp",
   "$_src/gpu/mock/GrMockGpu.h",
+  "$_src/gpu/mock/GrMockGpuCommandBuffer.h",
+  "$_src/gpu/mock/GrMockStencilAttachment.h",
+  "$_src/gpu/mock/GrMockTexture.h",
 
   # Sk files
   "$_src/gpu/SkGpuDevice.cpp",
diff --git a/include/gpu/GrTypes.h b/include/gpu/GrTypes.h
index 2175d92..1b90fb1 100644
--- a/include/gpu/GrTypes.h
+++ b/include/gpu/GrTypes.h
@@ -196,8 +196,9 @@
 
 /**
  * Backend-specific 3D context handle
- *      GrGLInterface* for OpenGL. If NULL will use the default GL interface.
- *      GrVkBackendContext* for Vulkan.
+ *      OpenGL: const GrGLInterface*. If null will use the result of GrGLCreateNativeInterface().
+ *      Vulkan: GrVkBackendContext*.
+ *      Mock: const GrMockOptions* or null for default constructed GrMockContextOptions.
  */
 typedef intptr_t GrBackendContext;
 
diff --git a/include/gpu/mock/GrMockOptions.h b/include/gpu/mock/GrMockOptions.h
new file mode 100644
index 0000000..b4d0336
--- /dev/null
+++ b/include/gpu/mock/GrMockOptions.h
@@ -0,0 +1,38 @@
+/*
+ * 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 GrMockOptions_DEFINED
+#define GrMockOptions_DEFINED
+
+#include "GrTypes.h"
+
+/**
+ * A pointer to this type is used as the GrBackendContext when creating a Mock GrContext. It can be
+ * used to specificy capability options for the mock context. If nullptr is used a default
+ * constructed GrMockOptions is used.
+ */
+struct GrMockOptions {
+    GrMockOptions() {
+        // By default RGBA_8888 is textureable and renderable and A8 is texturable.
+        fConfigOptions[kRGBA_8888_GrPixelConfig].fRenderable[0] = true;
+        fConfigOptions[kRGBA_8888_GrPixelConfig].fTexturable = true;
+        fConfigOptions[kAlpha_8_GrPixelConfig].fTexturable = true;
+    }
+
+    struct ConfigOptions {
+        /** The first value is for non-MSAA rendering, the second for MSAA. */
+        bool fRenderable[2] = {false, false};
+        bool fTexturable = false;
+    };
+
+    int fMaxTextureSize = 2048;
+    int fMaxRenderTargetSize = 2048;
+    int fMaxVertexAttributes = 16;
+    ConfigOptions fConfigOptions[kGrPixelConfigCnt];
+};
+
+#endif
diff --git a/src/gpu/GrTexturePriv.h b/src/gpu/GrTexturePriv.h
index 67631fc..8a256a4 100644
--- a/src/gpu/GrTexturePriv.h
+++ b/src/gpu/GrTexturePriv.h
@@ -56,12 +56,12 @@
     SkDestinationSurfaceColorMode mipColorMode() const { return fTexture->fMipColorMode; }
 
     static void ComputeScratchKey(const GrSurfaceDesc&, GrScratchKey*);
-
-private:
     static void ComputeScratchKey(GrPixelConfig config, int width, int height,
                                   GrSurfaceOrigin origin, bool isRenderTarget, int sampleCnt,
                                   bool isMipMapped, GrScratchKey* key);
 
+
+private:
     GrTexturePriv(GrTexture* texture) : fTexture(texture) { }
     GrTexturePriv(const GrTexturePriv& that) : fTexture(that.fTexture) { }
     GrTexturePriv& operator=(const GrTexturePriv&); // unimpl
diff --git a/src/gpu/mock/GrMockBuffer.h b/src/gpu/mock/GrMockBuffer.h
new file mode 100644
index 0000000..fdb812d
--- /dev/null
+++ b/src/gpu/mock/GrMockBuffer.h
@@ -0,0 +1,30 @@
+/*
+ * 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 GrMockBuffer_DEFINED
+#define GrMockBuffer_DEFINED
+
+#include "GrBuffer.h"
+#include "GrMockGpu.h"
+
+class GrMockBuffer : public GrBuffer {
+public:
+    GrMockBuffer(GrMockGpu* gpu, size_t sizeInBytes, GrBufferType type,
+                 GrAccessPattern accessPattern)
+            : INHERITED(gpu, sizeInBytes, type, accessPattern) {
+        this->registerWithCache(SkBudgeted::kYes);
+    }
+
+private:
+    void onMap() override {}
+    void onUnmap() override {}
+    bool onUpdateData(const void* src, size_t srcSizeInBytes) override { return true; }
+
+    typedef GrBuffer INHERITED;
+};
+
+#endif
diff --git a/src/gpu/mock/GrMockCaps.h b/src/gpu/mock/GrMockCaps.h
new file mode 100644
index 0000000..7190ad7
--- /dev/null
+++ b/src/gpu/mock/GrMockCaps.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 GrMockCaps_DEFINED
+#define GrMockCaps_DEFINED
+
+#include "GrCaps.h"
+#include "mock/GrMockOptions.h"
+
+class GrMockCaps : public GrCaps {
+public:
+    GrMockCaps(const GrContextOptions& contextOptions, const GrMockOptions& options)
+            : INHERITED(contextOptions), fOptions(options) {
+        fBufferMapThreshold = SK_MaxS32;
+        fMaxTextureSize = options.fMaxTextureSize;
+        fMaxRenderTargetSize = SkTMin(options.fMaxRenderTargetSize, fMaxTextureSize);
+        fMaxVertexAttributes = options.fMaxVertexAttributes;
+        fShaderCaps.reset(new GrShaderCaps(contextOptions));
+    }
+    bool isConfigTexturable(GrPixelConfig config) const override {
+        return fOptions.fConfigOptions[config].fTexturable;
+    }
+    bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const override {
+        return fOptions.fConfigOptions[config].fRenderable[withMSAA];
+    }
+    bool canConfigBeImageStorage(GrPixelConfig) const override { return false; }
+    bool initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc,
+                            bool* rectsMustMatch, bool* disallowSubrect) const override {
+        return false;
+    }
+
+private:
+    GrMockOptions fOptions;
+    typedef GrCaps INHERITED;
+};
+
+#endif
diff --git a/src/gpu/mock/GrMockGpu.cpp b/src/gpu/mock/GrMockGpu.cpp
new file mode 100644
index 0000000..70568e6
--- /dev/null
+++ b/src/gpu/mock/GrMockGpu.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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 "GrMockGpu.h"
+#include "GrMockBuffer.h"
+#include "GrMockCaps.h"
+#include "GrMockGpuCommandBuffer.h"
+#include "GrMockStencilAttachment.h"
+#include "GrMockTexture.h"
+
+GrGpu* GrMockGpu::Create(GrBackendContext backendContext, const GrContextOptions& contextOptions,
+                         GrContext* context) {
+    static const GrMockOptions kDefaultOptions = GrMockOptions();
+    const GrMockOptions* options = reinterpret_cast<const GrMockOptions*>(backendContext);
+    if (!options) {
+        options = &kDefaultOptions;
+    }
+    return new GrMockGpu(context, *options, contextOptions);
+}
+
+GrGpuCommandBuffer* GrMockGpu::createCommandBuffer(const GrGpuCommandBuffer::LoadAndStoreInfo&,
+                                                   const GrGpuCommandBuffer::LoadAndStoreInfo&) {
+    return new GrMockGpuCommandBuffer(this);
+}
+
+void GrMockGpu::submitCommandBuffer(const GrMockGpuCommandBuffer* cmdBuffer) {
+    for (int i = 0; i < cmdBuffer->numDraws(); ++i) {
+        fStats.incNumDraws();
+    }
+}
+
+GrMockGpu::GrMockGpu(GrContext* context, const GrMockOptions& options,
+                     const GrContextOptions& contextOptions)
+        : INHERITED(context) {
+    fCaps.reset(new GrMockCaps(contextOptions, options));
+}
+
+sk_sp<GrTexture> GrMockGpu::onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
+                                            const SkTArray<GrMipLevel>& texels) {
+    bool hasMipLevels = texels.count() > 1;
+    if (desc.fFlags & kRenderTarget_GrSurfaceFlag) {
+        return sk_sp<GrTexture>(new GrMockTextureRenderTarget(this, budgeted, desc, hasMipLevels));
+    }
+    return sk_sp<GrTexture>(new GrMockTexture(this, budgeted, desc, hasMipLevels));
+}
+
+GrBuffer* GrMockGpu::onCreateBuffer(size_t sizeInBytes, GrBufferType type,
+                                    GrAccessPattern accessPattern, const void*) {
+    return new GrMockBuffer(this, sizeInBytes, type, accessPattern);
+}
+
+GrStencilAttachment* GrMockGpu::createStencilAttachmentForRenderTarget(const GrRenderTarget* rt,
+                                                                       int width,
+                                                                       int height) {
+    static constexpr int kBits = 8;
+    fStats.incStencilAttachmentCreates();
+    return new GrMockStencilAttachment(this, width, height, kBits, rt->numColorSamples());
+}
diff --git a/src/gpu/mock/GrMockGpu.h b/src/gpu/mock/GrMockGpu.h
index e5d97ce..d54158b 100644
--- a/src/gpu/mock/GrMockGpu.h
+++ b/src/gpu/mock/GrMockGpu.h
@@ -4,55 +4,36 @@
  * Use of this source code is governed by a BSD-style license that can be
  * found in the LICENSE file.
  */
+
 #ifndef GrMockGpu_DEFINED
 #define GrMockGpu_DEFINED
 
-#include "GrCaps.h"
 #include "GrGpu.h"
 #include "GrSemaphore.h"
 #include "GrTexture.h"
 
+class GrMockGpuCommandBuffer;
+struct GrMockOptions;
 class GrPipeline;
 
-class GrMockCaps : public GrCaps {
-public:
-    explicit GrMockCaps(const GrContextOptions& options) : INHERITED(options) {
-        fBufferMapThreshold = SK_MaxS32;
-    }
-    bool isConfigTexturable(GrPixelConfig) const override { return false; }
-    bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const override { return false; }
-    bool canConfigBeImageStorage(GrPixelConfig) const override { return false; }
-    bool initDescForDstCopy(const GrRenderTargetProxy* src, GrSurfaceDesc* desc,
-                            bool* rectsMustMatch, bool* disallowSubrect) const override {
-        return false;
-    }
-
-private:
-    typedef GrCaps INHERITED;
-};
-
 class GrMockGpu : public GrGpu {
 public:
-    static GrGpu* Create(GrBackendContext backendContext, const GrContextOptions& options,
-                         GrContext* context) {
-        SkASSERT((void*)backendContext == nullptr);
-        return new GrMockGpu(context, options);
-    }
+    static GrGpu* Create(GrBackendContext, const GrContextOptions&, GrContext*);
 
     ~GrMockGpu() override {}
 
     bool onGetReadPixelsInfo(GrSurface* srcSurface, int readWidth, int readHeight, size_t rowBytes,
                              GrPixelConfig readConfig, DrawPreference*,
-                             ReadPixelTempDrawInfo*) override { return false; }
+                             ReadPixelTempDrawInfo*) override { return true; }
 
     bool onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height,
                               GrPixelConfig srcConfig, DrawPreference*,
-                              WritePixelTempDrawInfo*) override { return false; }
+                              WritePixelTempDrawInfo*) override { return true; }
 
     bool onCopySurface(GrSurface* dst,
                        GrSurface* src,
                        const SkIRect& srcRect,
-                       const SkIPoint& dstPoint) override { return false; }
+                       const SkIPoint& dstPoint) override { return true; }
 
     void onQueryMultisampleSpecs(GrRenderTarget* rt, const GrStencilSettings&,
                                  int* effectiveSampleCnt, SamplePattern*) override {
@@ -60,9 +41,7 @@
     }
 
     GrGpuCommandBuffer* createCommandBuffer(const GrGpuCommandBuffer::LoadAndStoreInfo&,
-                                            const GrGpuCommandBuffer::LoadAndStoreInfo&) override {
-        return nullptr;
-    }
+                                            const GrGpuCommandBuffer::LoadAndStoreInfo&) override;
 
     GrFence SK_WARN_UNUSED_RESULT insertFence() override { return 0; }
     bool waitFence(GrFence, uint64_t) override { return true; }
@@ -77,19 +56,17 @@
     void waitSemaphore(sk_sp<GrSemaphore> semaphore) override {}
     sk_sp<GrSemaphore> prepareTextureForCrossContextUsage(GrTexture*) override { return nullptr; }
 
+    void submitCommandBuffer(const GrMockGpuCommandBuffer*);
+
 private:
-    GrMockGpu(GrContext* context, const GrContextOptions& options) : INHERITED(context) {
-        fCaps.reset(new GrMockCaps(options));
-    }
+    GrMockGpu(GrContext* context, const GrMockOptions&, const GrContextOptions&);
 
     void onResetContext(uint32_t resetBits) override {}
 
     void xferBarrier(GrRenderTarget*, GrXferBarrierType) override {}
 
-    sk_sp<GrTexture> onCreateTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
-                                     const SkTArray<GrMipLevel>& texels) override {
-        return nullptr;
-    }
+    sk_sp<GrTexture> onCreateTexture(const GrSurfaceDesc&, SkBudgeted,
+                                     const SkTArray<GrMipLevel>&) override;
 
     sk_sp<GrTexture> onWrapBackendTexture(const GrBackendTexture&,
                                           GrSurfaceOrigin,
@@ -110,9 +87,8 @@
         return nullptr;
     }
 
-    GrBuffer* onCreateBuffer(size_t, GrBufferType, GrAccessPattern, const void*) override {
-        return nullptr;
-    }
+    GrBuffer* onCreateBuffer(size_t sizeInBytes, GrBufferType, GrAccessPattern,
+                             const void*) override;
 
     gr_instanced::InstancedRendering* onCreateInstancedRendering() override { return nullptr; }
 
@@ -121,30 +97,27 @@
                       GrPixelConfig,
                       void* buffer,
                       size_t rowBytes) override {
-        return false;
+        return true;
     }
 
     bool onWritePixels(GrSurface* surface,
                        int left, int top, int width, int height,
                        GrPixelConfig config, const SkTArray<GrMipLevel>& texels) override {
-        return false;
+        return true;
     }
 
     bool onTransferPixels(GrTexture* texture,
                           int left, int top, int width, int height,
                           GrPixelConfig config, GrBuffer* transferBuffer,
                           size_t offset, size_t rowBytes) override {
-        return false;
+        return true;
     }
 
     void onResolveRenderTarget(GrRenderTarget* target) override { return; }
 
     GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTarget*,
                                                                 int width,
-                                                                int height) override {
-        return nullptr;
-    }
-
+                                                                int height) override;
     void clearStencil(GrRenderTarget* target) override  {}
 
     GrBackendObject createTestingOnlyBackendTexture(void* pixels, int w, int h,
@@ -156,4 +129,5 @@
 
     typedef GrGpu INHERITED;
 };
-#endif  // GrMockGpu_DEFINED
+
+#endif
diff --git a/src/gpu/mock/GrMockGpuCommandBuffer.h b/src/gpu/mock/GrMockGpuCommandBuffer.h
new file mode 100644
index 0000000..c5719a5
--- /dev/null
+++ b/src/gpu/mock/GrMockGpuCommandBuffer.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 GrMockGpuCommandBuffer_DEFINED
+#define GrMockGpuCommandBuffer_DEFINED
+
+#include "GrGpuCommandBuffer.h"
+#include "GrMockGpu.h"
+
+class GrMockGpuCommandBuffer : public GrGpuCommandBuffer {
+public:
+    GrMockGpuCommandBuffer(GrMockGpu* gpu) : fGpu(gpu) {}
+
+    GrGpu* gpu() override { return fGpu; }
+    void inlineUpload(GrOpFlushState*, GrDrawOp::DeferredUploadFn&, GrRenderTarget*) override {}
+    void discard(GrRenderTarget*) override {}
+    void end() override {}
+
+    int numDraws() const { return fNumDraws; }
+
+private:
+    void onSubmit() override { fGpu->submitCommandBuffer(this); }
+    void onDraw(const GrPipeline&, const GrPrimitiveProcessor&, const GrMesh[],
+                const GrPipeline::DynamicState[], int meshCount, const SkRect& bounds) override {
+        ++fNumDraws;
+    }
+    void onClear(GrRenderTarget*, const GrFixedClip&, GrColor) override {}
+    void onClearStencilClip(GrRenderTarget*, const GrFixedClip&, bool insideStencilMask) override {}
+    GrRenderTarget* renderTarget() override { return nullptr; }
+
+    GrMockGpu* fGpu;
+    int fNumDraws = 0;
+
+    typedef GrGpuCommandBuffer INHERITED;
+};
+
+#endif
diff --git a/src/gpu/mock/GrMockStencilAttachment.h b/src/gpu/mock/GrMockStencilAttachment.h
new file mode 100644
index 0000000..697e444
--- /dev/null
+++ b/src/gpu/mock/GrMockStencilAttachment.h
@@ -0,0 +1,29 @@
+/*
+ * 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 GrMockStencilAttachment_DEFINED
+#define GrMockStencilAttachment_DEFINED
+
+#include "GrMockGpu.h"
+#include "GrStencilAttachment.h"
+
+class GrMockStencilAttachment : public GrStencilAttachment {
+public:
+    GrMockStencilAttachment(GrMockGpu* gpu, int width, int height, int bits, int sampleCnt)
+            : INHERITED(gpu, width, height, bits, sampleCnt) {
+        this->registerWithCache(SkBudgeted::kYes);
+    }
+
+private:
+    size_t onGpuMemorySize() const override {
+        return SkTMax(1, (int)(this->bits() / sizeof(char))) * this->width() * this->height();
+    }
+
+    typedef GrStencilAttachment INHERITED;
+};
+
+#endif
diff --git a/src/gpu/mock/GrMockTexture.h b/src/gpu/mock/GrMockTexture.h
new file mode 100644
index 0000000..41474c2
--- /dev/null
+++ b/src/gpu/mock/GrMockTexture.h
@@ -0,0 +1,90 @@
+/*
+ * 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 GrMockTexture_DEFINED
+#define GrMockTexture_DEFINED
+
+#include "GrMockGpu.h"
+#include "GrTexture.h"
+#include "GrTexturePriv.h"
+
+class GrMockTexture : public GrTexture {
+public:
+    GrMockTexture(GrMockGpu* gpu, SkBudgeted budgeted, const GrSurfaceDesc& desc, bool hasMipLevels)
+            : GrMockTexture(gpu, desc, hasMipLevels) {
+        this->registerWithCache(budgeted);
+    }
+    ~GrMockTexture() override {
+        if (fReleaseProc) {
+            fReleaseProc(fReleaseCtx);
+        }
+    }
+    GrBackendObject getTextureHandle() const override { return 0; }
+    void textureParamsModified() override {}
+    void setRelease(ReleaseProc proc, ReleaseCtx ctx) override {
+        fReleaseProc = proc;
+        fReleaseCtx = ctx;
+    }
+
+protected:
+    // constructor for subclasses
+    GrMockTexture(GrMockGpu* gpu, const GrSurfaceDesc& desc, bool hasMipLevels)
+            : GrSurface(gpu, desc)
+            , INHERITED(gpu, desc, kITexture2DSampler_GrSLType, GrSamplerParams::kMipMap_FilterMode,
+                        hasMipLevels)
+            , fReleaseProc(nullptr)
+            , fReleaseCtx(nullptr) {}
+
+private:
+    ReleaseProc fReleaseProc;
+    ReleaseCtx fReleaseCtx;
+
+    typedef GrTexture INHERITED;
+};
+
+class GrMockTextureRenderTarget : public GrMockTexture, public GrRenderTarget {
+public:
+    GrMockTextureRenderTarget(GrMockGpu* gpu, SkBudgeted budgeted, const GrSurfaceDesc& desc,
+                              bool hasMipLevels)
+            : GrSurface(gpu, desc)
+            , GrMockTexture(gpu, desc, hasMipLevels)
+            , GrRenderTarget(gpu, desc) {
+        this->registerWithCache(budgeted);
+    }
+    ResolveType getResolveType() const override { return kCanResolve_ResolveType; }
+    GrBackendObject getRenderTargetHandle() const override { return 0; }
+    bool canAttemptStencilAttachment() const override { return true; }
+    bool completeStencilAttachment() override { return true; }
+    GrTexture* asTexture() override { return this; }
+    GrRenderTarget* asRenderTarget() override { return this; }
+    const GrTexture* asTexture() const override { return this; }
+    const GrRenderTarget* asRenderTarget() const override { return this; }
+
+private:
+    void onAbandon() override {
+        GrRenderTarget::onAbandon();
+        GrMockTexture::onAbandon();
+    }
+
+    void onRelease() override {
+        GrRenderTarget::onRelease();
+        GrMockTexture::onRelease();
+    }
+
+    size_t onGpuMemorySize() const override {
+        return GrSurface::ComputeSize(this->config(), this->width(), this->height(),
+                                      this->numStencilSamples(),
+                                      this->texturePriv().hasMipMaps());
+    }
+
+    void computeScratchKey(GrScratchKey* key) const override {
+        GrTexturePriv::ComputeScratchKey(this->config(), this->width(), this->height(),
+                                         this->origin(), true, this->numStencilSamples(),
+                                         this->texturePriv().hasMipMaps(), key);
+    }
+};
+
+#endif
diff --git a/tools/gpu/GrContextFactory.cpp b/tools/gpu/GrContextFactory.cpp
index 23ffad1..d614b06 100644
--- a/tools/gpu/GrContextFactory.cpp
+++ b/tools/gpu/GrContextFactory.cpp
@@ -22,6 +22,7 @@
 #endif
 #include "gl/null/NullGLTestContext.h"
 #include "gl/GrGLGpu.h"
+#include "mock/MockTestContext.h"
 #include "GrCaps.h"
 
 #if defined(SK_BUILD_FOR_WIN32) && defined(SK_ENABLE_DISCRETE_GPU)
@@ -220,6 +221,19 @@
             break;
         }
 #endif
+        case kMock_GrBackend: {
+            TestContext* sharedContext = masterContext ? masterContext->fTestContext : nullptr;
+            SkASSERT(kMock_ContextType == type);
+            if (ContextOverrides::kRequireNVPRSupport & overrides) {
+                return ContextInfo();
+            }
+            testCtx.reset(CreateMockTestContext(sharedContext));
+            if (!testCtx) {
+                return ContextInfo();
+            }
+            backendContext = testCtx->backendContext();
+            break;
+        }
         default:
             return ContextInfo();
     }
diff --git a/tools/gpu/GrContextFactory.h b/tools/gpu/GrContextFactory.h
index 508249b..215b922 100644
--- a/tools/gpu/GrContextFactory.h
+++ b/tools/gpu/GrContextFactory.h
@@ -44,7 +44,8 @@
         kNullGL_ContextType,         //! Non-rendering OpenGL mock context.
         kDebugGL_ContextType,        //! Non-rendering, state verifying OpenGL context.
         kVulkan_ContextType,         //! Vulkan
-        kLastContextType = kVulkan_ContextType
+        kMock_ContextType,           //! Mock context that does not draw.
+        kLastContextType = kMock_ContextType
     };
 
     static const int kContextTypeCnt = kLastContextType + 1;
@@ -68,6 +69,7 @@
         switch (type) {
             case kNullGL_ContextType:
             case kDebugGL_ContextType:
+            case kMock_ContextType:
                 return false;
             default:
                 return true;
@@ -78,6 +80,8 @@
         switch (type) {
             case kVulkan_ContextType:
                 return kVulkan_GrBackend;
+            case kMock_ContextType:
+                return kMock_GrBackend;
             default:
                 return kOpenGL_GrBackend;
         }
@@ -109,8 +113,10 @@
                 return "Debug GL";
             case kVulkan_ContextType:
                 return "Vulkan";
+            case kMock_ContextType:
+                return "Mock";
         }
-        SkDEBUGFAIL("Unreachable");
+        SkFAIL("Unreachable");
         return "Unknown";
     }
 
diff --git a/tools/gpu/mock/MockTestContext.cpp b/tools/gpu/mock/MockTestContext.cpp
new file mode 100644
index 0000000..c47fff5
--- /dev/null
+++ b/tools/gpu/mock/MockTestContext.cpp
@@ -0,0 +1,45 @@
+
+/*
+ * 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 GLTestContext_DEFINED
+#define GLTestContext_DEFINED
+
+#include "MockTestContext.h"
+
+namespace {
+
+class MockTestContext : public sk_gpu_test::TestContext {
+public:
+    MockTestContext() {}
+    ~MockTestContext() override {}
+
+    virtual GrBackend backend() override { return kMock_GrBackend; }
+    virtual GrBackendContext backendContext() override {
+        return reinterpret_cast<GrBackendContext>(nullptr);
+    }
+    bool isValid() const override { return true; }
+    void testAbandon() override {}
+    void submit() override {}
+    void finish() override {}
+
+protected:
+    void teardown() override {}
+    void onPlatformMakeCurrent() const override {}
+    void onPlatformSwapBuffers() const override {}
+
+private:
+    typedef sk_gpu_test::TestContext INHERITED;
+};
+
+} // anonymous namespace
+
+namespace sk_gpu_test {
+
+TestContext* CreateMockTestContext(TestContext*) { return new MockTestContext(); }
+
+}  // namespace sk_gpu_test
+#endif
diff --git a/tools/gpu/mock/MockTestContext.h b/tools/gpu/mock/MockTestContext.h
new file mode 100644
index 0000000..4aac248
--- /dev/null
+++ b/tools/gpu/mock/MockTestContext.h
@@ -0,0 +1,22 @@
+
+/*
+ * 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 MockTestContext_DEFINED
+#define MockTestContext_DEFINED
+
+#include "TestContext.h"
+
+namespace sk_gpu_test {
+
+/**
+ * Creates mock context object for use with GrContexts created with kMock_GrBackend. It will
+ * trivially succeed at everything.
+ */
+TestContext* CreateMockTestContext(TestContext* shareContext = nullptr);
+
+}  // namespace sk_gpu_test
+#endif