Move SkGLContext and some GrGLInterface implementations to skgputest module

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1815823002
CQ_EXTRA_TRYBOTS=client.skia.compile:Build-Ubuntu-GCC-x86_64-Release-CMake-Trybot,Build-Mac-Clang-x86_64-Release-CMake-Trybot

Review URL: https://codereview.chromium.org/1815823002
diff --git a/tools/VisualBench/VisualBench.h b/tools/VisualBench/VisualBench.h
index 1920a52..e9fbdfb 100644
--- a/tools/VisualBench/VisualBench.h
+++ b/tools/VisualBench/VisualBench.h
@@ -16,7 +16,7 @@
 #include "SkSurface.h"
 #include "VisualFlags.h"
 #include "VisualModule.h"
-#include "gl/SkGLContext.h"
+#include "gl/GLContext.h"
 
 class GrContext;
 struct GrGLInterface;
diff --git a/tools/flags/SkCommonFlagsConfig.cpp b/tools/flags/SkCommonFlagsConfig.cpp
index 9e0fd60..1ee3130 100644
--- a/tools/flags/SkCommonFlagsConfig.cpp
+++ b/tools/flags/SkCommonFlagsConfig.cpp
@@ -9,6 +9,10 @@
 
 #include <stdlib.h>
 
+#if SK_SUPPORT_GPU
+using sk_gpu_test::GrContextFactory;
+#endif
+
 static const char defaultConfigs[] =
     "565 8888 gpu nonrendering"
 #if SK_ANGLE
diff --git a/tools/flags/SkCommonFlagsConfig.h b/tools/flags/SkCommonFlagsConfig.h
index 39f1f97..abf5946 100644
--- a/tools/flags/SkCommonFlagsConfig.h
+++ b/tools/flags/SkCommonFlagsConfig.h
@@ -50,7 +50,7 @@
 // * backends that represent a shorthand of above (such as "msaa16" representing "gpu(samples=16)")
 class SkCommandLineConfigGpu : public SkCommandLineConfig {
   public:
-    typedef GrContextFactory::GLContextType ContextType;
+    typedef sk_gpu_test::GrContextFactory::GLContextType ContextType;
     SkCommandLineConfigGpu(const SkString& tag, const SkTArray<SkString>& viaParts,
                            ContextType contextType, bool useNVPR, bool useDIText, int samples,
                            SkColorType colorType, SkColorProfileType profileType);
diff --git a/tools/gpu/GrContextFactory.cpp b/tools/gpu/GrContextFactory.cpp
new file mode 100755
index 0000000..0cf0cc7
--- /dev/null
+++ b/tools/gpu/GrContextFactory.cpp
@@ -0,0 +1,157 @@
+
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrContextFactory.h"
+#include "gl/GLContext.h"
+
+#if SK_ANGLE
+    #include "gl/angle/GLContext_angle.h"
+#endif
+#if SK_COMMAND_BUFFER
+    #include "gl/command_buffer/GLContext_command_buffer.h"
+#endif
+#include "gl/debug/DebugGLContext.h"
+#if SK_MESA
+    #include "gl/mesa/GLContext_mesa.h"
+#endif
+#include "gl/null/NullGLContext.h"
+#include "gl/GrGLGpu.h"
+#include "GrCaps.h"
+
+namespace sk_gpu_test {
+GrContextFactory::GrContextFactory() { }
+
+GrContextFactory::GrContextFactory(const GrContextOptions& opts)
+    : fGlobalOptions(opts) {
+}
+
+GrContextFactory::~GrContextFactory() {
+    this->destroyContexts();
+}
+
+void GrContextFactory::destroyContexts() {
+    for (Context& context : fContexts) {
+        if (context.fGLContext) {
+            context.fGLContext->makeCurrent();
+        }
+        if (!context.fGrContext->unique()) {
+            context.fGrContext->abandonContext();
+        }
+        context.fGrContext->unref();
+        delete(context.fGLContext);
+    }
+    fContexts.reset();
+}
+
+void GrContextFactory::abandonContexts() {
+    for (Context& context : fContexts) {
+        if (context.fGLContext) {
+            context.fGLContext->makeCurrent();
+            context.fGLContext->testAbandon();
+            delete(context.fGLContext);
+            context.fGLContext = nullptr;
+        }
+        context.fGrContext->abandonContext();
+    }
+}
+
+GrContextFactory::ContextInfo GrContextFactory::getContextInfo(GLContextType type,
+                                                               GLContextOptions options) {
+    for (int i = 0; i < fContexts.count(); ++i) {
+        Context& context = fContexts[i];
+        if (!context.fGLContext) {
+            continue;
+        }
+        if (context.fType == type &&
+            context.fOptions == options) {
+            context.fGLContext->makeCurrent();
+            return ContextInfo(context.fGrContext, context.fGLContext);
+        }
+    }
+    SkAutoTDelete<GLContext> glCtx;
+    SkAutoTUnref<GrContext> grCtx;
+    switch (type) {
+        case kNative_GLContextType:
+            glCtx.reset(CreatePlatformGLContext(kNone_GrGLStandard));
+            break;
+        case kGL_GLContextType:
+            glCtx.reset(CreatePlatformGLContext(kGL_GrGLStandard));
+            break;
+        case kGLES_GLContextType:
+            glCtx.reset(CreatePlatformGLContext(kGLES_GrGLStandard));
+            break;
+#if SK_ANGLE
+#ifdef SK_BUILD_FOR_WIN
+        case kANGLE_GLContextType:
+            glCtx.reset(CreateANGLEDirect3DGLContext());
+            break;
+#endif
+        case kANGLE_GL_GLContextType:
+            glCtx.reset(CreateANGLEOpenGLGLContext());
+            break;
+#endif
+#if SK_COMMAND_BUFFER
+        case kCommandBuffer_GLContextType:
+            glCtx.reset(CommandBufferGLContext::Create());
+            break;
+#endif
+#if SK_MESA
+        case kMESA_GLContextType:
+            glCtx.reset(CreateMesaGLContext());
+            break;
+#endif
+        case kNull_GLContextType:
+            glCtx.reset(CreateNullGLContext());
+            break;
+        case kDebug_GLContextType:
+            glCtx.reset(CreateDebugGLContext());
+            break;
+    }
+    if (nullptr == glCtx.get()) {
+        return ContextInfo();
+    }
+
+    SkASSERT(glCtx->isValid());
+
+    // Block NVPR from non-NVPR types.
+    SkAutoTUnref<const GrGLInterface> glInterface(SkRef(glCtx->gl()));
+    if (!(kEnableNVPR_GLContextOptions & options)) {
+        glInterface.reset(GrGLInterfaceRemoveNVPR(glInterface));
+        if (!glInterface) {
+            return ContextInfo();
+        }
+    }
+
+    glCtx->makeCurrent();
+    GrBackendContext p3dctx = reinterpret_cast<GrBackendContext>(glInterface.get());
+#ifdef SK_VULKAN
+    if (kEnableNVPR_GLContextOptions & options) {
+        return ContextInfo();
+    } else {
+        grCtx.reset(GrContext::Create(kVulkan_GrBackend, p3dctx, fGlobalOptions));
+    }
+#else
+    grCtx.reset(GrContext::Create(kOpenGL_GrBackend, p3dctx, fGlobalOptions));
+#endif
+    if (!grCtx.get()) {
+        return ContextInfo();
+    }
+    if (kEnableNVPR_GLContextOptions & options) {
+        if (!grCtx->caps()->shaderCaps()->pathRenderingSupport()) {
+            return ContextInfo();
+        }
+    }
+
+    Context& context = fContexts.push_back();
+    context.fGLContext = glCtx.release();
+    context.fGrContext = SkRef(grCtx.get());
+    context.fType = type;
+    context.fOptions = options;
+    return ContextInfo(context.fGrContext, context.fGLContext);
+}
+}  // namespace sk_gpu_test
diff --git a/tools/gpu/GrContextFactory.h b/tools/gpu/GrContextFactory.h
new file mode 100644
index 0000000..7e5c10e
--- /dev/null
+++ b/tools/gpu/GrContextFactory.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrContextFactory_DEFINED
+#define GrContextFactory_DEFINED
+
+#include "GrContext.h"
+#include "GrContextOptions.h"
+
+#include "gl/GLContext.h"
+#include "SkTArray.h"
+
+namespace sk_gpu_test {
+/**
+ * This is a simple class that is useful in test apps that use different
+ * GrContexts backed by different types of GL contexts. It manages creating the
+ * GL context and a GrContext that uses it. The GL/Gr contexts persist until the
+ * factory is destroyed (though the caller can always grab a ref on the returned
+ * Gr and GL contexts to make them outlive the factory).
+ */
+class GrContextFactory : SkNoncopyable {
+public:
+    enum GLContextType {
+        kNative_GLContextType,  //! OpenGL or OpenGL ES context.
+        kGL_GLContextType,      //! OpenGL context.
+        kGLES_GLContextType,    //! OpenGL ES context.
+#if SK_ANGLE
+#ifdef SK_BUILD_FOR_WIN
+        kANGLE_GLContextType,    //! ANGLE on DirectX OpenGL ES context.
+#endif
+        kANGLE_GL_GLContextType, //! ANGLE on OpenGL OpenGL ES context.
+#endif
+#if SK_COMMAND_BUFFER
+        kCommandBuffer_GLContextType, //! Chromium command buffer OpenGL ES context.
+#endif
+#if SK_MESA
+        kMESA_GLContextType,  //! MESA OpenGL context
+#endif
+        kNull_GLContextType,  //! Non-rendering OpenGL mock context.
+        kDebug_GLContextType, //! Non-rendering, state verifying OpenGL context.
+        kLastGLContextType = kDebug_GLContextType
+    };
+
+    static const int kGLContextTypeCnt = kLastGLContextType + 1;
+
+    /**
+     * Options for GL context creation. For historical and testing reasons the options will default
+     * to not using GL_NV_path_rendering extension  even when the driver supports it.
+     */
+    enum GLContextOptions {
+        kNone_GLContextOptions = 0,
+        kEnableNVPR_GLContextOptions = 0x1,
+    };
+
+    static bool IsRenderingGLContext(GLContextType type) {
+        switch (type) {
+            case kNull_GLContextType:
+            case kDebug_GLContextType:
+                return false;
+            default:
+                return true;
+        }
+    }
+
+    static const char* GLContextTypeName(GLContextType type) {
+        switch (type) {
+            case kNative_GLContextType:
+                return "native";
+            case kGL_GLContextType:
+                return "gl";
+            case kGLES_GLContextType:
+                return "gles";
+#if SK_ANGLE
+#ifdef SK_BUILD_FOR_WIN
+            case kANGLE_GLContextType:
+                return "angle";
+#endif
+            case kANGLE_GL_GLContextType:
+                return "angle-gl";
+#endif
+#if SK_COMMAND_BUFFER
+            case kCommandBuffer_GLContextType:
+                return "commandbuffer";
+#endif
+#if SK_MESA
+            case kMESA_GLContextType:
+                return "mesa";
+#endif
+            case kNull_GLContextType:
+                return "null";
+            case kDebug_GLContextType:
+                return "debug";
+            default:
+                SkFAIL("Unknown GL Context type.");
+        }
+    }
+
+    explicit GrContextFactory(const GrContextOptions& opts);
+    GrContextFactory();
+
+    ~GrContextFactory();
+
+    void destroyContexts();
+    void abandonContexts();
+
+    struct ContextInfo {
+        ContextInfo()
+            : fGrContext(nullptr), fGLContext(nullptr) { }
+        ContextInfo(GrContext* grContext, GLContext* glContext)
+            : fGrContext(grContext), fGLContext(glContext) { }
+        GrContext* fGrContext;
+        GLContext* fGLContext; //! Valid until the factory destroys it via abandonContexts() or
+                               //! destroyContexts().
+    };
+
+    /**
+     * Get a context initialized with a type of GL context. It also makes the GL context current.
+     */
+    ContextInfo getContextInfo(GLContextType type,
+                               GLContextOptions options = kNone_GLContextOptions);
+    /**
+     * Get a GrContext initialized with a type of GL context. It also makes the GL context current.
+     */
+    GrContext* get(GLContextType type,
+                   GLContextOptions options = kNone_GLContextOptions) {
+        return this->getContextInfo(type, options).fGrContext;
+    }
+    const GrContextOptions& getGlobalOptions() const { return fGlobalOptions; }
+
+private:
+    struct Context {
+        GLContextType       fType;
+        GLContextOptions    fOptions;
+        GLContext*          fGLContext;
+        GrContext*          fGrContext;
+    };
+    SkTArray<Context, true> fContexts;
+    const GrContextOptions  fGlobalOptions;
+};
+}  // namespace sk_gpu_test
+#endif
diff --git a/tools/gpu/GrTest.cpp b/tools/gpu/GrTest.cpp
new file mode 100644
index 0000000..2b6463d
--- /dev/null
+++ b/tools/gpu/GrTest.cpp
@@ -0,0 +1,419 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrTest.h"
+
+#include "GrBatchAtlas.h"
+#include "GrContextOptions.h"
+#include "GrDrawContextPriv.h"
+#include "GrDrawingManager.h"
+#include "GrGpuResourceCacheAccess.h"
+#include "GrResourceCache.h"
+
+#include "SkGpuDevice.h"
+#include "SkGrPriv.h"
+#include "SkString.h"
+
+#include "text/GrBatchFontCache.h"
+#include "text/GrTextBlobCache.h"
+
+namespace GrTest {
+void SetupAlwaysEvictAtlas(GrContext* context) {
+    // These sizes were selected because they allow each atlas to hold a single plot and will thus
+    // stress the atlas
+    int dim = GrBatchAtlas::kGlyphMaxDim;
+    GrBatchAtlasConfig configs[3];
+    configs[kA8_GrMaskFormat].fWidth = dim;
+    configs[kA8_GrMaskFormat].fHeight = dim;
+    configs[kA8_GrMaskFormat].fLog2Width = SkNextLog2(dim);
+    configs[kA8_GrMaskFormat].fLog2Height = SkNextLog2(dim);
+    configs[kA8_GrMaskFormat].fPlotWidth = dim;
+    configs[kA8_GrMaskFormat].fPlotHeight = dim;
+
+    configs[kA565_GrMaskFormat].fWidth = dim;
+    configs[kA565_GrMaskFormat].fHeight = dim;
+    configs[kA565_GrMaskFormat].fLog2Width = SkNextLog2(dim);
+    configs[kA565_GrMaskFormat].fLog2Height = SkNextLog2(dim);
+    configs[kA565_GrMaskFormat].fPlotWidth = dim;
+    configs[kA565_GrMaskFormat].fPlotHeight = dim;
+
+    configs[kARGB_GrMaskFormat].fWidth = dim;
+    configs[kARGB_GrMaskFormat].fHeight = dim;
+    configs[kARGB_GrMaskFormat].fLog2Width = SkNextLog2(dim);
+    configs[kARGB_GrMaskFormat].fLog2Height = SkNextLog2(dim);
+    configs[kARGB_GrMaskFormat].fPlotWidth = dim;
+    configs[kARGB_GrMaskFormat].fPlotHeight = dim;
+
+    context->setTextContextAtlasSizes_ForTesting(configs);
+}
+};
+
+void GrTestTarget::init(GrContext* ctx, GrDrawTarget* target, GrRenderTarget* rt) {
+    SkASSERT(!fContext);
+
+    fContext.reset(SkRef(ctx));
+    fDrawTarget.reset(SkRef(target));
+    fRenderTarget.reset(SkRef(rt));
+}
+
+void GrContext::getTestTarget(GrTestTarget* tar, GrRenderTarget* rt) {
+    this->flush();
+    // We could create a proxy GrDrawTarget that passes through to fGpu until ~GrTextTarget() and
+    // then disconnects. This would help prevent test writers from mixing using the returned
+    // GrDrawTarget and regular drawing. We could also assert or fail in GrContext drawing methods
+    // until ~GrTestTarget().
+    if (!rt) {
+        GrSurfaceDesc desc;
+        desc.fFlags = kRenderTarget_GrSurfaceFlag;
+        desc.fWidth = 32;
+        desc.fHeight = 32;
+        desc.fConfig = kRGBA_8888_GrPixelConfig;
+        desc.fSampleCnt = 0;
+
+        SkAutoTUnref<GrTexture> texture(this->textureProvider()->createTexture(
+            desc, SkBudgeted::kNo, nullptr, 0));
+        if (nullptr == texture) {
+            return;
+        }
+        SkASSERT(nullptr != texture->asRenderTarget());
+        rt = texture->asRenderTarget();
+    }
+
+    SkAutoTUnref<GrDrawTarget> dt(fDrawingManager->newDrawTarget(rt));
+    tar->init(this, dt, rt);
+}
+
+void GrContext::setTextBlobCacheLimit_ForTesting(size_t bytes) {
+    fTextBlobCache->setBudget(bytes);
+}
+
+void GrContext::setTextContextAtlasSizes_ForTesting(const GrBatchAtlasConfig* configs) {
+    fBatchFontCache->setAtlasSizes_ForTesting(configs);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GrContext::purgeAllUnlockedResources() {
+    fResourceCache->purgeAllUnlocked();
+}
+
+void GrContext::resetGpuStats() const {
+#if GR_GPU_STATS
+    fGpu->stats()->reset();
+#endif
+}
+
+void GrContext::dumpCacheStats(SkString* out) const {
+#if GR_CACHE_STATS
+    fResourceCache->dumpStats(out);
+#endif
+}
+
+void GrContext::dumpCacheStatsKeyValuePairs(SkTArray<SkString>* keys,
+                                            SkTArray<double>* values) const {
+#if GR_CACHE_STATS
+    fResourceCache->dumpStatsKeyValuePairs(keys, values);
+#endif
+}
+
+void GrContext::printCacheStats() const {
+    SkString out;
+    this->dumpCacheStats(&out);
+    SkDebugf("%s", out.c_str());
+}
+
+void GrContext::dumpGpuStats(SkString* out) const {
+#if GR_GPU_STATS
+    return fGpu->stats()->dump(out);
+#endif
+}
+
+void GrContext::dumpGpuStatsKeyValuePairs(SkTArray<SkString>* keys,
+                                          SkTArray<double>* values) const {
+#if GR_GPU_STATS
+    return fGpu->stats()->dumpKeyValuePairs(keys, values);
+#endif
+}
+
+void GrContext::printGpuStats() const {
+    SkString out;
+    this->dumpGpuStats(&out);
+    SkDebugf("%s", out.c_str());
+}
+
+GrTexture* GrContext::getFontAtlasTexture(GrMaskFormat format) {
+    GrBatchFontCache* cache = this->getBatchFontCache();
+
+    return cache->getTexture(format);
+}
+
+void SkGpuDevice::drawTexture(GrTexture* tex, const SkRect& dst, const SkPaint& paint) {
+    GrPaint grPaint;
+    SkMatrix mat;
+    mat.reset();
+    if (!SkPaintToGrPaint(this->context(), paint, mat, &grPaint)) {
+        return;
+    }
+    SkMatrix textureMat;
+    textureMat.reset();
+    textureMat[SkMatrix::kMScaleX] = 1.0f/dst.width();
+    textureMat[SkMatrix::kMScaleY] = 1.0f/dst.height();
+    textureMat[SkMatrix::kMTransX] = -dst.fLeft/dst.width();
+    textureMat[SkMatrix::kMTransY] = -dst.fTop/dst.height();
+
+    grPaint.addColorTextureProcessor(tex, textureMat);
+
+    GrClip clip;
+    fDrawContext->drawRect(clip, grPaint, mat, dst);
+}
+
+
+#if GR_GPU_STATS
+void GrGpu::Stats::dump(SkString* out) {
+    out->appendf("Render Target Binds: %d\n", fRenderTargetBinds);
+    out->appendf("Shader Compilations: %d\n", fShaderCompilations);
+    out->appendf("Textures Created: %d\n", fTextureCreates);
+    out->appendf("Texture Uploads: %d\n", fTextureUploads);
+    out->appendf("Transfers to Texture: %d\n", fTransfersToTexture);
+    out->appendf("Stencil Buffer Creates: %d\n", fStencilAttachmentCreates);
+    out->appendf("Number of draws: %d\n", fNumDraws);
+}
+
+void GrGpu::Stats::dumpKeyValuePairs(SkTArray<SkString>* keys, SkTArray<double>* values) {
+    keys->push_back(SkString("render_target_binds")); values->push_back(fRenderTargetBinds);
+    keys->push_back(SkString("shader_compilations")); values->push_back(fShaderCompilations);
+    keys->push_back(SkString("texture_uploads")); values->push_back(fTextureUploads);
+    keys->push_back(SkString("number_of_draws")); values->push_back(fNumDraws);
+    keys->push_back(SkString("number_of_failed_draws")); values->push_back(fNumFailedDraws);
+}
+
+#endif
+
+#if GR_CACHE_STATS
+void GrResourceCache::getStats(Stats* stats) const {
+    stats->reset();
+
+    stats->fTotal = this->getResourceCount();
+    stats->fNumNonPurgeable = fNonpurgeableResources.count();
+    stats->fNumPurgeable = fPurgeableQueue.count();
+
+    for (int i = 0; i < fNonpurgeableResources.count(); ++i) {
+        stats->update(fNonpurgeableResources[i]);
+    }
+    for (int i = 0; i < fPurgeableQueue.count(); ++i) {
+        stats->update(fPurgeableQueue.at(i));
+    }
+}
+
+void GrResourceCache::dumpStats(SkString* out) const {
+    this->validate();
+
+    Stats stats;
+
+    this->getStats(&stats);
+
+    float countUtilization = (100.f * fBudgetedCount) / fMaxCount;
+    float byteUtilization = (100.f * fBudgetedBytes) / fMaxBytes;
+
+    out->appendf("Budget: %d items %d bytes\n", fMaxCount, (int)fMaxBytes);
+    out->appendf("\t\tEntry Count: current %d"
+                 " (%d budgeted, %d external(%d borrowed, %d adopted), %d locked, %d scratch %.2g%% full), high %d\n",
+                 stats.fTotal, fBudgetedCount, stats.fExternal, stats.fBorrowed,
+                 stats.fAdopted, stats.fNumNonPurgeable, stats.fScratch, countUtilization,
+                 fHighWaterCount);
+    out->appendf("\t\tEntry Bytes: current %d (budgeted %d, %.2g%% full, %d unbudgeted) high %d\n",
+                 SkToInt(fBytes), SkToInt(fBudgetedBytes), byteUtilization,
+                 SkToInt(stats.fUnbudgetedSize), SkToInt(fHighWaterBytes));
+}
+
+void GrResourceCache::dumpStatsKeyValuePairs(SkTArray<SkString>* keys,
+                                             SkTArray<double>* values) const {
+    this->validate();
+
+    Stats stats;
+    this->getStats(&stats);
+
+    keys->push_back(SkString("gpu_cache_purgable_entries")); values->push_back(stats.fNumPurgeable);
+}
+
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
+void GrResourceCache::changeTimestamp(uint32_t newTimestamp) { fTimestamp = newTimestamp; }
+
+///////////////////////////////////////////////////////////////////////////////
+
+#define ASSERT_SINGLE_OWNER \
+    SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fDrawContext->fSingleOwner);)
+#define RETURN_IF_ABANDONED        if (fDrawContext->fDrawingManager->abandoned()) { return; }
+
+void GrDrawContextPriv::testingOnly_drawBatch(const GrPipelineBuilder& pipelineBuilder,
+                                              GrDrawBatch* batch) {
+    ASSERT_SINGLE_OWNER
+    RETURN_IF_ABANDONED
+    SkDEBUGCODE(fDrawContext->validate();)
+    GR_AUDIT_TRAIL_AUTO_FRAME(fDrawContext->fAuditTrail, "GrDrawContext::testingOnly_drawBatch");
+
+    fDrawContext->getDrawTarget()->drawBatch(pipelineBuilder, batch);
+}
+
+#undef ASSERT_SINGLE_OWNER
+#undef RETURN_IF_ABANDONED
+
+///////////////////////////////////////////////////////////////////////////////
+// Code for the mock context. It's built on a mock GrGpu class that does nothing.
+////
+
+#include "GrGpu.h"
+
+class GrPipeline;
+
+class MockCaps : public GrCaps {
+public:
+    explicit MockCaps(const GrContextOptions& options) : INHERITED(options) {}
+    bool isConfigTexturable(GrPixelConfig config) const override { return false; }
+    bool isConfigRenderable(GrPixelConfig config, bool withMSAA) const override { return false; }
+private:
+    typedef GrCaps INHERITED;
+};
+
+class MockGpu : public GrGpu {
+public:
+    MockGpu(GrContext* context, const GrContextOptions& options) : INHERITED(context) {
+        fCaps.reset(new MockCaps(options));
+    }
+    ~MockGpu() override {}
+
+    bool onGetReadPixelsInfo(GrSurface* srcSurface, int readWidth, int readHeight, size_t rowBytes,
+                             GrPixelConfig readConfig, DrawPreference*,
+                             ReadPixelTempDrawInfo*) override { return false; }
+
+    bool onGetWritePixelsInfo(GrSurface* dstSurface, int width, int height,
+                              GrPixelConfig srcConfig, DrawPreference*,
+                              WritePixelTempDrawInfo*) override { return false; }
+
+    void discard(GrRenderTarget*) override {}
+
+    bool onCopySurface(GrSurface* dst,
+                       GrSurface* src,
+                       const SkIRect& srcRect,
+                       const SkIPoint& dstPoint) override { return false; };
+
+    void onGetMultisampleSpecs(GrRenderTarget* rt,
+                               const GrStencilSettings&,
+                               int* effectiveSampleCnt,
+                               SkAutoTDeleteArray<SkPoint>*) override {
+        *effectiveSampleCnt = rt->desc().fSampleCnt;
+    }
+
+    bool initCopySurfaceDstDesc(const GrSurface* src, GrSurfaceDesc* desc) const override {
+        return false;
+    }
+
+    void drawDebugWireRect(GrRenderTarget*, const SkIRect&, GrColor) override {};
+
+private:
+    void onResetContext(uint32_t resetBits) override {}
+
+    void xferBarrier(GrRenderTarget*, GrXferBarrierType) override {}
+
+    GrTexture* onCreateTexture(const GrSurfaceDesc& desc, GrGpuResource::LifeCycle lifeCycle,
+                               const SkTArray<GrMipLevel>& texels) override {
+        return nullptr;
+    }
+
+    GrTexture* onCreateCompressedTexture(const GrSurfaceDesc& desc, GrGpuResource::LifeCycle,
+                                         const SkTArray<GrMipLevel>& texels) override {
+        return nullptr;
+    }
+
+    GrTexture* onWrapBackendTexture(const GrBackendTextureDesc&,
+                                    GrWrapOwnership) override { return nullptr; }
+
+    GrRenderTarget* onWrapBackendRenderTarget(const GrBackendRenderTargetDesc&,
+                                              GrWrapOwnership) override {
+        return nullptr;
+    }
+
+    GrRenderTarget* onWrapBackendTextureAsRenderTarget(const GrBackendTextureDesc&,
+                                                       GrWrapOwnership) override {
+        return nullptr;
+    }
+
+    GrBuffer* onCreateBuffer(GrBufferType, size_t, GrAccessPattern) override { return nullptr; }
+
+    void onClear(GrRenderTarget*, const SkIRect& rect, GrColor color) override {}
+
+    void onClearStencilClip(GrRenderTarget*, const SkIRect& rect, bool insideClip) override {}
+
+    void onDraw(const GrPipeline&,
+                const GrPrimitiveProcessor&,
+                const GrMesh*,
+                int meshCount) override {}
+
+    bool onReadPixels(GrSurface* surface,
+                      int left, int top, int width, int height,
+                      GrPixelConfig,
+                      void* buffer,
+                      size_t rowBytes) override {
+        return false;
+    }
+
+    bool onWritePixels(GrSurface* surface,
+                       int left, int top, int width, int height,
+                       GrPixelConfig config, const SkTArray<GrMipLevel>& texels) override {
+        return false;
+    }
+
+    bool onTransferPixels(GrSurface* surface,
+                          int left, int top, int width, int height,
+                          GrPixelConfig config, GrBuffer* transferBuffer,
+                          size_t offset, size_t rowBytes) override {
+        return false;
+    }
+
+    void onResolveRenderTarget(GrRenderTarget* target) override { return; }
+
+    GrStencilAttachment* createStencilAttachmentForRenderTarget(const GrRenderTarget*,
+                                                                int width,
+                                                                int height) override {
+        return nullptr;
+    }
+
+    void clearStencil(GrRenderTarget* target) override  {}
+
+    GrBackendObject createTestingOnlyBackendTexture(void* pixels, int w, int h,
+                                                    GrPixelConfig config) override {
+        return 0;
+    }
+    bool isTestingOnlyBackendTexture(GrBackendObject ) const override { return false; }
+    void deleteTestingOnlyBackendTexture(GrBackendObject, bool abandonTexture) override {}
+
+    typedef GrGpu INHERITED;
+};
+
+GrContext* GrContext::CreateMockContext() {
+    GrContext* context = new GrContext;
+
+    context->initMockContext();
+    return context;
+}
+
+void GrContext::initMockContext() {
+    GrContextOptions options;
+    options.fBufferMapThreshold = 0;
+    SkASSERT(nullptr == fGpu);
+    fGpu = new MockGpu(this, options);
+    SkASSERT(fGpu);
+    this->initCommon(options);
+
+    // We delete these because we want to test the cache starting with zero resources. Also, none of
+    // these objects are required for any of tests that use this context. TODO: make stop allocating
+    // resources in the buffer pools.
+    fDrawingManager->abandon();
+}
diff --git a/tools/gpu/GrTest.h b/tools/gpu/GrTest.h
new file mode 100644
index 0000000..53aaac3
--- /dev/null
+++ b/tools/gpu/GrTest.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrTest_DEFINED
+#define GrTest_DEFINED
+
+#include "GrContext.h"
+#include "GrDrawTarget.h"
+#include "gl/GrGLContext.h"
+
+namespace GrTest {
+    /**
+     * Forces the GrContext to use a small atlas which only has room for one plot and will thus
+     * constantly be evicting entries
+     */
+    void SetupAlwaysEvictAtlas(GrContext*);
+};
+
+/** TODO Please do not use this if you can avoid it.  We are in the process of deleting it.
+    Allows a test to temporarily draw to a GrDrawTarget owned by a GrContext. Tests that use this
+    should be careful not to mix using the GrDrawTarget directly and drawing via SkCanvas or
+    GrContext. In the future this object may provide some guards to prevent this. */
+class GrTestTarget {
+public:
+    GrTestTarget() {};
+
+    void init(GrContext*, GrDrawTarget*, GrRenderTarget*);
+
+    GrDrawTarget* target() { return fDrawTarget.get(); }
+    GrResourceProvider* resourceProvider() { return fContext->resourceProvider(); }
+
+private:
+    SkAutoTUnref<GrContext>                 fContext;
+    SkAutoTUnref<GrDrawTarget>              fDrawTarget;
+    SkAutoTUnref<GrRenderTarget>            fRenderTarget;
+};
+
+#endif
diff --git a/tools/gpu/gl/GLContext.cpp b/tools/gpu/gl/GLContext.cpp
new file mode 100644
index 0000000..ac0e310
--- /dev/null
+++ b/tools/gpu/gl/GLContext.cpp
@@ -0,0 +1,188 @@
+
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "GLContext.h"
+#include "gl/GrGLUtil.h"
+#include "SkGpuFenceSync.h"
+
+namespace sk_gpu_test {
+class GLContext::GLFenceSync : public SkGpuFenceSync {
+public:
+    static GLFenceSync* CreateIfSupported(const GLContext*);
+
+    SkPlatformGpuFence SK_WARN_UNUSED_RESULT insertFence() const override;
+    bool waitFence(SkPlatformGpuFence fence, bool flush) const override;
+    void deleteFence(SkPlatformGpuFence fence) const override;
+
+private:
+    GLFenceSync() {}
+
+    static const GrGLenum GL_SYNC_GPU_COMMANDS_COMPLETE  = 0x9117;
+    static const GrGLenum GL_WAIT_FAILED                 = 0x911d;
+    static const GrGLbitfield GL_SYNC_FLUSH_COMMANDS_BIT = 0x00000001;
+
+    typedef struct __GLsync *GLsync;
+
+    typedef GLsync (GR_GL_FUNCTION_TYPE* GLFenceSyncProc) (GrGLenum, GrGLbitfield);
+    typedef GrGLenum (GR_GL_FUNCTION_TYPE* GLClientWaitSyncProc) (GLsync, GrGLbitfield, GrGLuint64);
+    typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GLDeleteSyncProc) (GLsync);
+
+    GLFenceSyncProc        fGLFenceSync;
+    GLClientWaitSyncProc   fGLClientWaitSync;
+    GLDeleteSyncProc       fGLDeleteSync;
+
+    typedef SkGpuFenceSync INHERITED;
+};
+
+GLContext::GLContext()
+    : fCurrentFenceIdx(0) {
+    memset(fFrameFences, 0, sizeof(fFrameFences));
+}
+
+GLContext::~GLContext() {
+    // Subclass should call teardown.
+#ifdef SK_DEBUG
+    for (size_t i = 0; i < SK_ARRAY_COUNT(fFrameFences); i++) {
+        SkASSERT(0 == fFrameFences[i]);
+    }
+#endif
+    SkASSERT(nullptr == fGL.get());
+    SkASSERT(nullptr == fFenceSync.get());
+}
+
+void GLContext::init(const GrGLInterface* gl, SkGpuFenceSync* fenceSync) {
+    SkASSERT(!fGL.get());
+    fGL.reset(gl);
+    fFenceSync.reset(fenceSync ? fenceSync : GLFenceSync::CreateIfSupported(this));
+}
+
+void GLContext::teardown() {
+    if (fFenceSync) {
+        for (size_t i = 0; i < SK_ARRAY_COUNT(fFrameFences); i++) {
+            if (fFrameFences[i]) {
+                fFenceSync->deleteFence(fFrameFences[i]);
+                fFrameFences[i] = 0;
+            }
+        }
+        fFenceSync.reset(nullptr);
+    }
+
+    fGL.reset(nullptr);
+}
+
+void GLContext::makeCurrent() const {
+    this->onPlatformMakeCurrent();
+}
+
+void GLContext::swapBuffers() {
+    this->onPlatformSwapBuffers();
+}
+
+void GLContext::waitOnSyncOrSwap() {
+    if (!fFenceSync) {
+        // Fallback on the platform SwapBuffers method for synchronization. This may have no effect.
+        this->swapBuffers();
+        return;
+    }
+
+    if (fFrameFences[fCurrentFenceIdx]) {
+        if (!fFenceSync->waitFence(fFrameFences[fCurrentFenceIdx], true)) {
+            SkDebugf("WARNING: Wait failed for fence sync. Timings might not be accurate.\n");
+        }
+        fFenceSync->deleteFence(fFrameFences[fCurrentFenceIdx]);
+    }
+
+    fFrameFences[fCurrentFenceIdx] = fFenceSync->insertFence();
+    fCurrentFenceIdx = (fCurrentFenceIdx + 1) % SK_ARRAY_COUNT(fFrameFences);
+}
+
+void GLContext::testAbandon() {
+    if (fGL) {
+        fGL->abandon();
+    }
+    if (fFenceSync) {
+        memset(fFrameFences, 0, sizeof(fFrameFences));
+    }
+}
+
+GLContext::GLFenceSync* GLContext::GLFenceSync::CreateIfSupported(const GLContext* ctx) {
+    SkAutoTDelete<GLFenceSync> ret(new GLFenceSync);
+
+    if (kGL_GrGLStandard == ctx->gl()->fStandard) {
+        const GrGLubyte* versionStr;
+        GR_GL_CALL_RET(ctx->gl(), versionStr, GetString(GR_GL_VERSION));
+        GrGLVersion version = GrGLGetVersionFromString(reinterpret_cast<const char*>(versionStr));
+        if (version < GR_GL_VER(3,2) && !ctx->gl()->hasExtension("GL_ARB_sync")) {
+            return nullptr;
+        }
+        ret->fGLFenceSync = reinterpret_cast<GLFenceSyncProc>(
+            ctx->onPlatformGetProcAddress("glFenceSync"));
+        ret->fGLClientWaitSync = reinterpret_cast<GLClientWaitSyncProc>(
+            ctx->onPlatformGetProcAddress("glClientWaitSync"));
+        ret->fGLDeleteSync = reinterpret_cast<GLDeleteSyncProc>(
+            ctx->onPlatformGetProcAddress("glDeleteSync"));
+    } else {
+        if (!ctx->gl()->hasExtension("GL_APPLE_sync")) {
+            return nullptr;
+        }
+        ret->fGLFenceSync = reinterpret_cast<GLFenceSyncProc>(
+            ctx->onPlatformGetProcAddress("glFenceSyncAPPLE"));
+        ret->fGLClientWaitSync = reinterpret_cast<GLClientWaitSyncProc>(
+            ctx->onPlatformGetProcAddress("glClientWaitSyncAPPLE"));
+        ret->fGLDeleteSync = reinterpret_cast<GLDeleteSyncProc>(
+            ctx->onPlatformGetProcAddress("glDeleteSyncAPPLE"));
+    }
+
+    if (!ret->fGLFenceSync || !ret->fGLClientWaitSync || !ret->fGLDeleteSync) {
+        return nullptr;
+    }
+
+    return ret.release();
+}
+
+SkPlatformGpuFence GLContext::GLFenceSync::insertFence() const {
+    return fGLFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+}
+
+bool GLContext::GLFenceSync::waitFence(SkPlatformGpuFence fence, bool flush) const {
+    GLsync glsync = static_cast<GLsync>(fence);
+    return GL_WAIT_FAILED != fGLClientWaitSync(glsync, flush ? GL_SYNC_FLUSH_COMMANDS_BIT : 0, -1);
+}
+
+void GLContext::GLFenceSync::deleteFence(SkPlatformGpuFence fence) const {
+    GLsync glsync = static_cast<GLsync>(fence);
+    fGLDeleteSync(glsync);
+}
+
+GrGLint GLContext::createTextureRectangle(int width, int height, GrGLenum internalFormat,
+                                          GrGLenum externalFormat, GrGLenum externalType,
+                                          GrGLvoid* data) {
+    if (!(kGL_GrGLStandard == fGL->fStandard && GrGLGetVersion(fGL) >= GR_GL_VER(3, 1)) &&
+        !fGL->fExtensions.has("GL_ARB_texture_rectangle")) {
+        return 0;
+    }
+
+    if  (GrGLGetGLSLVersion(fGL) < GR_GLSL_VER(1, 40)) {
+        return 0;
+    }
+
+    GrGLuint id;
+    GR_GL_CALL(fGL, GenTextures(1, &id));
+    GR_GL_CALL(fGL, BindTexture(GR_GL_TEXTURE_RECTANGLE, id));
+    GR_GL_CALL(fGL, TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_MAG_FILTER,
+                                  GR_GL_NEAREST));
+    GR_GL_CALL(fGL, TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_MIN_FILTER,
+                                  GR_GL_NEAREST));
+    GR_GL_CALL(fGL, TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_WRAP_S,
+                                  GR_GL_CLAMP_TO_EDGE));    
+    GR_GL_CALL(fGL, TexParameteri(GR_GL_TEXTURE_RECTANGLE, GR_GL_TEXTURE_WRAP_T,
+                                  GR_GL_CLAMP_TO_EDGE));
+    GR_GL_CALL(fGL, TexImage2D(GR_GL_TEXTURE_RECTANGLE, 0, internalFormat, width, height, 0,
+                               externalFormat, externalType, data));
+    return id;
+}
+}  // namespace sk_gpu_test
diff --git a/tools/gpu/gl/GLContext.h b/tools/gpu/gl/GLContext.h
new file mode 100644
index 0000000..3f47613
--- /dev/null
+++ b/tools/gpu/gl/GLContext.h
@@ -0,0 +1,141 @@
+
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef GLContext_DEFINED
+#define GLContext_DEFINED
+
+#include "gl/GrGLInterface.h"
+#include "../private/SkGpuFenceSync.h"
+
+
+namespace sk_gpu_test {
+/**
+ * Create an offscreen Oppengl context. Provides a GrGLInterface struct of function pointers for
+ * the context. This class is intended for Skia's internal testing needs and not for general use.
+ */
+class GLContext : public SkNoncopyable {
+public:
+    virtual ~GLContext();
+
+    bool isValid() const { return NULL != gl(); }
+
+    const GrGLInterface *gl() const { return fGL.get(); }
+
+    bool fenceSyncSupport() const { return fFenceSync != nullptr; }
+
+    bool getMaxGpuFrameLag(int *maxFrameLag) const {
+        if (!fFenceSync) {
+            return false;
+        }
+        *maxFrameLag = kMaxFrameLag;
+        return true;
+    }
+
+    void makeCurrent() const;
+
+    /** Used for testing EGLImage integration. Take a GL_TEXTURE_2D and wraps it in an EGL Image */
+    virtual GrEGLImage texture2DToEGLImage(GrGLuint /*texID*/) const { return 0; }
+
+    virtual void destroyEGLImage(GrEGLImage) const { }
+
+    /** Used for testing GL_TEXTURE_RECTANGLE integration. */
+    GrGLint createTextureRectangle(int width, int height, GrGLenum internalFormat,
+                                   GrGLenum externalFormat, GrGLenum externalType,
+                                   GrGLvoid *data);
+
+    /**
+     * Used for testing EGLImage integration. Takes a EGLImage and wraps it in a
+     * GL_TEXTURE_EXTERNAL_OES.
+     */
+    virtual GrGLuint eglImageToExternalTexture(GrEGLImage) const { return 0; }
+
+    void swapBuffers();
+
+    /**
+     * The only purpose of this function it to provide a means of scheduling
+     * work on the GPU (since all of the subclasses create primary buffers for
+     * testing that are small and not meant to be rendered to the screen).
+     *
+     * If the platform supports fence sync (OpenGL 3.2+ or EGL_KHR_fence_sync),
+     * this will not swap any buffers, but rather emulate triple buffer
+     * synchronization using fences.
+     *
+     * Otherwise it will call the platform SwapBuffers method. This may or may
+     * not perform some sort of synchronization, depending on whether the
+     * drawing surface provided by the platform is double buffered.
+     */
+    void waitOnSyncOrSwap();
+
+    /**
+     * This notifies the context that we are deliberately testing abandoning
+     * the context. It is useful for debugging contexts that would otherwise
+     * test that GPU resources are properly deleted. It also allows a debugging
+     * context to test that further GL calls are not made by Skia GPU code.
+     */
+    void testAbandon();
+
+    /**
+     * Creates a new GL context of the same type and makes the returned context current
+     * (if not null).
+     */
+    virtual GLContext *createNew() const { return nullptr; }
+
+    class GLFenceSync;  // SkGpuFenceSync implementation that uses the OpenGL functionality.
+
+    /*
+     * returns the fencesync object owned by this GLContext
+     */
+    SkGpuFenceSync *fenceSync() { return fFenceSync.get(); }
+
+protected:
+    GLContext();
+
+    /*
+     * Methods that sublcasses must call from their constructors and destructors.
+     */
+    void init(const GrGLInterface *, SkGpuFenceSync * = NULL);
+
+    void teardown();
+
+    /*
+     * Operations that have a platform-dependent implementation.
+     */
+    virtual void onPlatformMakeCurrent() const = 0;
+
+    virtual void onPlatformSwapBuffers() const = 0;
+
+    virtual GrGLFuncPtr onPlatformGetProcAddress(const char *) const = 0;
+
+private:
+    enum {
+        kMaxFrameLag = 3
+    };
+
+    SkAutoTDelete <SkGpuFenceSync> fFenceSync;
+    SkPlatformGpuFence fFrameFences[kMaxFrameLag - 1];
+    int fCurrentFenceIdx;
+
+    /** Subclass provides the gl interface object if construction was
+     *  successful. */
+    SkAutoTUnref<const GrGLInterface> fGL;
+
+    friend class GLFenceSync;  // For onPlatformGetProcAddress.
+};
+
+
+/** Creates platform-dependent GL context object.  The shareContext parameter is in an optional
+ * context with which to share display lists. This should be a pointer to an GLContext created
+ * with SkCreatePlatformGLContext.  NULL indicates that no sharing is to take place. Returns a valid
+ * gl context object or NULL if such can not be created.
+ * Note: If Skia embedder needs a custom GL context that sets up the GL interface, this function
+ * should be implemented by the embedder. Otherwise, the default implementation for the platform
+ * should be compiled in the library.
+ */
+GLContext* CreatePlatformGLContext(GrGLStandard forcedGpuAPI, GLContext *shareContext = nullptr);
+
+}  // namespace sk_gpu_test
+#endif
diff --git a/tools/gpu/gl/angle/GLContext_angle.cpp b/tools/gpu/gl/angle/GLContext_angle.cpp
new file mode 100644
index 0000000..0d7dfdb
--- /dev/null
+++ b/tools/gpu/gl/angle/GLContext_angle.cpp
@@ -0,0 +1,320 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GLContext_angle.h"
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include "gl/GrGLDefines.h"
+#include "gl/GrGLUtil.h"
+
+#include "gl/GrGLInterface.h"
+#include "gl/GrGLAssembleInterface.h"
+#include "../ports/SkOSLibrary.h"
+
+#include <EGL/egl.h>
+
+#define EGL_PLATFORM_ANGLE_ANGLE                0x3202
+#define EGL_PLATFORM_ANGLE_TYPE_ANGLE           0x3203
+#define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE      0x3207
+#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE     0x3208
+#define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE    0x320D
+
+namespace {
+struct Libs {
+    void* fGLLib;
+    void* fEGLLib;
+};
+
+static GrGLFuncPtr angle_get_gl_proc(void* ctx, const char name[]) {
+    const Libs* libs = reinterpret_cast<const Libs*>(ctx);
+    GrGLFuncPtr proc = (GrGLFuncPtr) GetProcedureAddress(libs->fGLLib, name);
+    if (proc) {
+        return proc;
+    }
+    proc = (GrGLFuncPtr) GetProcedureAddress(libs->fEGLLib, name);
+    if (proc) {
+        return proc;
+    }
+    return eglGetProcAddress(name);
+}
+
+void* get_angle_egl_display(void* nativeDisplay, bool useGLBackend) {
+    PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT;
+    eglGetPlatformDisplayEXT =
+        (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");
+
+    // We expect ANGLE to support this extension
+    if (!eglGetPlatformDisplayEXT) {
+        return EGL_NO_DISPLAY;
+    }
+
+    EGLDisplay display = EGL_NO_DISPLAY;
+    if (useGLBackend) {
+        EGLint attribs[3] = {
+            EGL_PLATFORM_ANGLE_TYPE_ANGLE,
+            EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE,
+            EGL_NONE
+        };
+        display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, nativeDisplay, attribs);
+    } else {
+        // Try for an ANGLE D3D11 context, fall back to D3D9.
+        EGLint attribs[3][3] = {
+            {
+                EGL_PLATFORM_ANGLE_TYPE_ANGLE,
+                EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
+                EGL_NONE
+            },
+            {
+                EGL_PLATFORM_ANGLE_TYPE_ANGLE,
+                EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE,
+                EGL_NONE
+            },
+        };
+        for (int i = 0; i < 3 && display == EGL_NO_DISPLAY; ++i) {
+            display = eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE,nativeDisplay, attribs[i]);
+        }
+    }
+    return display;
+}
+
+class ANGLEGLContext : public sk_gpu_test::GLContext {
+public:
+    ANGLEGLContext(bool preferGLBackend);
+    ~ANGLEGLContext() override;
+
+    GrEGLImage texture2DToEGLImage(GrGLuint texID) const override;
+    void destroyEGLImage(GrEGLImage) const override;
+    GrGLuint eglImageToExternalTexture(GrEGLImage) const override;
+    sk_gpu_test::GLContext* createNew() const override;
+
+private:
+    void destroyGLContext();
+
+    void onPlatformMakeCurrent() const override;
+    void onPlatformSwapBuffers() const override;
+    GrGLFuncPtr onPlatformGetProcAddress(const char* name) const override;
+
+    void* fContext;
+    void* fDisplay;
+    void* fSurface;
+    bool  fIsGLBackend;
+};
+
+ANGLEGLContext::ANGLEGLContext(bool useGLBackend)
+    : fContext(EGL_NO_CONTEXT)
+    , fDisplay(EGL_NO_DISPLAY)
+    , fSurface(EGL_NO_SURFACE) {
+
+    EGLint numConfigs;
+    static const EGLint configAttribs[] = {
+        EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+        EGL_RED_SIZE, 8,
+        EGL_GREEN_SIZE, 8,
+        EGL_BLUE_SIZE, 8,
+        EGL_ALPHA_SIZE, 8,
+        EGL_NONE
+    };
+
+    fIsGLBackend = useGLBackend;
+    fDisplay = get_angle_egl_display(EGL_DEFAULT_DISPLAY, useGLBackend);
+    if (EGL_NO_DISPLAY == fDisplay) {
+        SkDebugf("Could not create EGL display!");
+        return;
+    }
+
+    EGLint majorVersion;
+    EGLint minorVersion;
+    eglInitialize(fDisplay, &majorVersion, &minorVersion);
+
+    EGLConfig surfaceConfig;
+    eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs);
+
+    static const EGLint contextAttribs[] = {
+        EGL_CONTEXT_CLIENT_VERSION, 2,
+        EGL_NONE
+    };
+    fContext = eglCreateContext(fDisplay, surfaceConfig, nullptr, contextAttribs);
+
+
+    static const EGLint surfaceAttribs[] = {
+        EGL_WIDTH, 1,
+        EGL_HEIGHT, 1,
+        EGL_NONE
+    };
+
+    fSurface = eglCreatePbufferSurface(fDisplay, surfaceConfig, surfaceAttribs);
+
+    eglMakeCurrent(fDisplay, fSurface, fSurface, fContext);
+
+    SkAutoTUnref<const GrGLInterface> gl(sk_gpu_test::CreateANGLEGLInterface());
+    if (nullptr == gl.get()) {
+        SkDebugf("Could not create ANGLE GL interface!\n");
+        this->destroyGLContext();
+        return;
+    }
+    if (!gl->validate()) {
+        SkDebugf("Could not validate ANGLE GL interface!\n");
+        this->destroyGLContext();
+        return;
+    }
+
+    this->init(gl.release());
+}
+
+ANGLEGLContext::~ANGLEGLContext() {
+    this->teardown();
+    this->destroyGLContext();
+}
+
+GrEGLImage ANGLEGLContext::texture2DToEGLImage(GrGLuint texID) const {
+    if (!this->gl()->hasExtension("EGL_KHR_gl_texture_2D_image")) {
+        return GR_EGL_NO_IMAGE;
+    }
+    GrEGLImage img;
+    GrEGLint attribs[] = { GR_EGL_GL_TEXTURE_LEVEL, 0,
+                           GR_EGL_IMAGE_PRESERVED, GR_EGL_TRUE,
+                           GR_EGL_NONE };
+    // 64 bit cast is to shut Visual C++ up about casting 32 bit value to a pointer.
+    GrEGLClientBuffer clientBuffer = reinterpret_cast<GrEGLClientBuffer>((uint64_t)texID);
+    GR_GL_CALL_RET(this->gl(), img,
+                   EGLCreateImage(fDisplay, fContext, GR_EGL_GL_TEXTURE_2D, clientBuffer,
+                                  attribs));
+    return img;
+}
+
+void ANGLEGLContext::destroyEGLImage(GrEGLImage image) const {
+    GR_GL_CALL(this->gl(), EGLDestroyImage(fDisplay, image));
+}
+
+GrGLuint ANGLEGLContext::eglImageToExternalTexture(GrEGLImage image) const {
+    GrGLClearErr(this->gl());
+    if (!this->gl()->hasExtension("GL_OES_EGL_image_external")) {
+        return 0;
+    }
+    typedef GrGLvoid (*EGLImageTargetTexture2DProc)(GrGLenum, GrGLeglImage);
+    EGLImageTargetTexture2DProc glEGLImageTargetTexture2D =
+        (EGLImageTargetTexture2DProc)eglGetProcAddress("glEGLImageTargetTexture2DOES");
+    if (!glEGLImageTargetTexture2D) {
+        return 0;
+    }
+    GrGLuint texID;
+    GR_GL_CALL(this->gl(), GenTextures(1, &texID));
+    if (!texID) {
+        return 0;
+    }
+    GR_GL_CALL(this->gl(), BindTexture(GR_GL_TEXTURE_EXTERNAL, texID));
+    if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) {
+        GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
+        return 0;
+    }
+    glEGLImageTargetTexture2D(GR_GL_TEXTURE_EXTERNAL, image);
+    if (GR_GL_GET_ERROR(this->gl()) != GR_GL_NO_ERROR) {
+        GR_GL_CALL(this->gl(), DeleteTextures(1, &texID));
+        return 0;
+    }
+    return texID;
+}
+
+sk_gpu_test::GLContext* ANGLEGLContext::createNew() const {
+#ifdef SK_BUILD_FOR_WIN
+    sk_gpu_test::GLContext* ctx = fIsGLBackend ? sk_gpu_test::CreateANGLEOpenGLGLContext()
+                                               : sk_gpu_test::CreateANGLEDirect3DGLContext();
+#else
+    sk_gpu_test::GLContext* ctx = sk_gpu_test::CreateANGLEOpenGLGLContext();
+#endif
+    if (ctx) {
+        ctx->makeCurrent();
+    }
+    return ctx;
+}
+
+void ANGLEGLContext::destroyGLContext() {
+    if (fDisplay) {
+        eglMakeCurrent(fDisplay, 0, 0, 0);
+
+        if (fContext) {
+            eglDestroyContext(fDisplay, fContext);
+            fContext = EGL_NO_CONTEXT;
+        }
+
+        if (fSurface) {
+            eglDestroySurface(fDisplay, fSurface);
+            fSurface = EGL_NO_SURFACE;
+        }
+
+        //TODO should we close the display?
+        fDisplay = EGL_NO_DISPLAY;
+    }
+}
+
+void ANGLEGLContext::onPlatformMakeCurrent() const {
+    if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
+        SkDebugf("Could not set the context.\n");
+    }
+}
+
+void ANGLEGLContext::onPlatformSwapBuffers() const {
+    if (!eglSwapBuffers(fDisplay, fSurface)) {
+        SkDebugf("Could not complete eglSwapBuffers.\n");
+    }
+}
+
+GrGLFuncPtr ANGLEGLContext::onPlatformGetProcAddress(const char* name) const {
+    return eglGetProcAddress(name);
+}
+}  // anonymous namespace
+
+namespace sk_gpu_test {
+const GrGLInterface* CreateANGLEGLInterface() {
+    static Libs gLibs = { nullptr, nullptr };
+
+    if (nullptr == gLibs.fGLLib) {
+        // We load the ANGLE library and never let it go
+#if defined _WIN32
+        gLibs.fGLLib = DynamicLoadLibrary("libGLESv2.dll");
+        gLibs.fEGLLib = DynamicLoadLibrary("libEGL.dll");
+#elif defined SK_BUILD_FOR_MAC
+        gLibs.fGLLib = DynamicLoadLibrary("libGLESv2.dylib");
+        gLibs.fEGLLib = DynamicLoadLibrary("libEGL.dylib");
+#else
+        gLibs.fGLLib = DynamicLoadLibrary("libGLESv2.so");
+        gLibs.fEGLLib = DynamicLoadLibrary("libEGL.so");
+#endif
+    }
+
+    if (nullptr == gLibs.fGLLib || nullptr == gLibs.fEGLLib) {
+        // We can't setup the interface correctly w/o the so
+        return nullptr;
+    }
+
+    return GrGLAssembleGLESInterface(&gLibs, angle_get_gl_proc);
+}
+
+#ifdef SK_BUILD_FOR_WIN
+GLContext* CreateANGLEDirect3DGLContext() {
+        SkANGLEGLContext* ctx = new SkANGLEGLContext(false);
+        if (!ctx->isValid()) {
+            delete ctx;
+            return NULL;
+        }
+        return ctx;
+    }
+#endif
+
+GLContext* CreateANGLEOpenGLGLContext() {
+    ANGLEGLContext* ctx = new ANGLEGLContext(true);
+    if (!ctx->isValid()) {
+        delete ctx;
+        return NULL;
+    }
+    return ctx;
+}
+}  // namespace sk_gpu_test
diff --git a/tools/gpu/gl/angle/GLContext_angle.h b/tools/gpu/gl/angle/GLContext_angle.h
new file mode 100644
index 0000000..519ea6b
--- /dev/null
+++ b/tools/gpu/gl/angle/GLContext_angle.h
@@ -0,0 +1,30 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef GLContext_angle_DEFINED
+#define GLContext_angle_DEFINED
+
+#include "gl/GLContext.h"
+
+namespace sk_gpu_test {
+
+/**
+ * Creates a GrGLInterface for the currently ANGLE GL context currently bound in ANGLE's EGL
+ * implementation.
+ */
+const GrGLInterface* CreateANGLEGLInterface();
+
+#ifdef SK_BUILD_FOR_WIN
+/** Creates a GLContext backed by ANGLE's Direct3D backend. */
+GLContext* CreateANGLEDirect3DGLContext();
+#endif
+
+/** Creates a GLContext backed by ANGLE's OpenGL backend. */
+GLContext* CreateANGLEOpenGLGLContext();
+
+}  // namespace sk_gpu_test
+#endif
diff --git a/tools/gpu/gl/command_buffer/GLContext_command_buffer.cpp b/tools/gpu/gl/command_buffer/GLContext_command_buffer.cpp
new file mode 100644
index 0000000..b878cb4
--- /dev/null
+++ b/tools/gpu/gl/command_buffer/GLContext_command_buffer.cpp
@@ -0,0 +1,345 @@
+
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkOnce.h"
+#include "gl/GrGLInterface.h"
+#include "gl/GrGLAssembleInterface.h"
+#include "gl/command_buffer/GLContext_command_buffer.h"
+#include "../ports/SkOSEnvironment.h"
+#include "../ports/SkOSLibrary.h"
+
+#if defined SK_BUILD_FOR_MAC
+
+// EGL doesn't exist on the mac, so expose what we need to get the command buffer's EGL running.
+typedef void *EGLDisplay;
+typedef unsigned int EGLBoolean;
+typedef void *EGLConfig;
+typedef void *EGLSurface;
+typedef void *EGLContext;
+typedef int32_t EGLint;
+typedef void* EGLNativeDisplayType;
+typedef void* EGLNativeWindowType;
+typedef void (*__eglMustCastToProperFunctionPointerType)(void);
+#define EGL_FALSE 0
+#define EGL_OPENGL_ES2_BIT 0x0004
+#define EGL_CONTEXT_CLIENT_VERSION 0x3098
+#define EGL_NO_SURFACE ((EGLSurface)0)
+#define EGL_NO_DISPLAY ((EGLDisplay)0)
+#define EGL_NO_CONTEXT ((EGLContext)0)
+#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0)
+#define EGL_SURFACE_TYPE 0x3033
+#define EGL_PBUFFER_BIT 0x0001
+#define EGL_RENDERABLE_TYPE 0x3040
+#define EGL_RED_SIZE 0x3024
+#define EGL_GREEN_SIZE 0x3023
+#define EGL_BLUE_SIZE 0x3022
+#define EGL_ALPHA_SIZE 0x3021
+#define EGL_DEPTH_SIZE 0x3025
+#define EGL_STENCIL_SIZE 0x3025
+#define EGL_SAMPLES 0x3031
+#define EGL_SAMPLE_BUFFERS 0x3032
+#define EGL_NONE 0x3038
+#define EGL_WIDTH 0x3057
+#define EGL_HEIGHT 0x3056
+
+#else
+
+#include <EGL/egl.h>
+
+#endif
+
+typedef EGLDisplay (*GetDisplayProc)(EGLNativeDisplayType display_id);
+typedef EGLBoolean (*InitializeProc)(EGLDisplay dpy, EGLint *major, EGLint *minor);
+typedef EGLBoolean (*TerminateProc)(EGLDisplay dpy);
+typedef EGLBoolean (*ChooseConfigProc)(EGLDisplay dpy, const EGLint* attrib_list, EGLConfig* configs, EGLint config_size, EGLint* num_config);
+typedef EGLBoolean (*GetConfigAttrib)(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint* value);
+typedef EGLSurface (*CreateWindowSurfaceProc)(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint* attrib_list);
+typedef EGLSurface (*CreatePbufferSurfaceProc)(EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list);
+typedef EGLBoolean (*DestroySurfaceProc)(EGLDisplay dpy, EGLSurface surface);
+typedef EGLContext (*CreateContextProc)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint* attrib_list);
+typedef EGLBoolean (*DestroyContextProc)(EGLDisplay dpy, EGLContext ctx);
+typedef EGLBoolean (*MakeCurrentProc)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
+typedef EGLBoolean (*SwapBuffersProc)(EGLDisplay dpy, EGLSurface surface);
+typedef __eglMustCastToProperFunctionPointerType (*GetProcAddressProc)(const char* procname);
+
+static GetDisplayProc gfGetDisplay = nullptr;
+static InitializeProc gfInitialize = nullptr;
+static TerminateProc gfTerminate = nullptr;
+static ChooseConfigProc gfChooseConfig = nullptr;
+static GetConfigAttrib gfGetConfigAttrib = nullptr;
+static CreateWindowSurfaceProc gfCreateWindowSurface = nullptr;
+static CreatePbufferSurfaceProc gfCreatePbufferSurface = nullptr;
+static DestroySurfaceProc gfDestroySurface = nullptr;
+static CreateContextProc gfCreateContext = nullptr;
+static DestroyContextProc gfDestroyContext = nullptr;
+static MakeCurrentProc gfMakeCurrent = nullptr;
+static SwapBuffersProc gfSwapBuffers = nullptr;
+static GetProcAddressProc gfGetProcAddress = nullptr;
+
+static void* gLibrary = nullptr;
+static bool gfFunctionsLoadedSuccessfully = false;
+
+namespace {
+static void load_command_buffer_functions() {
+    if (!gLibrary) {
+#if defined _WIN32
+        gLibrary = DynamicLoadLibrary("command_buffer_gles2.dll");
+#elif defined SK_BUILD_FOR_MAC
+        gLibrary = DynamicLoadLibrary("libcommand_buffer_gles2.dylib");
+#else
+        gLibrary = DynamicLoadLibrary("libcommand_buffer_gles2.so");
+#endif // defined _WIN32
+        if (gLibrary) {
+            gfGetDisplay = (GetDisplayProc)GetProcedureAddress(gLibrary, "eglGetDisplay");
+            gfInitialize = (InitializeProc)GetProcedureAddress(gLibrary, "eglInitialize");
+            gfTerminate = (TerminateProc)GetProcedureAddress(gLibrary, "eglTerminate");
+            gfChooseConfig = (ChooseConfigProc)GetProcedureAddress(gLibrary, "eglChooseConfig");
+            gfGetConfigAttrib = (GetConfigAttrib)GetProcedureAddress(gLibrary, "eglGetConfigAttrib");
+            gfCreateWindowSurface = (CreateWindowSurfaceProc)GetProcedureAddress(gLibrary, "eglCreateWindowSurface");
+            gfCreatePbufferSurface = (CreatePbufferSurfaceProc)GetProcedureAddress(gLibrary, "eglCreatePbufferSurface");
+            gfDestroySurface = (DestroySurfaceProc)GetProcedureAddress(gLibrary, "eglDestroySurface");
+            gfCreateContext = (CreateContextProc)GetProcedureAddress(gLibrary, "eglCreateContext");
+            gfDestroyContext = (DestroyContextProc)GetProcedureAddress(gLibrary, "eglDestroyContext");
+            gfMakeCurrent = (MakeCurrentProc)GetProcedureAddress(gLibrary, "eglMakeCurrent");
+            gfSwapBuffers = (SwapBuffersProc)GetProcedureAddress(gLibrary, "eglSwapBuffers");
+            gfGetProcAddress = (GetProcAddressProc)GetProcedureAddress(gLibrary, "eglGetProcAddress");
+
+            gfFunctionsLoadedSuccessfully = gfGetDisplay && gfInitialize && gfTerminate &&
+                                            gfChooseConfig && gfCreateWindowSurface &&
+                                            gfCreatePbufferSurface && gfDestroySurface &&
+                                            gfCreateContext && gfDestroyContext && gfMakeCurrent &&
+                                            gfSwapBuffers && gfGetProcAddress;
+
+        }
+    }
+}
+
+static GrGLFuncPtr command_buffer_get_gl_proc(void* ctx, const char name[]) {
+    if (!gfFunctionsLoadedSuccessfully) {
+        return nullptr;
+    }
+    return gfGetProcAddress(name);
+}
+
+SK_DECLARE_STATIC_ONCE(loadCommandBufferOnce);
+static void load_command_buffer_once() {
+    SkOnce(&loadCommandBufferOnce, load_command_buffer_functions);
+}
+
+static const GrGLInterface* create_command_buffer_interface() {
+    load_command_buffer_once();
+    if (!gfFunctionsLoadedSuccessfully) {
+        return nullptr;
+    }
+    return GrGLAssembleGLESInterface(gLibrary, command_buffer_get_gl_proc);
+}
+
+}  // anonymous namespace
+
+namespace sk_gpu_test {
+
+CommandBufferGLContext::CommandBufferGLContext()
+    : fContext(EGL_NO_CONTEXT), fDisplay(EGL_NO_DISPLAY), fSurface(EGL_NO_SURFACE) {
+
+    static const EGLint configAttribs[] = {
+        EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+        EGL_RED_SIZE, 8,
+        EGL_GREEN_SIZE, 8,
+        EGL_BLUE_SIZE, 8,
+        EGL_ALPHA_SIZE, 8,
+        EGL_NONE
+    };
+
+    static const EGLint surfaceAttribs[] = {
+        EGL_WIDTH, 1,
+        EGL_HEIGHT, 1,
+        EGL_NONE
+    };
+
+    initializeGLContext(nullptr, configAttribs, surfaceAttribs);
+}
+
+CommandBufferGLContext::CommandBufferGLContext(void *nativeWindow, int msaaSampleCount) {
+    static const EGLint surfaceAttribs[] = {EGL_NONE};
+
+    EGLint configAttribs[] = {
+        EGL_RED_SIZE, 8,
+        EGL_GREEN_SIZE, 8,
+        EGL_BLUE_SIZE, 8,
+        EGL_ALPHA_SIZE, 8,
+        EGL_DEPTH_SIZE, 8,
+        EGL_STENCIL_SIZE, 8,
+        EGL_SAMPLE_BUFFERS, 1,
+        EGL_SAMPLES, msaaSampleCount,
+        EGL_NONE
+    };
+    if (msaaSampleCount == 0) {
+        configAttribs[12] = EGL_NONE;
+    }
+
+    initializeGLContext(nativeWindow, configAttribs, surfaceAttribs);
+}
+
+void CommandBufferGLContext::initializeGLContext(void *nativeWindow, const int *configAttribs,
+                                                 const int *surfaceAttribs) {
+    load_command_buffer_once();
+    if (!gfFunctionsLoadedSuccessfully) {
+        SkDebugf("Command Buffer: Could not load EGL functions.\n");
+        return;
+    }
+
+    // Make sure CHROMIUM_path_rendering is enabled for NVPR support.
+    sk_setenv("CHROME_COMMAND_BUFFER_GLES2_ARGS", "--enable-gl-path-rendering");
+    fDisplay = gfGetDisplay(EGL_DEFAULT_DISPLAY);
+    if (EGL_NO_DISPLAY == fDisplay) {
+        SkDebugf("Command Buffer: Could not create EGL display.\n");
+        return;
+    }
+
+    EGLint majorVersion;
+    EGLint minorVersion;
+    if (!gfInitialize(fDisplay, &majorVersion, &minorVersion)) {
+        SkDebugf("Command Buffer: Could not initialize EGL display.\n");
+        this->destroyGLContext();
+        return;
+    }
+
+    EGLint numConfigs;
+    if (!gfChooseConfig(fDisplay, configAttribs, static_cast<EGLConfig *>(&fConfig), 1,
+                        &numConfigs) || numConfigs != 1) {
+        SkDebugf("Command Buffer: Could not choose EGL config.\n");
+        this->destroyGLContext();
+        return;
+    }
+
+    if (nativeWindow) {
+        fSurface = gfCreateWindowSurface(fDisplay,
+                                         static_cast<EGLConfig>(fConfig),
+                                         (EGLNativeWindowType) nativeWindow,
+                                         surfaceAttribs);
+    } else {
+        fSurface = gfCreatePbufferSurface(fDisplay,
+                                          static_cast<EGLConfig>(fConfig),
+                                          surfaceAttribs);
+    }
+    if (EGL_NO_SURFACE == fSurface) {
+        SkDebugf("Command Buffer: Could not create EGL surface.\n");
+        this->destroyGLContext();
+        return;
+    }
+
+    static const EGLint contextAttribs[] = {
+        EGL_CONTEXT_CLIENT_VERSION, 2,
+        EGL_NONE
+    };
+    fContext = gfCreateContext(fDisplay, static_cast<EGLConfig>(fConfig), nullptr, contextAttribs);
+    if (EGL_NO_CONTEXT == fContext) {
+        SkDebugf("Command Buffer: Could not create EGL context.\n");
+        this->destroyGLContext();
+        return;
+    }
+
+    if (!gfMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
+        SkDebugf("Command Buffer: Could not make EGL context current.\n");
+        this->destroyGLContext();
+        return;
+    }
+
+    SkAutoTUnref<const GrGLInterface> gl(create_command_buffer_interface());
+    if (nullptr == gl.get()) {
+        SkDebugf("Command Buffer: Could not create CommandBuffer GL interface.\n");
+        this->destroyGLContext();
+        return;
+    }
+    if (!gl->validate()) {
+        SkDebugf("Command Buffer: Could not validate CommandBuffer GL interface.\n");
+        this->destroyGLContext();
+        return;
+    }
+
+    this->init(gl.release());
+}
+
+CommandBufferGLContext::~CommandBufferGLContext() {
+    this->teardown();
+    this->destroyGLContext();
+}
+
+void CommandBufferGLContext::destroyGLContext() {
+    if (!gfFunctionsLoadedSuccessfully) {
+        return;
+    }
+    if (fDisplay) {
+        gfMakeCurrent(fDisplay, 0, 0, 0);
+
+        if (fContext) {
+            gfDestroyContext(fDisplay, fContext);
+            fContext = EGL_NO_CONTEXT;
+        }
+
+        if (fSurface) {
+            gfDestroySurface(fDisplay, fSurface);
+            fSurface = EGL_NO_SURFACE;
+        }
+
+        gfTerminate(fDisplay);
+        fDisplay = EGL_NO_DISPLAY;
+    }
+}
+
+void CommandBufferGLContext::onPlatformMakeCurrent() const {
+    if (!gfFunctionsLoadedSuccessfully) {
+        return;
+    }
+    if (!gfMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
+        SkDebugf("Command Buffer: Could not make EGL context current.\n");
+    }
+}
+
+void CommandBufferGLContext::onPlatformSwapBuffers() const {
+    if (!gfFunctionsLoadedSuccessfully) {
+        return;
+    }
+    if (!gfSwapBuffers(fDisplay, fSurface)) {
+        SkDebugf("Command Buffer: Could not complete gfSwapBuffers.\n");
+    }
+}
+
+GrGLFuncPtr CommandBufferGLContext::onPlatformGetProcAddress(const char *name) const {
+    if (!gfFunctionsLoadedSuccessfully) {
+        return nullptr;
+    }
+    return gfGetProcAddress(name);
+}
+
+void CommandBufferGLContext::presentCommandBuffer() {
+    if (this->gl()) {
+        this->gl()->fFunctions.fFlush();
+    }
+
+    this->onPlatformSwapBuffers();
+}
+
+bool CommandBufferGLContext::makeCurrent() {
+    return gfMakeCurrent(fDisplay, fSurface, fSurface, fContext) != EGL_FALSE;
+}
+
+int CommandBufferGLContext::getStencilBits() {
+    EGLint result = 0;
+    gfGetConfigAttrib(fDisplay, static_cast<EGLConfig>(fConfig), EGL_STENCIL_SIZE, &result);
+    return result;
+}
+
+int CommandBufferGLContext::getSampleCount() {
+    EGLint result = 0;
+    gfGetConfigAttrib(fDisplay, static_cast<EGLConfig>(fConfig), EGL_SAMPLES, &result);
+    return result;
+}
+
+}  // namespace sk_gpu_test
diff --git a/tools/gpu/gl/command_buffer/GLContext_command_buffer.h b/tools/gpu/gl/command_buffer/GLContext_command_buffer.h
new file mode 100644
index 0000000..73f02e2
--- /dev/null
+++ b/tools/gpu/gl/command_buffer/GLContext_command_buffer.h
@@ -0,0 +1,68 @@
+
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GLContext_command_buffer_DEFINED
+#define GLContext_command_buffer_DEFINED
+
+#include "gl/GLContext.h"
+
+namespace sk_gpu_test {
+class CommandBufferGLContext : public GLContext {
+public:
+    ~CommandBufferGLContext() override;
+
+    static CommandBufferGLContext *Create() {
+        CommandBufferGLContext *ctx = new CommandBufferGLContext;
+        if (!ctx->isValid()) {
+            delete ctx;
+            return nullptr;
+        }
+        return ctx;
+    }
+
+    static CommandBufferGLContext *Create(void *nativeWindow, int msaaSampleCount) {
+        CommandBufferGLContext *ctx = new CommandBufferGLContext(nativeWindow, msaaSampleCount);
+        if (!ctx->isValid()) {
+            delete ctx;
+            return nullptr;
+        }
+        return ctx;
+    }
+
+    void presentCommandBuffer();
+
+    bool makeCurrent();
+
+    int getStencilBits();
+
+    int getSampleCount();
+
+private:
+    CommandBufferGLContext();
+
+    CommandBufferGLContext(void *nativeWindow, int msaaSampleCount);
+
+    void initializeGLContext(void *nativeWindow, const int *configAttribs,
+                             const int *surfaceAttribs);
+
+    void destroyGLContext();
+
+    void onPlatformMakeCurrent() const override;
+
+    void onPlatformSwapBuffers() const override;
+
+    GrGLFuncPtr onPlatformGetProcAddress(const char *name) const override;
+
+    void *fContext;
+    void *fDisplay;
+    void *fSurface;
+    void *fConfig;
+};
+}   // namespace sk_gpu_test
+
+#endif
diff --git a/tools/gpu/gl/debug/DebugGLContext.cpp b/tools/gpu/gl/debug/DebugGLContext.cpp
new file mode 100644
index 0000000..f4cbbea
--- /dev/null
+++ b/tools/gpu/gl/debug/DebugGLContext.cpp
@@ -0,0 +1,1256 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "DebugGLContext.h"
+
+#include "GrBufferObj.h"
+#include "GrFrameBufferObj.h"
+#include "GrProgramObj.h"
+#include "GrRenderBufferObj.h"
+#include "GrShaderObj.h"
+#include "GrTextureObj.h"
+#include "GrTextureUnitObj.h"
+#include "GrVertexArrayObj.h"
+#include "gl/GrGLTestInterface.h"
+
+#include "SkMutex.h"
+
+namespace {
+
+// Helper macro to make creating an object (where you need to get back a derived type) easier
+#define CREATE(className, classEnum)                     \
+    reinterpret_cast<className *>(this->createObj(classEnum))
+
+// Helper macro to make creating an object (where you need to get back a derived type) easier
+#define FIND(id, className, classEnum)                   \
+    reinterpret_cast<className *>(this->findObject(id, classEnum))
+
+class DebugInterface : public GrGLTestInterface {
+public:
+    DebugInterface()
+        : fCurrGenericID(0)
+        , fCurrTextureUnit(0)
+        , fArrayBuffer(nullptr)
+        , fElementArrayBuffer(nullptr)
+        , fVertexArray(nullptr)
+        , fPackRowLength(0)
+        , fUnpackRowLength(0)
+        , fPackAlignment(4)
+        , fFrameBuffer(nullptr)
+        , fRenderBuffer(nullptr)
+        , fProgram(nullptr)
+        , fAbandoned(false) {
+        for (int i = 0; i < kDefaultMaxTextureUnits; ++i) {
+            fTextureUnits[i] =
+                reinterpret_cast<GrTextureUnitObj*>(this->createObj(kTextureUnit_ObjTypes));
+            fTextureUnits[i]->ref();
+            fTextureUnits[i]->setNumber(i);
+        }
+        this->init(kGL_GrGLStandard);
+    }
+
+    ~DebugInterface() override {
+        // unref & delete the texture units first so they don't show up on the leak report
+        for (int i = 0; i < kDefaultMaxTextureUnits; ++i) {
+            fTextureUnits[i]->unref();
+            fTextureUnits[i]->deleteAction();
+        }
+        for (int i = 0; i < fObjects.count(); ++i) {
+            delete fObjects[i];
+        }
+        fObjects.reset();
+
+        fArrayBuffer = nullptr;
+        fElementArrayBuffer = nullptr;
+        fVertexArray = nullptr;
+
+        this->report();
+    }
+
+    void abandon() const override { fAbandoned = true; }
+
+    GrGLvoid activeTexture(GrGLenum texture) override {
+        // Ganesh offsets the texture unit indices
+        texture -= GR_GL_TEXTURE0;
+        GrAlwaysAssert(texture < kDefaultMaxTextureUnits);
+        fCurrTextureUnit = texture;
+    }
+
+    GrGLvoid attachShader(GrGLuint programID, GrGLuint shaderID) override {
+
+        GrProgramObj *program = FIND(programID, GrProgramObj, kProgram_ObjTypes);
+        GrAlwaysAssert(program);
+
+        GrShaderObj *shader = FIND(shaderID, GrShaderObj, kShader_ObjTypes);
+        GrAlwaysAssert(shader);
+
+        program->AttachShader(shader);
+    }
+
+    ////////////////////////////////////////////////////////////////////////////////
+    GrGLvoid bindTexture(GrGLenum target, GrGLuint textureID) override {
+        GrAlwaysAssert(target == GR_GL_TEXTURE_2D ||
+                       target == GR_GL_TEXTURE_RECTANGLE ||
+                       target == GR_GL_TEXTURE_EXTERNAL);
+
+        // a textureID of 0 is acceptable - it binds to the default texture target
+        GrTextureObj *texture = FIND(textureID, GrTextureObj, kTexture_ObjTypes);
+
+        this->setTexture(texture);
+    }
+
+    ////////////////////////////////////////////////////////////////////////////////
+    GrGLvoid bufferData(GrGLenum target, GrGLsizeiptr size, const GrGLvoid* data,
+                        GrGLenum usage) override {
+        GrAlwaysAssert(GR_GL_ARRAY_BUFFER == target ||
+                       GR_GL_ELEMENT_ARRAY_BUFFER == target);
+        GrAlwaysAssert(size >= 0);
+        GrAlwaysAssert(GR_GL_STREAM_DRAW == usage ||
+                       GR_GL_STATIC_DRAW == usage ||
+                       GR_GL_DYNAMIC_DRAW == usage);
+
+        GrBufferObj *buffer = nullptr;
+        switch (target) {
+            case GR_GL_ARRAY_BUFFER:
+                buffer = this->getArrayBuffer();
+                break;
+            case GR_GL_ELEMENT_ARRAY_BUFFER:
+                buffer = this->getElementArrayBuffer();
+                break;
+            default:
+                SkFAIL("Unexpected target to glBufferData");
+                break;
+        }
+
+        GrAlwaysAssert(buffer);
+        GrAlwaysAssert(buffer->getBound());
+
+        buffer->allocate(size, reinterpret_cast<const GrGLchar *>(data));
+        buffer->setUsage(usage);
+    }
+
+
+    GrGLvoid pixelStorei(GrGLenum pname, GrGLint param) override {
+
+        switch (pname) {
+            case GR_GL_UNPACK_ROW_LENGTH:
+                fUnpackRowLength = param;
+                break;
+            case GR_GL_PACK_ROW_LENGTH:
+                fPackRowLength = param;
+                break;
+            case GR_GL_UNPACK_ALIGNMENT:
+                break;
+            case GR_GL_PACK_ALIGNMENT:
+                fPackAlignment = param;
+                break;
+            default:
+                GrAlwaysAssert(false);
+                break;
+        }
+    }
+
+    GrGLvoid readPixels(GrGLint x,
+                        GrGLint y,
+                        GrGLsizei width,
+                        GrGLsizei height,
+                        GrGLenum format,
+                        GrGLenum type,
+                        GrGLvoid* pixels) override {
+
+        GrGLint pixelsInRow = width;
+        if (fPackRowLength > 0) {
+            pixelsInRow = fPackRowLength;
+        }
+
+        GrGLint componentsPerPixel = 0;
+
+        switch (format) {
+            case GR_GL_RGBA:
+                // fallthrough
+            case GR_GL_BGRA:
+                componentsPerPixel = 4;
+                break;
+            case GR_GL_RGB:
+                componentsPerPixel = 3;
+                break;
+            case GR_GL_RED:
+                componentsPerPixel = 1;
+                break;
+            default:
+                GrAlwaysAssert(false);
+                break;
+        }
+
+        GrGLint alignment = fPackAlignment;
+
+        GrGLint componentSize = 0;  // size (in bytes) of a single component
+
+        switch (type) {
+            case GR_GL_UNSIGNED_BYTE:
+                componentSize = 1;
+                break;
+            default:
+                GrAlwaysAssert(false);
+                break;
+        }
+
+        GrGLint rowStride = 0;  // number of components (not bytes) to skip
+        if (componentSize >= alignment) {
+            rowStride = componentsPerPixel * pixelsInRow;
+        } else {
+            float fTemp =
+                sk_float_ceil(componentSize * componentsPerPixel * pixelsInRow /
+                              static_cast<float>(alignment));
+            rowStride = static_cast<GrGLint>(alignment * fTemp / componentSize);
+        }
+
+        GrGLchar *scanline = static_cast<GrGLchar *>(pixels);
+        for (int y = 0; y < height; ++y) {
+            memset(scanline, 0, componentsPerPixel * componentSize * width);
+            scanline += rowStride;
+        }
+    }
+
+    GrGLvoid useProgram(GrGLuint programID) override {
+
+        // A programID of 0 is legal
+        GrProgramObj *program = FIND(programID, GrProgramObj, kProgram_ObjTypes);
+
+        this->useProgram(program);
+    }
+
+    GrGLvoid bindFramebuffer(GrGLenum target, GrGLuint frameBufferID) override {
+
+        GrAlwaysAssert(GR_GL_FRAMEBUFFER == target ||
+                       GR_GL_READ_FRAMEBUFFER == target ||
+                       GR_GL_DRAW_FRAMEBUFFER);
+
+        // a frameBufferID of 0 is acceptable - it binds to the default
+        // frame buffer
+        GrFrameBufferObj *frameBuffer = FIND(frameBufferID, GrFrameBufferObj,
+                                             kFrameBuffer_ObjTypes);
+
+        this->setFrameBuffer(frameBuffer);
+    }
+
+    GrGLvoid bindRenderbuffer(GrGLenum target, GrGLuint renderBufferID) override {
+
+        GrAlwaysAssert(GR_GL_RENDERBUFFER == target);
+
+        // a renderBufferID of 0 is acceptable - it unbinds the bound render buffer
+        GrRenderBufferObj *renderBuffer = FIND(renderBufferID, GrRenderBufferObj,
+                                               kRenderBuffer_ObjTypes);
+
+        this->setRenderBuffer(renderBuffer);
+    }
+
+    GrGLvoid deleteTextures(GrGLsizei n, const GrGLuint* textures) override {
+        // first potentially unbind the texture
+        for (unsigned int i = 0; i < kDefaultMaxTextureUnits; ++i) {
+            GrTextureUnitObj *pTU = this->getTextureUnit(i);
+
+            if (pTU->getTexture()) {
+                for (int j = 0; j < n; ++j) {
+
+                    if (textures[j] == pTU->getTexture()->getID()) {
+                        // this ID is the current texture - revert the binding to 0
+                        pTU->setTexture(nullptr);
+                    }
+                }
+            }
+        }
+
+        // TODO: fuse the following block with DeleteRenderBuffers?
+        // Open GL will remove a deleted render buffer from the active
+        // frame buffer but not from any other frame buffer
+        if (this->getFrameBuffer()) {
+
+            GrFrameBufferObj *frameBuffer = this->getFrameBuffer();
+
+            for (int i = 0; i < n; ++i) {
+
+                if (frameBuffer->getColor() &&
+                    textures[i] == frameBuffer->getColor()->getID()) {
+                    frameBuffer->setColor(nullptr);
+                }
+                if (frameBuffer->getDepth() &&
+                    textures[i] == frameBuffer->getDepth()->getID()) {
+                    frameBuffer->setDepth(nullptr);
+                }
+                if (frameBuffer->getStencil() &&
+                    textures[i] == frameBuffer->getStencil()->getID()) {
+                    frameBuffer->setStencil(nullptr);
+                }
+            }
+        }
+
+        // then actually "delete" the buffers
+        for (int i = 0; i < n; ++i) {
+            GrTextureObj *buffer = FIND(textures[i], GrTextureObj, kTexture_ObjTypes);
+            GrAlwaysAssert(buffer);
+
+            // OpenGL gives no guarantees if a texture is deleted while attached to
+            // something other than the currently bound frame buffer
+            GrAlwaysAssert(!buffer->getBound());
+
+            GrAlwaysAssert(!buffer->getDeleted());
+            buffer->deleteAction();
+        }
+
+    }
+
+    GrGLvoid deleteFramebuffers(GrGLsizei n, const GrGLuint *frameBuffers) override {
+
+        // first potentially unbind the buffers
+        if (this->getFrameBuffer()) {
+            for (int i = 0; i < n; ++i) {
+
+                if (frameBuffers[i] ==
+                    this->getFrameBuffer()->getID()) {
+                    // this ID is the current frame buffer - rebind to the default
+                    this->setFrameBuffer(nullptr);
+                }
+            }
+        }
+
+        // then actually "delete" the buffers
+        for (int i = 0; i < n; ++i) {
+            GrFrameBufferObj *buffer = FIND(frameBuffers[i], GrFrameBufferObj,
+                                            kFrameBuffer_ObjTypes);
+            GrAlwaysAssert(buffer);
+
+            GrAlwaysAssert(!buffer->getDeleted());
+            buffer->deleteAction();
+        }
+    }
+
+    GrGLvoid deleteRenderbuffers(GrGLsizei n,const GrGLuint *renderBuffers) override {
+
+        // first potentially unbind the buffers
+        if (this->getRenderBuffer()) {
+            for (int i = 0; i < n; ++i) {
+
+                if (renderBuffers[i] ==
+                    this->getRenderBuffer()->getID()) {
+                    // this ID is the current render buffer - make no
+                    // render buffer be bound
+                    this->setRenderBuffer(nullptr);
+                }
+            }
+        }
+
+        // TODO: fuse the following block with DeleteTextures?
+        // Open GL will remove a deleted render buffer from the active frame
+        // buffer but not from any other frame buffer
+        if (this->getFrameBuffer()) {
+
+            GrFrameBufferObj *frameBuffer = this->getFrameBuffer();
+
+            for (int i = 0; i < n; ++i) {
+
+                if (frameBuffer->getColor() &&
+                    renderBuffers[i] == frameBuffer->getColor()->getID()) {
+                    frameBuffer->setColor(nullptr);
+                }
+                if (frameBuffer->getDepth() &&
+                    renderBuffers[i] == frameBuffer->getDepth()->getID()) {
+                    frameBuffer->setDepth(nullptr);
+                }
+                if (frameBuffer->getStencil() &&
+                    renderBuffers[i] == frameBuffer->getStencil()->getID()) {
+                    frameBuffer->setStencil(nullptr);
+                }
+            }
+        }
+
+        // then actually "delete" the buffers
+        for (int i = 0; i < n; ++i) {
+            GrRenderBufferObj *buffer = FIND(renderBuffers[i], GrRenderBufferObj,
+                                             kRenderBuffer_ObjTypes);
+            GrAlwaysAssert(buffer);
+
+            // OpenGL gives no guarantees if a render buffer is deleted
+            // while attached to something other than the currently
+            // bound frame buffer
+            GrAlwaysAssert(!buffer->getColorBound());
+            GrAlwaysAssert(!buffer->getDepthBound());
+            // However, at GrContext destroy time we release all GrRsources and so stencil buffers
+            // may get deleted before FBOs that refer to them.
+            //GrAlwaysAssert(!buffer->getStencilBound());
+
+            GrAlwaysAssert(!buffer->getDeleted());
+            buffer->deleteAction();
+        }
+    }
+
+    GrGLvoid framebufferRenderbuffer(GrGLenum target,
+                                     GrGLenum attachment,
+                                     GrGLenum renderbuffertarget,
+                                     GrGLuint renderBufferID) override {
+
+        GrAlwaysAssert(GR_GL_FRAMEBUFFER == target);
+        GrAlwaysAssert(GR_GL_COLOR_ATTACHMENT0 == attachment ||
+                       GR_GL_DEPTH_ATTACHMENT == attachment ||
+                       GR_GL_STENCIL_ATTACHMENT == attachment);
+        GrAlwaysAssert(GR_GL_RENDERBUFFER == renderbuffertarget);
+
+        GrFrameBufferObj *framebuffer = this->getFrameBuffer();
+        // A render buffer cannot be attached to the default framebuffer
+        GrAlwaysAssert(framebuffer);
+
+        // a renderBufferID of 0 is acceptable - it unbinds the current
+        // render buffer
+        GrRenderBufferObj *renderbuffer = FIND(renderBufferID, GrRenderBufferObj,
+                                               kRenderBuffer_ObjTypes);
+
+        switch (attachment) {
+            case GR_GL_COLOR_ATTACHMENT0:
+                framebuffer->setColor(renderbuffer);
+                break;
+            case GR_GL_DEPTH_ATTACHMENT:
+                framebuffer->setDepth(renderbuffer);
+                break;
+            case GR_GL_STENCIL_ATTACHMENT:
+                framebuffer->setStencil(renderbuffer);
+                break;
+            default:
+                GrAlwaysAssert(false);
+                break;
+        };
+
+    }
+
+    ////////////////////////////////////////////////////////////////////////////////
+    GrGLvoid framebufferTexture2D(GrGLenum target, GrGLenum attachment, GrGLenum textarget,
+                                  GrGLuint textureID, GrGLint level) override {
+
+        GrAlwaysAssert(GR_GL_FRAMEBUFFER == target);
+        GrAlwaysAssert(GR_GL_COLOR_ATTACHMENT0 == attachment ||
+                       GR_GL_DEPTH_ATTACHMENT == attachment ||
+                       GR_GL_STENCIL_ATTACHMENT == attachment);
+        GrAlwaysAssert(GR_GL_TEXTURE_2D == textarget);
+
+        GrFrameBufferObj *framebuffer = this->getFrameBuffer();
+        // A texture cannot be attached to the default framebuffer
+        GrAlwaysAssert(framebuffer);
+
+        // A textureID of 0 is allowed - it unbinds the currently bound texture
+        GrTextureObj *texture = FIND(textureID, GrTextureObj, kTexture_ObjTypes);
+        if (texture) {
+            // The texture shouldn't be bound to a texture unit - this
+            // could lead to a feedback loop
+            GrAlwaysAssert(!texture->getBound());
+        }
+
+        GrAlwaysAssert(0 == level);
+
+        switch (attachment) {
+            case GR_GL_COLOR_ATTACHMENT0:
+                framebuffer->setColor(texture);
+                break;
+            case GR_GL_DEPTH_ATTACHMENT:
+                framebuffer->setDepth(texture);
+                break;
+            case GR_GL_STENCIL_ATTACHMENT:
+                framebuffer->setStencil(texture);
+                break;
+            default:
+                GrAlwaysAssert(false);
+                break;
+        };
+    }
+
+    GrGLuint createProgram() override {
+
+        GrProgramObj *program = CREATE(GrProgramObj, kProgram_ObjTypes);
+
+        return program->getID();
+    }
+
+    GrGLuint createShader(GrGLenum type) override {
+
+        GrAlwaysAssert(GR_GL_VERTEX_SHADER == type ||
+                       GR_GL_FRAGMENT_SHADER == type);
+
+        GrShaderObj *shader = CREATE(GrShaderObj, kShader_ObjTypes);
+        shader->setType(type);
+
+        return shader->getID();
+    }
+
+    GrGLenum checkFramebufferStatus(GrGLenum target) override { return GR_GL_FRAMEBUFFER_COMPLETE; }
+
+    GrGLvoid deleteProgram(GrGLuint programID) override {
+
+        GrProgramObj *program = FIND(programID, GrProgramObj, kProgram_ObjTypes);
+        GrAlwaysAssert(program);
+
+        if (program->getRefCount()) {
+            // someone is still using this program so we can't delete it here
+            program->setMarkedForDeletion();
+        } else {
+            program->deleteAction();
+        }
+    }
+
+    GrGLvoid deleteShader(GrGLuint shaderID) override {
+
+        GrShaderObj *shader = FIND(shaderID, GrShaderObj, kShader_ObjTypes);
+        GrAlwaysAssert(shader);
+
+        if (shader->getRefCount()) {
+            // someone is still using this shader so we can't delete it here
+            shader->setMarkedForDeletion();
+        } else {
+            shader->deleteAction();
+        }
+    }
+
+    GrGLvoid genBuffers(GrGLsizei n, GrGLuint* ids) override {
+        this->genObjs(kBuffer_ObjTypes, n, ids);
+    }
+
+    GrGLvoid genFramebuffers(GrGLsizei n, GrGLuint* ids) override {
+        this->genObjs(kFrameBuffer_ObjTypes, n, ids);
+    }
+
+    GrGLvoid genRenderbuffers(GrGLsizei n, GrGLuint* ids) override {
+        this->genObjs(kRenderBuffer_ObjTypes, n, ids);
+    }
+
+    GrGLvoid genTextures(GrGLsizei n, GrGLuint* ids) override {
+        this->genObjs(kTexture_ObjTypes, n, ids);
+    }
+
+    GrGLvoid genVertexArrays(GrGLsizei n, GrGLuint* ids) override {
+        this->genObjs(kVertexArray_ObjTypes, n, ids);
+    }
+
+    GrGLvoid genQueries(GrGLsizei n, GrGLuint *ids) override { this->genGenericIds(n, ids); }
+
+    GrGLenum getError() override { return GR_GL_NO_ERROR; }
+
+    GrGLvoid getIntegerv(GrGLenum pname, GrGLint* params) override {
+        // TODO: remove from Ganesh the #defines for gets we don't use.
+        // We would like to minimize gets overall due to performance issues
+        switch (pname) {
+            case GR_GL_CONTEXT_PROFILE_MASK:
+                *params = GR_GL_CONTEXT_COMPATIBILITY_PROFILE_BIT;
+                break;
+            case GR_GL_STENCIL_BITS:
+                *params = 8;
+                break;
+            case GR_GL_SAMPLES:
+                *params = 1;
+                break;
+            case GR_GL_FRAMEBUFFER_BINDING:
+                *params = 0;
+                break;
+            case GR_GL_VIEWPORT:
+                params[0] = 0;
+                params[1] = 0;
+                params[2] = 800;
+                params[3] = 600;
+                break;
+            case GR_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
+            case GR_GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS:
+            case GR_GL_MAX_TEXTURE_IMAGE_UNITS:
+            case GR_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
+                *params = 8;
+                break;
+            case GR_GL_MAX_TEXTURE_COORDS:
+                *params = 8;
+                break;
+            case GR_GL_MAX_VERTEX_UNIFORM_VECTORS:
+                *params = kDefaultMaxVertexUniformVectors;
+                break;
+            case GR_GL_MAX_FRAGMENT_UNIFORM_VECTORS:
+                *params = kDefaultMaxFragmentUniformVectors;
+                break;
+            case GR_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
+                *params = 16 * 4;
+                break;
+            case GR_GL_NUM_COMPRESSED_TEXTURE_FORMATS:
+                *params = 0;
+                break;
+            case GR_GL_COMPRESSED_TEXTURE_FORMATS:
+                break;
+            case GR_GL_MAX_TEXTURE_SIZE:
+                *params = 8192;
+                break;
+            case GR_GL_MAX_RENDERBUFFER_SIZE:
+                *params = 8192;
+                break;
+            case GR_GL_MAX_SAMPLES:
+                *params = 32;
+                break;
+            case GR_GL_MAX_VERTEX_ATTRIBS:
+                *params = kDefaultMaxVertexAttribs;
+                break;
+            case GR_GL_MAX_VARYING_VECTORS:
+                *params = kDefaultMaxVaryingVectors;
+                break;
+            case GR_GL_NUM_EXTENSIONS: {
+                GrGLint i = 0;
+                while (kExtensions[i++]);
+                *params = i;
+                break;
+            }
+            default:
+                SkFAIL("Unexpected pname to GetIntegerv");
+        }
+    }
+
+    GrGLvoid getMultisamplefv(GrGLenum pname, GrGLuint index, GrGLfloat* val) override {
+        val[0] = val[1] = 0.5f;
+    }
+
+    GrGLvoid getProgramiv(GrGLuint program, GrGLenum pname, GrGLint* params) override {
+        this->getShaderOrProgramiv(program, pname, params);
+    }
+
+    GrGLvoid getProgramInfoLog(GrGLuint program, GrGLsizei bufsize, GrGLsizei* length,
+                               char* infolog) override {
+        this->getInfoLog(program, bufsize, length, infolog);
+    }
+
+    GrGLvoid getQueryiv(GrGLenum GLtarget, GrGLenum pname, GrGLint *params) override {
+        switch (pname) {
+            case GR_GL_CURRENT_QUERY:
+                *params = 0;
+                break;
+            case GR_GL_QUERY_COUNTER_BITS:
+                *params = 32;
+                break;
+            default:
+                SkFAIL("Unexpected pname passed GetQueryiv.");
+        }
+    }
+
+    GrGLvoid getQueryObjecti64v(GrGLuint id, GrGLenum pname, GrGLint64 *params) override {
+        this->queryResult(id, pname, params);
+    }
+
+    GrGLvoid getQueryObjectiv(GrGLuint id, GrGLenum pname, GrGLint *params) override {
+        this->queryResult(id, pname, params);
+    }
+
+    GrGLvoid getQueryObjectui64v(GrGLuint id, GrGLenum pname, GrGLuint64 *params) override {
+        this->queryResult(id, pname, params);
+    }
+
+    GrGLvoid getQueryObjectuiv(GrGLuint id, GrGLenum pname, GrGLuint *params) override {
+        this->queryResult(id, pname, params);
+    }
+
+    GrGLvoid getShaderiv(GrGLuint shader, GrGLenum pname, GrGLint* params) override {
+        this->getShaderOrProgramiv(shader, pname, params);
+    }
+
+    GrGLvoid getShaderInfoLog(GrGLuint shader, GrGLsizei bufsize, GrGLsizei* length,
+                              char* infolog) override {
+        this->getInfoLog(shader, bufsize, length, infolog);
+    }
+
+    const GrGLubyte* getString(GrGLenum name) override {
+        switch (name) {
+            case GR_GL_EXTENSIONS:
+                return CombinedExtensionString();
+            case GR_GL_VERSION:
+                return (const GrGLubyte*)"4.0 Debug GL";
+            case GR_GL_SHADING_LANGUAGE_VERSION:
+                return (const GrGLubyte*)"4.20.8 Debug GLSL";
+            case GR_GL_VENDOR:
+                return (const GrGLubyte*)"Debug Vendor";
+            case GR_GL_RENDERER:
+                return (const GrGLubyte*)"The Debug (Non-)Renderer";
+            default:
+                SkFAIL("Unexpected name passed to GetString");
+                return nullptr;
+        }
+    }
+
+    const GrGLubyte* getStringi(GrGLenum name, GrGLuint i) override {
+        switch (name) {
+            case GR_GL_EXTENSIONS: {
+                GrGLint count;
+                this->getIntegerv(GR_GL_NUM_EXTENSIONS, &count);
+                if ((GrGLint)i <= count) {
+                    return (const GrGLubyte*) kExtensions[i];
+                } else {
+                    return nullptr;
+                }
+            }
+            default:
+                SkFAIL("Unexpected name passed to GetStringi");
+                return nullptr;
+        }
+    }
+
+    GrGLvoid getTexLevelParameteriv(GrGLenum target, GrGLint level, GrGLenum pname,
+                                    GrGLint* params) override {
+        // we used to use this to query stuff about externally created textures,
+        // now we just require clients to tell us everything about the texture.
+        SkFAIL("Should never query texture parameters.");
+    }
+
+    GrGLvoid deleteVertexArrays(GrGLsizei n, const GrGLuint* ids) override {
+        for (GrGLsizei i = 0; i < n; ++i) {
+            GrVertexArrayObj* array = FIND(ids[i], GrVertexArrayObj, kVertexArray_ObjTypes);
+            GrAlwaysAssert(array);
+
+            // Deleting the current vertex array binds object 0
+            if (this->getVertexArray() == array) {
+                this->setVertexArray(nullptr);
+            }
+
+            if (array->getRefCount()) {
+                // someone is still using this vertex array so we can't delete it here
+                array->setMarkedForDeletion();
+            } else {
+                array->deleteAction();
+            }
+        }
+    }
+
+    GrGLvoid bindVertexArray(GrGLuint id) override {
+        GrVertexArrayObj* array = FIND(id, GrVertexArrayObj, kVertexArray_ObjTypes);
+        GrAlwaysAssert((0 == id) || array);
+        this->setVertexArray(array);
+    }
+
+    GrGLvoid bindBuffer(GrGLenum target, GrGLuint bufferID) override {
+        GrAlwaysAssert(GR_GL_ARRAY_BUFFER == target || GR_GL_ELEMENT_ARRAY_BUFFER == target);
+
+        GrBufferObj *buffer = FIND(bufferID, GrBufferObj, kBuffer_ObjTypes);
+        // 0 is a permissible bufferID - it unbinds the current buffer
+
+        switch (target) {
+            case GR_GL_ARRAY_BUFFER:
+                this->setArrayBuffer(buffer);
+                break;
+            case GR_GL_ELEMENT_ARRAY_BUFFER:
+                this->setElementArrayBuffer(buffer);
+                break;
+            default:
+                SkFAIL("Unexpected target to glBindBuffer");
+                break;
+        }
+    }
+
+    // deleting a bound buffer has the side effect of binding 0
+    GrGLvoid deleteBuffers(GrGLsizei n, const GrGLuint* ids) override {
+        // first potentially unbind the buffers
+        for (int i = 0; i < n; ++i) {
+
+            if (this->getArrayBuffer() &&
+                ids[i] == this->getArrayBuffer()->getID()) {
+                // this ID is the current array buffer
+                this->setArrayBuffer(nullptr);
+            }
+            if (this->getElementArrayBuffer() &&
+                ids[i] == this->getElementArrayBuffer()->getID()) {
+                // this ID is the current element array buffer
+                this->setElementArrayBuffer(nullptr);
+            }
+        }
+
+        // then actually "delete" the buffers
+        for (int i = 0; i < n; ++i) {
+            GrBufferObj *buffer = FIND(ids[i], GrBufferObj, kBuffer_ObjTypes);
+            GrAlwaysAssert(buffer);
+
+            GrAlwaysAssert(!buffer->getDeleted());
+            buffer->deleteAction();
+        }
+    }
+
+    // map a buffer to the caller's address space
+    GrGLvoid* mapBufferRange(GrGLenum target, GrGLintptr offset, GrGLsizeiptr length,
+                             GrGLbitfield access) override {
+        GrAlwaysAssert(GR_GL_ARRAY_BUFFER == target ||
+                       GR_GL_ELEMENT_ARRAY_BUFFER == target);
+
+        // We only expect read access and we expect that the buffer or range is always invalidated.
+        GrAlwaysAssert(!SkToBool(GR_GL_MAP_READ_BIT & access));
+        GrAlwaysAssert((GR_GL_MAP_INVALIDATE_BUFFER_BIT | GR_GL_MAP_INVALIDATE_RANGE_BIT) & access);
+
+        GrBufferObj *buffer = nullptr;
+        switch (target) {
+            case GR_GL_ARRAY_BUFFER:
+                buffer = this->getArrayBuffer();
+                break;
+            case GR_GL_ELEMENT_ARRAY_BUFFER:
+                buffer = this->getElementArrayBuffer();
+                break;
+            default:
+                SkFAIL("Unexpected target to glMapBufferRange");
+                break;
+        }
+
+        if (buffer) {
+            GrAlwaysAssert(offset >= 0 && offset + length <= buffer->getSize());
+            GrAlwaysAssert(!buffer->getMapped());
+            buffer->setMapped(offset, length);
+            return buffer->getDataPtr() + offset;
+        }
+
+        GrAlwaysAssert(false);
+        return nullptr;        // no buffer bound to the target
+    }
+
+    GrGLvoid* mapBuffer(GrGLenum target, GrGLenum access) override {
+        GrAlwaysAssert(GR_GL_WRITE_ONLY == access);
+
+        GrBufferObj *buffer = nullptr;
+        switch (target) {
+            case GR_GL_ARRAY_BUFFER:
+                buffer = this->getArrayBuffer();
+                break;
+            case GR_GL_ELEMENT_ARRAY_BUFFER:
+                buffer = this->getElementArrayBuffer();
+                break;
+            default:
+                SkFAIL("Unexpected target to glMapBuffer");
+                break;
+        }
+
+        return this->mapBufferRange(target, 0, buffer->getSize(),
+                                    GR_GL_MAP_WRITE_BIT | GR_GL_MAP_INVALIDATE_BUFFER_BIT);
+    }
+
+    // remove a buffer from the caller's address space
+    // TODO: check if the "access" method from "glMapBuffer" was honored
+    GrGLboolean unmapBuffer(GrGLenum target) override {
+        GrAlwaysAssert(GR_GL_ARRAY_BUFFER == target ||
+                       GR_GL_ELEMENT_ARRAY_BUFFER == target);
+
+        GrBufferObj *buffer = nullptr;
+        switch (target) {
+            case GR_GL_ARRAY_BUFFER:
+                buffer = this->getArrayBuffer();
+                break;
+            case GR_GL_ELEMENT_ARRAY_BUFFER:
+                buffer = this->getElementArrayBuffer();
+                break;
+            default:
+                SkFAIL("Unexpected target to glUnmapBuffer");
+                break;
+        }
+
+        if (buffer) {
+            GrAlwaysAssert(buffer->getMapped());
+            buffer->resetMapped();
+            return GR_GL_TRUE;
+        }
+
+        GrAlwaysAssert(false);
+        return GR_GL_FALSE; // GR_GL_INVALID_OPERATION;
+    }
+
+    GrGLvoid flushMappedBufferRange(GrGLenum target, GrGLintptr offset,
+                                    GrGLsizeiptr length) override {
+        GrAlwaysAssert(GR_GL_ARRAY_BUFFER == target ||
+                       GR_GL_ELEMENT_ARRAY_BUFFER == target);
+
+        GrBufferObj *buffer = nullptr;
+        switch (target) {
+            case GR_GL_ARRAY_BUFFER:
+                buffer = this->getArrayBuffer();
+                break;
+            case GR_GL_ELEMENT_ARRAY_BUFFER:
+                buffer = this->getElementArrayBuffer();
+                break;
+            default:
+                SkFAIL("Unexpected target to glUnmapBuffer");
+                break;
+        }
+
+        if (buffer) {
+            GrAlwaysAssert(buffer->getMapped());
+            GrAlwaysAssert(offset >= 0 && (offset + length) <= buffer->getMappedLength());
+        } else {
+            GrAlwaysAssert(false);
+        }
+    }
+
+    GrGLvoid getBufferParameteriv(GrGLenum target, GrGLenum value, GrGLint* params) override {
+
+        GrAlwaysAssert(GR_GL_ARRAY_BUFFER == target ||
+                       GR_GL_ELEMENT_ARRAY_BUFFER == target);
+        GrAlwaysAssert(GR_GL_BUFFER_SIZE == value ||
+                       GR_GL_BUFFER_USAGE == value);
+
+        GrBufferObj *buffer = nullptr;
+        switch (target) {
+            case GR_GL_ARRAY_BUFFER:
+                buffer = this->getArrayBuffer();
+                break;
+            case GR_GL_ELEMENT_ARRAY_BUFFER:
+                buffer = this->getElementArrayBuffer();
+                break;
+        }
+
+        GrAlwaysAssert(buffer);
+
+        switch (value) {
+            case GR_GL_BUFFER_MAPPED:
+                *params = GR_GL_FALSE;
+                if (buffer)
+                    *params = buffer->getMapped() ? GR_GL_TRUE : GR_GL_FALSE;
+                break;
+            case GR_GL_BUFFER_SIZE:
+                *params = 0;
+                if (buffer)
+                    *params = SkToInt(buffer->getSize());
+                break;
+            case GR_GL_BUFFER_USAGE:
+                *params = GR_GL_STATIC_DRAW;
+                if (buffer)
+                    *params = buffer->getUsage();
+                break;
+            default:
+                SkFAIL("Unexpected value to glGetBufferParamateriv");
+                break;
+        }
+    }
+
+private:
+    // the OpenGLES 2.0 spec says this must be >= 128
+    static const GrGLint kDefaultMaxVertexUniformVectors = 128;
+
+    // the OpenGLES 2.0 spec says this must be >=16
+    static const GrGLint kDefaultMaxFragmentUniformVectors = 16;
+
+    // the OpenGLES 2.0 spec says this must be >= 8
+    static const GrGLint kDefaultMaxVertexAttribs = 8;
+
+    // the OpenGLES 2.0 spec says this must be >= 8
+    static const GrGLint kDefaultMaxVaryingVectors = 8;
+
+    // the OpenGLES 2.0 spec says this must be >= 2
+    static const GrGLint kDefaultMaxTextureUnits = 8;
+
+    static const char* kExtensions[];
+
+    GrGLuint                    fCurrGenericID;
+    GrGLuint                    fCurrTextureUnit;
+    GrTextureUnitObj*           fTextureUnits[kDefaultMaxTextureUnits];
+    GrBufferObj*                fArrayBuffer;
+    GrBufferObj*                fElementArrayBuffer;
+    GrVertexArrayObj*           fVertexArray;
+    GrGLint                     fPackRowLength;
+    GrGLint                     fUnpackRowLength;
+    GrGLint                     fPackAlignment;
+    GrFrameBufferObj*           fFrameBuffer;
+    GrRenderBufferObj*          fRenderBuffer;
+    GrProgramObj*               fProgram;
+    mutable bool                fAbandoned;
+    // global store of all objects
+    SkTArray<GrFakeRefObj *>    fObjects;
+
+    static const GrGLubyte* CombinedExtensionString() {
+        static SkString gExtString;
+        static SkMutex gMutex;
+        gMutex.acquire();
+        if (0 == gExtString.size()) {
+            int i = 0;
+            while (kExtensions[i]) {
+                if (i > 0) {
+                    gExtString.append(" ");
+                }
+                gExtString.append(kExtensions[i]);
+                ++i;
+            }
+        }
+        gMutex.release();
+        return (const GrGLubyte*) gExtString.c_str();
+    }
+
+    GrGLvoid genGenericIds(GrGLsizei n, GrGLuint* ids) {
+        for (int i = 0; i < n; ++i) {
+            ids[i] = ++fCurrGenericID;
+        }
+    }
+
+    GrGLvoid getInfoLog(GrGLuint object, GrGLsizei bufsize, GrGLsizei* length,
+                        char* infolog) {
+        if (length) {
+            *length = 0;
+        }
+        if (bufsize > 0) {
+            *infolog = 0;
+        }
+    }
+
+    GrGLvoid getShaderOrProgramiv(GrGLuint object,  GrGLenum pname, GrGLint* params) {
+        switch (pname) {
+            case GR_GL_LINK_STATUS:  // fallthru
+            case GR_GL_COMPILE_STATUS:
+                *params = GR_GL_TRUE;
+                break;
+            case GR_GL_INFO_LOG_LENGTH:
+                *params = 0;
+                break;
+                // we don't expect any other pnames
+            default:
+                SkFAIL("Unexpected pname to GetProgramiv");
+                break;
+        }
+    }
+
+    template <typename T>
+    void queryResult(GrGLenum GLtarget, GrGLenum pname, T *params) {
+        switch (pname) {
+            case GR_GL_QUERY_RESULT_AVAILABLE:
+                *params = GR_GL_TRUE;
+                break;
+            case GR_GL_QUERY_RESULT:
+                *params = 0;
+                break;
+            default:
+                SkFAIL("Unexpected pname passed to GetQueryObject.");
+                break;
+        }
+    }
+
+    enum ObjTypes {
+        kTexture_ObjTypes = 0,
+        kBuffer_ObjTypes,
+        kRenderBuffer_ObjTypes,
+        kFrameBuffer_ObjTypes,
+        kShader_ObjTypes,
+        kProgram_ObjTypes,
+        kTextureUnit_ObjTypes,
+        kVertexArray_ObjTypes,
+        kObjTypeCount
+    };
+
+    typedef GrFakeRefObj *(*Create)();
+
+    static Create gFactoryFunc[kObjTypeCount];
+
+    GrGLvoid genObjs(ObjTypes type, GrGLsizei n, GrGLuint* ids) {
+        for (int i = 0; i < n; ++i) {
+            GrAlwaysAssert(ids[i] == 0);
+            GrFakeRefObj *obj = this->createObj(type);
+            GrAlwaysAssert(obj);
+            ids[i] = obj->getID();
+        }
+    }
+
+    GrFakeRefObj* createObj(ObjTypes type) {
+        GrFakeRefObj *temp = (*gFactoryFunc[type])();
+
+        fObjects.push_back(temp);
+
+        return temp;
+    }
+
+    GrFakeRefObj* findObject(GrGLuint ID, ObjTypes type) {
+        for (int i = 0; i < fObjects.count(); ++i) {
+            if (fObjects[i]->getID() == ID) { // && fObjects[i]->getType() == type) {
+                // The application shouldn't be accessing objects
+                // that (as far as OpenGL knows) were already deleted
+                GrAlwaysAssert(!fObjects[i]->getDeleted());
+                GrAlwaysAssert(!fObjects[i]->getMarkedForDeletion());
+                return fObjects[i];
+            }
+        }
+        return nullptr;
+    }
+
+    GrTextureUnitObj* getTextureUnit(int unit) {
+        GrAlwaysAssert(0 <= unit && kDefaultMaxTextureUnits > unit);
+
+        return fTextureUnits[unit];
+    }
+
+    void setArrayBuffer(GrBufferObj *arrayBuffer) {
+        if (fArrayBuffer) {
+            // automatically break the binding of the old buffer
+            GrAlwaysAssert(fArrayBuffer->getBound());
+            fArrayBuffer->resetBound();
+
+            GrAlwaysAssert(!fArrayBuffer->getDeleted());
+            fArrayBuffer->unref();
+        }
+
+        fArrayBuffer = arrayBuffer;
+
+        if (fArrayBuffer) {
+            GrAlwaysAssert(!fArrayBuffer->getDeleted());
+            fArrayBuffer->ref();
+
+            GrAlwaysAssert(!fArrayBuffer->getBound());
+            fArrayBuffer->setBound();
+        }
+    }
+
+    GrBufferObj* getArrayBuffer() { return fArrayBuffer; }
+    void setElementArrayBuffer(GrBufferObj *elementArrayBuffer) {
+        if (fElementArrayBuffer) {
+            // automatically break the binding of the old buffer
+            GrAlwaysAssert(fElementArrayBuffer->getBound());
+            fElementArrayBuffer->resetBound();
+
+            GrAlwaysAssert(!fElementArrayBuffer->getDeleted());
+            fElementArrayBuffer->unref();
+        }
+
+        fElementArrayBuffer = elementArrayBuffer;
+
+        if (fElementArrayBuffer) {
+            GrAlwaysAssert(!fElementArrayBuffer->getDeleted());
+            fElementArrayBuffer->ref();
+
+            GrAlwaysAssert(!fElementArrayBuffer->getBound());
+            fElementArrayBuffer->setBound();
+        }
+    }
+
+    GrBufferObj *getElementArrayBuffer() { return fElementArrayBuffer; }
+
+    void setVertexArray(GrVertexArrayObj* vertexArray) {
+        if (vertexArray) {
+            SkASSERT(!vertexArray->getDeleted());
+        }
+        SkRefCnt_SafeAssign(fVertexArray, vertexArray);
+    }
+
+    GrVertexArrayObj* getVertexArray() { return fVertexArray; }
+
+    void setTexture(GrTextureObj *texture) {
+        fTextureUnits[fCurrTextureUnit]->setTexture(texture);
+    }
+
+    void setFrameBuffer(GrFrameBufferObj *frameBuffer) {
+        if (fFrameBuffer) {
+            GrAlwaysAssert(fFrameBuffer->getBound());
+            fFrameBuffer->resetBound();
+
+            GrAlwaysAssert(!fFrameBuffer->getDeleted());
+            fFrameBuffer->unref();
+        }
+
+        fFrameBuffer = frameBuffer;
+
+        if (fFrameBuffer) {
+            GrAlwaysAssert(!fFrameBuffer->getDeleted());
+            fFrameBuffer->ref();
+
+            GrAlwaysAssert(!fFrameBuffer->getBound());
+            fFrameBuffer->setBound();
+        }
+    }
+
+    GrFrameBufferObj *getFrameBuffer() { return fFrameBuffer; }
+
+    void setRenderBuffer(GrRenderBufferObj *renderBuffer) {
+        if (fRenderBuffer) {
+            GrAlwaysAssert(fRenderBuffer->getBound());
+            fRenderBuffer->resetBound();
+
+            GrAlwaysAssert(!fRenderBuffer->getDeleted());
+            fRenderBuffer->unref();
+        }
+
+        fRenderBuffer = renderBuffer;
+
+        if (fRenderBuffer) {
+            GrAlwaysAssert(!fRenderBuffer->getDeleted());
+            fRenderBuffer->ref();
+
+            GrAlwaysAssert(!fRenderBuffer->getBound());
+            fRenderBuffer->setBound();
+        }
+    }
+    GrRenderBufferObj *getRenderBuffer() { return fRenderBuffer; }
+
+    void useProgram(GrProgramObj *program) {
+        if (fProgram) {
+            GrAlwaysAssert(fProgram->getInUse());
+            fProgram->resetInUse();
+
+            GrAlwaysAssert(!fProgram->getDeleted());
+            fProgram->unref();
+        }
+
+        fProgram = program;
+
+        if (fProgram) {
+            GrAlwaysAssert(!fProgram->getDeleted());
+            fProgram->ref();
+
+            GrAlwaysAssert(!fProgram->getInUse());
+            fProgram->setInUse();
+        }
+    }
+
+    void report() const {
+        for (int i = 0; i < fObjects.count(); ++i) {
+            if (!fAbandoned) {
+                GrAlwaysAssert(0 == fObjects[i]->getRefCount());
+                GrAlwaysAssert(fObjects[i]->getDeleted());
+            }
+        }
+    }
+
+    typedef GrGLTestInterface INHERITED;
+};
+
+#undef CREATE
+#undef FIND
+
+DebugInterface::Create DebugInterface::gFactoryFunc[kObjTypeCount] = {
+    GrTextureObj::createGrTextureObj,
+    GrBufferObj::createGrBufferObj,
+    GrRenderBufferObj::createGrRenderBufferObj,
+    GrFrameBufferObj::createGrFrameBufferObj,
+    GrShaderObj::createGrShaderObj,
+    GrProgramObj::createGrProgramObj,
+    GrTextureUnitObj::createGrTextureUnitObj,
+    GrVertexArrayObj::createGrVertexArrayObj,
+};
+
+const char* DebugInterface::kExtensions[] = {
+    "GL_ARB_framebuffer_object",
+    "GL_ARB_blend_func_extended",
+    "GL_ARB_timer_query",
+    "GL_ARB_draw_buffers",
+    "GL_ARB_occlusion_query",
+    "GL_EXT_stencil_wrap",
+    nullptr, // signifies the end of the array.
+};
+
+class DebugGLContext : public sk_gpu_test::GLContext {
+public:
+   DebugGLContext() {
+       this->init(new DebugInterface());
+   }
+
+   ~DebugGLContext() override { this->teardown(); }
+
+private:
+    void onPlatformMakeCurrent() const override {}
+    void onPlatformSwapBuffers() const override {}
+    GrGLFuncPtr onPlatformGetProcAddress(const char*) const override { return nullptr; }
+};
+}  // anonymous namespace
+
+namespace sk_gpu_test {
+GLContext* CreateDebugGLContext() {
+    GLContext* ctx = new DebugGLContext();
+    if (ctx->isValid()) {
+        return ctx;
+    }
+    delete ctx;
+    return nullptr;
+}
+}
diff --git a/tools/gpu/gl/debug/DebugGLContext.h b/tools/gpu/gl/debug/DebugGLContext.h
new file mode 100644
index 0000000..0ac505b
--- /dev/null
+++ b/tools/gpu/gl/debug/DebugGLContext.h
@@ -0,0 +1,17 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef DebugGLContext_DEFINED
+#define DebugGLContext_DEFINED
+
+#include "gl/GLContext.h"
+
+namespace sk_gpu_test {
+GLContext* CreateDebugGLContext();
+}  // namespace sk_gpu_test
+
+#endif
diff --git a/tools/gpu/gl/debug/GrBufferObj.cpp b/tools/gpu/gl/debug/GrBufferObj.cpp
new file mode 100644
index 0000000..37d4438
--- /dev/null
+++ b/tools/gpu/gl/debug/GrBufferObj.cpp
@@ -0,0 +1,31 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrBufferObj.h"
+
+void GrBufferObj::allocate(GrGLsizeiptr size, const GrGLchar *dataPtr) {
+    GrAlwaysAssert(size >= 0);
+
+    // delete pre-existing data
+    delete[] fDataPtr;
+
+    fSize = size;
+    fDataPtr = new GrGLchar[size];
+    if (dataPtr) {
+        memcpy(fDataPtr, dataPtr, fSize);
+    }
+    // TODO: w/ no dataPtr the data is unitialized - this could be tracked
+}
+
+void GrBufferObj::deleteAction() {
+
+    // buffers are automatically unmapped when deleted
+    this->resetMapped();
+
+    this->INHERITED::deleteAction();
+}
diff --git a/tools/gpu/gl/debug/GrBufferObj.h b/tools/gpu/gl/debug/GrBufferObj.h
new file mode 100644
index 0000000..96aef6e
--- /dev/null
+++ b/tools/gpu/gl/debug/GrBufferObj.h
@@ -0,0 +1,76 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrBufferObj_DEFINED
+#define GrBufferObj_DEFINED
+
+#include "GrFakeRefObj.h"
+#include "gl/GrGLDefines.h"
+
+////////////////////////////////////////////////////////////////////////////////
+class GrBufferObj : public GrFakeRefObj {
+    GR_DEFINE_CREATOR(GrBufferObj);
+
+public:
+    GrBufferObj()
+        : GrFakeRefObj()
+        , fDataPtr(nullptr)
+        , fMapped(false)
+        , fBound(false)
+        , fSize(0)
+        , fUsage(GR_GL_STATIC_DRAW) {
+    }
+    virtual ~GrBufferObj() {
+        delete[] fDataPtr;
+    }
+
+    void access() {
+        // cannot access the buffer if it is currently mapped
+        GrAlwaysAssert(!fMapped);
+    }
+
+    void setMapped(GrGLintptr offset, GrGLsizeiptr length) {
+        fMapped = true;
+        fMappedOffset = offset;
+        fMappedLength = length;
+    }
+    void resetMapped()           { fMapped = false; }
+    bool getMapped() const       { return fMapped; }
+    GrGLintptr getMappedOffset() const { return fMappedOffset; }
+    GrGLsizeiptr getMappedLength() const { return fMappedLength; }
+
+    void setBound()              { fBound = true; }
+    void resetBound()            { fBound = false; }
+    bool getBound() const        { return fBound; }
+
+    void allocate(GrGLsizeiptr size, const GrGLchar *dataPtr);
+    GrGLsizeiptr getSize() const { return fSize; }
+    GrGLchar *getDataPtr()       { return fDataPtr; }
+
+    void setUsage(GrGLint usage) { fUsage = usage; }
+    GrGLint getUsage() const     { return fUsage; }
+
+    void deleteAction() override;
+
+protected:
+private:
+
+    GrGLchar*    fDataPtr;
+    bool         fMapped;       // is the buffer object mapped via "glMapBuffer[Range]"?
+    GrGLintptr   fMappedOffset; // the offset of the buffer range that is mapped
+    GrGLsizeiptr fMappedLength; // the size of the buffer range that is mapped
+    bool         fBound;        // is the buffer object bound via "glBindBuffer"?
+    GrGLsizeiptr fSize;         // size in bytes
+    GrGLint      fUsage;        // one of: GL_STREAM_DRAW,
+                                //         GL_STATIC_DRAW,
+                                //         GL_DYNAMIC_DRAW
+
+    typedef GrFakeRefObj INHERITED;
+};
+
+#endif // GrBufferObj_DEFINED
diff --git a/tools/gpu/gl/debug/GrFBBindableObj.h b/tools/gpu/gl/debug/GrFBBindableObj.h
new file mode 100644
index 0000000..e2b43a6
--- /dev/null
+++ b/tools/gpu/gl/debug/GrFBBindableObj.h
@@ -0,0 +1,88 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrFBBindableObj_DEFINED
+#define GrFBBindableObj_DEFINED
+
+#include "SkTDArray.h"
+#include "GrFakeRefObj.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// A common base class for render buffers and textures
+class GrFBBindableObj : public GrFakeRefObj {
+
+public:
+    GrFBBindableObj()
+        : GrFakeRefObj() {
+    }
+
+    virtual ~GrFBBindableObj() {
+        GrAlwaysAssert(0 == fColorReferees.count());
+        GrAlwaysAssert(0 == fDepthReferees.count());
+        GrAlwaysAssert(0 == fStencilReferees.count());
+    }
+
+    void setColorBound(GrFakeRefObj *referee) {
+        fColorReferees.append(1, &referee);
+    }
+    void resetColorBound(GrFakeRefObj *referee) {
+        int index = fColorReferees.find(referee);
+        GrAlwaysAssert(0 <= index);
+        fColorReferees.removeShuffle(index);
+    }
+    bool getColorBound(GrFakeRefObj *referee) const {
+        int index = fColorReferees.find(referee);
+        return 0 <= index;
+    }
+    bool getColorBound() const {
+        return 0 != fColorReferees.count();
+    }
+
+    void setDepthBound(GrFakeRefObj *referee) {
+        fDepthReferees.append(1, &referee);
+    }
+    void resetDepthBound(GrFakeRefObj *referee) {
+        int index = fDepthReferees.find(referee);
+        GrAlwaysAssert(0 <= index);
+        fDepthReferees.removeShuffle(index);
+    }
+    bool getDepthBound(GrFakeRefObj *referee) const {
+        int index = fDepthReferees.find(referee);
+        return 0 <= index;
+    }
+    bool getDepthBound() const {
+        return 0 != fDepthReferees.count();
+    }
+
+    void setStencilBound(GrFakeRefObj *referee) {
+        fStencilReferees.append(1, &referee);
+    }
+    void resetStencilBound(GrFakeRefObj *referee) {
+        int index = fStencilReferees.find(referee);
+        GrAlwaysAssert(0 <= index);
+        fStencilReferees.removeShuffle(index);
+    }
+    bool getStencilBound(GrFakeRefObj *referee) const {
+        int index = fStencilReferees.find(referee);
+        return 0 <= index;
+    }
+    bool getStencilBound() const {
+        return 0 != fStencilReferees.count();
+    }
+
+
+protected:
+private:
+    SkTDArray<GrFakeRefObj *> fColorReferees;   // frame buffers that use this as a color buffer (via "glFramebufferRenderbuffer" or "glFramebufferTexture2D")
+    SkTDArray<GrFakeRefObj *> fDepthReferees;   // frame buffers that use this as a depth buffer (via "glFramebufferRenderbuffer" or "glFramebufferTexture2D")
+    SkTDArray<GrFakeRefObj *> fStencilReferees; // frame buffers that use this as a stencil buffer (via "glFramebufferRenderbuffer" or "glFramebufferTexture2D")
+
+    typedef GrFakeRefObj INHERITED;
+};
+
+#endif // GrFBBindableObj_DEFINED
diff --git a/tools/gpu/gl/debug/GrFakeRefObj.h b/tools/gpu/gl/debug/GrFakeRefObj.h
new file mode 100644
index 0000000..3058051
--- /dev/null
+++ b/tools/gpu/gl/debug/GrFakeRefObj.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrFakeRefObj_DEFINED
+#define GrFakeRefObj_DEFINED
+
+#include "SkTypes.h"
+#include "gl/GrGLInterface.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// This object is used to track the OpenGL objects. We don't use real
+// reference counting (i.e., we don't free the objects when their ref count
+// goes to 0) so that we can detect invalid memory accesses. The refs we
+// are tracking in this class are actually OpenGL's references to the objects
+// not "ours"
+// Each object also gets a unique globally identifying ID
+class GrFakeRefObj : SkNoncopyable {
+public:
+    GrFakeRefObj()
+        : fRef(0)
+        , fMarkedForDeletion(false)
+        , fDeleted(false) {
+
+        // source for globally unique IDs - 0 is reserved!
+        static int fNextID = 0;
+
+        fID = ++fNextID;
+    }
+    virtual ~GrFakeRefObj() {};
+
+    void ref() {
+        fRef++;
+    }
+    void unref() {
+        fRef--;
+        GrAlwaysAssert(fRef >= 0);
+
+        // often in OpenGL a given object may still be in use when the
+        // delete call is made. In these cases the object is marked
+        // for deletion and then freed when it is no longer in use
+        if (0 == fRef && fMarkedForDeletion) {
+            this->deleteAction();
+        }
+    }
+    int getRefCount() const             { return fRef; }
+
+    GrGLuint getID() const              { return fID; }
+
+    void setMarkedForDeletion()         { fMarkedForDeletion = true; }
+    bool getMarkedForDeletion() const   { return fMarkedForDeletion; }
+
+    bool getDeleted() const             { return fDeleted; }
+
+    // The deleteAction fires if the object has been marked for deletion but
+    // couldn't be deleted earlier due to refs
+    virtual void deleteAction() {
+        this->setDeleted();
+    }
+
+protected:
+private:
+    int         fRef;               // ref count
+    GrGLuint    fID;                // globally unique ID
+    bool        fMarkedForDeletion;
+    // The deleted flag is only set when OpenGL thinks the object is deleted
+    // It is obviously still allocated w/in this framework
+    bool        fDeleted;
+
+    // setDeleted should only ever appear in the deleteAction method!
+    void setDeleted()                   { fDeleted = true; }
+};
+
+////////////////////////////////////////////////////////////////////////////////
+// Each class derived from GrFakeRefObj should use this macro to add a
+// factory creation entry point. This entry point is used by the GrGLDebug
+// object to instantiate the various objects
+// all globally unique IDs
+#define GR_DEFINE_CREATOR(className) \
+public:                              \
+    static GrFakeRefObj *create##className() { return new className; }
+
+#endif // GrFakeRefObj_DEFINED
diff --git a/tools/gpu/gl/debug/GrFrameBufferObj.cpp b/tools/gpu/gl/debug/GrFrameBufferObj.cpp
new file mode 100644
index 0000000..7dc12ac
--- /dev/null
+++ b/tools/gpu/gl/debug/GrFrameBufferObj.cpp
@@ -0,0 +1,67 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrFrameBufferObj.h"
+#include "GrFBBindableObj.h"
+
+void GrFrameBufferObj::setColor(GrFBBindableObj *buffer) {
+    if (fColorBuffer) {
+        // automatically break the binding of the old buffer
+        GrAlwaysAssert(fColorBuffer->getColorBound(this));
+        fColorBuffer->resetColorBound(this);
+
+        GrAlwaysAssert(!fColorBuffer->getDeleted());
+        fColorBuffer->unref();
+    }
+    fColorBuffer = buffer;
+    if (fColorBuffer) {
+        GrAlwaysAssert(!fColorBuffer->getDeleted());
+        fColorBuffer->ref();
+
+        GrAlwaysAssert(!fColorBuffer->getColorBound(this));
+        fColorBuffer->setColorBound(this);
+    }
+}
+
+void GrFrameBufferObj::setDepth(GrFBBindableObj *buffer) {
+    if (fDepthBuffer) {
+        // automatically break the binding of the old buffer
+        GrAlwaysAssert(fDepthBuffer->getDepthBound(this));
+        fDepthBuffer->resetDepthBound(this);
+
+        GrAlwaysAssert(!fDepthBuffer->getDeleted());
+        fDepthBuffer->unref();
+    }
+    fDepthBuffer = buffer;
+    if (fDepthBuffer) {
+        GrAlwaysAssert(!fDepthBuffer->getDeleted());
+        fDepthBuffer->ref();
+
+        GrAlwaysAssert(!fDepthBuffer->getDepthBound(this));
+        fDepthBuffer->setDepthBound(this);
+    }
+}
+
+void GrFrameBufferObj::setStencil(GrFBBindableObj *buffer) {
+    if (fStencilBuffer) {
+        // automatically break the binding of the old buffer
+        GrAlwaysAssert(fStencilBuffer->getStencilBound(this));
+        fStencilBuffer->resetStencilBound(this);
+
+        //GrAlwaysAssert(!fStencilBuffer->getDeleted());
+        fStencilBuffer->unref();
+    }
+    fStencilBuffer = buffer;
+    if (fStencilBuffer) {
+        GrAlwaysAssert(!fStencilBuffer->getDeleted());
+        fStencilBuffer->ref();
+
+        GrAlwaysAssert(!fStencilBuffer->getStencilBound(this));
+        fStencilBuffer->setStencilBound(this);
+    }
+}
diff --git a/tools/gpu/gl/debug/GrFrameBufferObj.h b/tools/gpu/gl/debug/GrFrameBufferObj.h
new file mode 100644
index 0000000..42a0eff
--- /dev/null
+++ b/tools/gpu/gl/debug/GrFrameBufferObj.h
@@ -0,0 +1,68 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrFrameBufferObj_DEFINED
+#define GrFrameBufferObj_DEFINED
+
+#include "GrFakeRefObj.h"
+class GrFBBindableObj;
+
+////////////////////////////////////////////////////////////////////////////////
+// TODO: when a framebuffer obj is bound the GL_SAMPLES query must return 0
+// TODO: GL_STENCIL_BITS must also be redirected to the framebuffer
+class GrFrameBufferObj : public GrFakeRefObj {
+    GR_DEFINE_CREATOR(GrFrameBufferObj);
+
+public:
+    GrFrameBufferObj()
+        : GrFakeRefObj()
+        , fBound(false)
+        , fColorBuffer(nullptr)
+        , fDepthBuffer(nullptr)
+        , fStencilBuffer(nullptr) {
+    }
+
+    virtual ~GrFrameBufferObj() {
+        fColorBuffer = nullptr;
+        fDepthBuffer = nullptr;
+        fStencilBuffer = nullptr;
+    }
+
+    void setBound()         { fBound = true; }
+    void resetBound()       { fBound = false; }
+    bool getBound() const   { return fBound; }
+
+    void setColor(GrFBBindableObj *buffer);
+    GrFBBindableObj *getColor()       { return fColorBuffer; }
+
+    void setDepth(GrFBBindableObj *buffer);
+    GrFBBindableObj *getDepth()       { return fDepthBuffer; }
+
+    void setStencil(GrFBBindableObj *buffer);
+    GrFBBindableObj *getStencil()     { return fStencilBuffer; }
+
+    void deleteAction() override {
+
+        setColor(nullptr);
+        setDepth(nullptr);
+        setStencil(nullptr);
+
+        this->INHERITED::deleteAction();
+    }
+
+protected:
+private:
+    bool fBound;        // is this frame buffer currently bound via "glBindFramebuffer"?
+    GrFBBindableObj * fColorBuffer;
+    GrFBBindableObj * fDepthBuffer;
+    GrFBBindableObj * fStencilBuffer;
+
+    typedef GrFakeRefObj INHERITED;
+};
+
+#endif // GrFrameBufferObj_DEFINED
diff --git a/tools/gpu/gl/debug/GrProgramObj.cpp b/tools/gpu/gl/debug/GrProgramObj.cpp
new file mode 100644
index 0000000..d6cc36b
--- /dev/null
+++ b/tools/gpu/gl/debug/GrProgramObj.cpp
@@ -0,0 +1,27 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrProgramObj.h"
+#include "GrShaderObj.h"
+
+void GrProgramObj::AttachShader(GrShaderObj *shader) {
+    shader->ref();
+    fShaders.push_back(shader);
+}
+
+void GrProgramObj::deleteAction() {
+
+    // shaders are automatically detached from a deleted program. They will only be
+    // deleted if they were marked for deletion by a prior call to glDeleteShader
+    for (int i = 0; i < fShaders.count(); ++i) {
+        fShaders[i]->unref();
+    }
+    fShaders.reset();
+
+    this->INHERITED::deleteAction();
+}
diff --git a/tools/gpu/gl/debug/GrProgramObj.h b/tools/gpu/gl/debug/GrProgramObj.h
new file mode 100644
index 0000000..a25341a
--- /dev/null
+++ b/tools/gpu/gl/debug/GrProgramObj.h
@@ -0,0 +1,43 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrProgramObj_DEFINED
+#define GrProgramObj_DEFINED
+
+#include "SkTArray.h"
+#include "GrFakeRefObj.h"
+class GrShaderObj;
+
+////////////////////////////////////////////////////////////////////////////////
+class GrProgramObj : public GrFakeRefObj {
+    GR_DEFINE_CREATOR(GrProgramObj);
+
+public:
+    GrProgramObj()
+        : GrFakeRefObj()
+        , fInUse(false) {}
+
+    void AttachShader(GrShaderObj *shader);
+
+    void deleteAction() override;
+
+    // TODO: this flag system won't work w/ multiple contexts!
+    void setInUse()         { fInUse = true; }
+    void resetInUse()       { fInUse = false; }
+    bool getInUse() const   { return fInUse; }
+
+protected:
+
+private:
+    SkTArray<GrShaderObj *> fShaders;
+    bool fInUse;            // has this program been activated by a glUseProgram call?
+
+    typedef GrFakeRefObj INHERITED;
+};
+
+#endif // GrProgramObj_DEFINED
diff --git a/tools/gpu/gl/debug/GrRenderBufferObj.h b/tools/gpu/gl/debug/GrRenderBufferObj.h
new file mode 100644
index 0000000..8231ef5
--- /dev/null
+++ b/tools/gpu/gl/debug/GrRenderBufferObj.h
@@ -0,0 +1,40 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrRenderBufferObj_DEFINED
+#define GrRenderBufferObj_DEFINED
+
+#include "GrFBBindableObj.h"
+
+////////////////////////////////////////////////////////////////////////////////
+class GrRenderBufferObj : public GrFBBindableObj {
+    GR_DEFINE_CREATOR(GrRenderBufferObj);
+
+public:
+    GrRenderBufferObj()
+        : GrFBBindableObj()
+        , fBound(false) {
+    }
+
+    void setBound()         { fBound = true; }
+    void resetBound()       { fBound = false; }
+    bool getBound() const   { return fBound; }
+
+    void deleteAction() override {
+
+        this->INHERITED::deleteAction();
+    }
+
+protected:
+private:
+    bool fBound;           // is this render buffer currently bound via "glBindRenderbuffer"?
+
+    typedef GrFBBindableObj INHERITED;
+};
+
+#endif // GrRenderBufferObj_DEFINED
diff --git a/tools/gpu/gl/debug/GrShaderObj.cpp b/tools/gpu/gl/debug/GrShaderObj.cpp
new file mode 100644
index 0000000..8d3caa1
--- /dev/null
+++ b/tools/gpu/gl/debug/GrShaderObj.cpp
@@ -0,0 +1,14 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrShaderObj.h"
+
+void GrShaderObj::deleteAction() {
+
+    this->INHERITED::deleteAction();
+}
diff --git a/tools/gpu/gl/debug/GrShaderObj.h b/tools/gpu/gl/debug/GrShaderObj.h
new file mode 100644
index 0000000..327bd7f
--- /dev/null
+++ b/tools/gpu/gl/debug/GrShaderObj.h
@@ -0,0 +1,36 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrShaderObj_DEFINED
+#define GrShaderObj_DEFINED
+
+#include "GrFakeRefObj.h"
+#include "gl/GrGLDefines.h"
+
+////////////////////////////////////////////////////////////////////////////////
+class GrShaderObj : public GrFakeRefObj {
+    GR_DEFINE_CREATOR(GrShaderObj);
+
+public:
+    GrShaderObj()
+        : GrFakeRefObj()
+        , fType(GR_GL_VERTEX_SHADER)    {}
+
+    void setType(GrGLenum type)         { fType = type; }
+    GrGLenum getType()                  { return fType; }
+
+    void deleteAction() override;
+
+protected:
+private:
+    GrGLenum fType;  // either GR_GL_VERTEX_SHADER or GR_GL_FRAGMENT_SHADER
+
+    typedef GrFakeRefObj INHERITED;
+};
+
+#endif // GrShaderObj_DEFINED
diff --git a/tools/gpu/gl/debug/GrTextureObj.cpp b/tools/gpu/gl/debug/GrTextureObj.cpp
new file mode 100644
index 0000000..86063fb
--- /dev/null
+++ b/tools/gpu/gl/debug/GrTextureObj.cpp
@@ -0,0 +1,14 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrTextureObj.h"
+
+void GrTextureObj::deleteAction() {
+
+    this->INHERITED::deleteAction();
+}
diff --git a/tools/gpu/gl/debug/GrTextureObj.h b/tools/gpu/gl/debug/GrTextureObj.h
new file mode 100644
index 0000000..fcf851d
--- /dev/null
+++ b/tools/gpu/gl/debug/GrTextureObj.h
@@ -0,0 +1,57 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrTextureObj_DEFINED
+#define GrTextureObj_DEFINED
+
+#include "GrFBBindableObj.h"
+
+class GrTextureUnitObj;
+
+////////////////////////////////////////////////////////////////////////////////
+class GrTextureObj : public GrFBBindableObj {
+    GR_DEFINE_CREATOR(GrTextureObj);
+
+public:
+    GrTextureObj()
+        : GrFBBindableObj() {
+    }
+
+    virtual ~GrTextureObj() {
+        GrAlwaysAssert(0 == fTextureUnitReferees.count());
+    }
+
+    void setBound(GrTextureUnitObj *referee) {
+        fTextureUnitReferees.append(1, &referee);
+    }
+
+    void resetBound(GrTextureUnitObj *referee) {
+        int index = fTextureUnitReferees.find(referee);
+        GrAlwaysAssert(0 <= index);
+        fTextureUnitReferees.removeShuffle(index);
+    }
+    bool getBound(GrTextureUnitObj *referee) const {
+        int index = fTextureUnitReferees.find(referee);
+        return 0 <= index;
+    }
+    bool getBound() const {
+        return 0 != fTextureUnitReferees.count();
+    }
+
+    void deleteAction() override;
+
+protected:
+
+private:
+    // texture units that bind this texture (via "glBindTexture")
+    SkTDArray<GrTextureUnitObj *> fTextureUnitReferees;
+
+    typedef GrFBBindableObj INHERITED;
+};
+
+#endif // GrTextureObj_DEFINED
diff --git a/tools/gpu/gl/debug/GrTextureUnitObj.cpp b/tools/gpu/gl/debug/GrTextureUnitObj.cpp
new file mode 100644
index 0000000..316dcec
--- /dev/null
+++ b/tools/gpu/gl/debug/GrTextureUnitObj.cpp
@@ -0,0 +1,31 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrTextureUnitObj.h"
+#include "GrTextureObj.h"
+
+void GrTextureUnitObj::setTexture(GrTextureObj *texture)  {
+
+    if (fTexture) {
+        GrAlwaysAssert(fTexture->getBound(this));
+        fTexture->resetBound(this);
+
+        GrAlwaysAssert(!fTexture->getDeleted());
+        fTexture->unref();
+    }
+
+    fTexture = texture;
+
+    if (fTexture) {
+        GrAlwaysAssert(!fTexture->getDeleted());
+        fTexture->ref();
+
+        GrAlwaysAssert(!fTexture->getBound(this));
+        fTexture->setBound(this);
+    }
+}
diff --git a/tools/gpu/gl/debug/GrTextureUnitObj.h b/tools/gpu/gl/debug/GrTextureUnitObj.h
new file mode 100644
index 0000000..5c7a039
--- /dev/null
+++ b/tools/gpu/gl/debug/GrTextureUnitObj.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrTextureUnitObj_DEFINED
+#define GrTextureUnitObj_DEFINED
+
+#include "GrFakeRefObj.h"
+class GrTextureObj;
+
+////////////////////////////////////////////////////////////////////////////////
+// Although texture unit objects are allocated & deallocated like the other
+// GL emulation objects they are derived from GrFakeRefObj to provide some
+// uniformity in how the debug interface class manages resources
+class GrTextureUnitObj : public GrFakeRefObj {
+    GR_DEFINE_CREATOR(GrTextureUnitObj);
+
+public:
+    GrTextureUnitObj()
+        : GrFakeRefObj()
+        , fNumber(0)
+        , fTexture(nullptr) {
+    }
+
+    void setNumber(GrGLenum number) {
+        fNumber = number;
+    }
+    GrGLenum getNumber() const { return fNumber; }
+
+    void setTexture(GrTextureObj *texture);
+    GrTextureObj *getTexture()                  { return fTexture; }
+
+protected:
+private:
+    GrGLenum fNumber;
+    GrTextureObj *fTexture;
+
+    typedef GrFakeRefObj INHERITED;
+};
+
+#endif // GrTextureUnitObj_DEFINED
diff --git a/tools/gpu/gl/debug/GrVertexArrayObj.h b/tools/gpu/gl/debug/GrVertexArrayObj.h
new file mode 100644
index 0000000..989c610
--- /dev/null
+++ b/tools/gpu/gl/debug/GrVertexArrayObj.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrVertexArrayObj_DEFINED
+#define GrVertexArrayObj_DEFINED
+
+#include "GrFakeRefObj.h"
+
+class GrVertexArrayObj : public GrFakeRefObj {
+    GR_DEFINE_CREATOR(GrVertexArrayObj);
+
+public:
+    GrVertexArrayObj() : GrFakeRefObj() {}
+
+    typedef GrFakeRefObj INHERITED;
+};
+#endif
diff --git a/tools/gpu/gl/egl/CreatePlatformGLContext_egl.cpp b/tools/gpu/gl/egl/CreatePlatformGLContext_egl.cpp
new file mode 100644
index 0000000..ac2e7ca
--- /dev/null
+++ b/tools/gpu/gl/egl/CreatePlatformGLContext_egl.cpp
@@ -0,0 +1,337 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "gl/GLContext.h"
+
+#include <GLES2/gl2.h>
+
+#define EGL_EGLEXT_PROTOTYPES
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include "gl/GrGLDefines.h"
+#include "gl/GrGLUtil.h"
+
+namespace {
+
+// TODO: Share this class with ANGLE if/when it gets support for EGL_KHR_fence_sync.
+class SkEGLFenceSync : public SkGpuFenceSync {
+public:
+    static SkEGLFenceSync* CreateIfSupported(EGLDisplay);
+
+    SkPlatformGpuFence SK_WARN_UNUSED_RESULT insertFence() const override;
+    bool waitFence(SkPlatformGpuFence fence, bool flush) const override;
+    void deleteFence(SkPlatformGpuFence fence) const override;
+
+private:
+    SkEGLFenceSync(EGLDisplay display) : fDisplay(display) {}
+
+    EGLDisplay                    fDisplay;
+
+    typedef SkGpuFenceSync INHERITED;
+};
+
+class EGLGLContext : public sk_gpu_test::GLContext {
+public:
+    EGLGLContext(GrGLStandard forcedGpuAPI);
+    ~EGLGLContext() override;
+
+    GrEGLImage texture2DToEGLImage(GrGLuint texID) const override;
+    void destroyEGLImage(GrEGLImage) const override;
+    GrGLuint eglImageToExternalTexture(GrEGLImage) const override;
+    sk_gpu_test::GLContext* createNew() const override;
+
+private:
+    void destroyGLContext();
+
+    void onPlatformMakeCurrent() const override;
+    void onPlatformSwapBuffers() const override;
+    GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
+
+    EGLContext fContext;
+    EGLDisplay fDisplay;
+    EGLSurface fSurface;
+};
+
+EGLGLContext::EGLGLContext(GrGLStandard forcedGpuAPI)
+    : fContext(EGL_NO_CONTEXT)
+    , fDisplay(EGL_NO_DISPLAY)
+    , fSurface(EGL_NO_SURFACE) {
+    static const EGLint kEGLContextAttribsForOpenGL[] = {
+        EGL_NONE
+    };
+
+    static const EGLint kEGLContextAttribsForOpenGLES[] = {
+        EGL_CONTEXT_CLIENT_VERSION, 2,
+        EGL_NONE
+    };
+
+    static const struct {
+        const EGLint* fContextAttribs;
+        EGLenum fAPI;
+        EGLint  fRenderableTypeBit;
+        GrGLStandard fStandard;
+    } kAPIs[] = {
+        {   // OpenGL
+            kEGLContextAttribsForOpenGL,
+            EGL_OPENGL_API,
+            EGL_OPENGL_BIT,
+            kGL_GrGLStandard
+        },
+        {   // OpenGL ES. This seems to work for both ES2 and 3 (when available).
+            kEGLContextAttribsForOpenGLES,
+            EGL_OPENGL_ES_API,
+            EGL_OPENGL_ES2_BIT,
+            kGLES_GrGLStandard
+        },
+    };
+
+    size_t apiLimit = SK_ARRAY_COUNT(kAPIs);
+    size_t api = 0;
+    if (forcedGpuAPI == kGL_GrGLStandard) {
+        apiLimit = 1;
+    } else if (forcedGpuAPI == kGLES_GrGLStandard) {
+        api = 1;
+    }
+    SkASSERT(forcedGpuAPI == kNone_GrGLStandard || kAPIs[api].fStandard == forcedGpuAPI);
+
+    SkAutoTUnref<const GrGLInterface> gl;
+
+    for (; nullptr == gl.get() && api < apiLimit; ++api) {
+        fDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+
+        EGLint majorVersion;
+        EGLint minorVersion;
+        eglInitialize(fDisplay, &majorVersion, &minorVersion);
+
+#if 0
+        SkDebugf("VENDOR: %s\n", eglQueryString(fDisplay, EGL_VENDOR));
+        SkDebugf("APIS: %s\n", eglQueryString(fDisplay, EGL_CLIENT_APIS));
+        SkDebugf("VERSION: %s\n", eglQueryString(fDisplay, EGL_VERSION));
+        SkDebugf("EXTENSIONS %s\n", eglQueryString(fDisplay, EGL_EXTENSIONS));
+#endif
+
+        if (!eglBindAPI(kAPIs[api].fAPI)) {
+            continue;
+        }
+
+        EGLint numConfigs = 0;
+        const EGLint configAttribs[] = {
+            EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+            EGL_RENDERABLE_TYPE, kAPIs[api].fRenderableTypeBit,
+            EGL_RED_SIZE, 8,
+            EGL_GREEN_SIZE, 8,
+            EGL_BLUE_SIZE, 8,
+            EGL_ALPHA_SIZE, 8,
+            EGL_NONE
+        };
+
+        EGLConfig surfaceConfig;
+        if (!eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs)) {
+            SkDebugf("eglChooseConfig failed. EGL Error: 0x%08x\n", eglGetError());
+            continue;
+        }
+
+        if (0 == numConfigs) {
+            SkDebugf("No suitable EGL config found.\n");
+            continue;
+        }
+
+        fContext = eglCreateContext(fDisplay, surfaceConfig, nullptr, kAPIs[api].fContextAttribs);
+        if (EGL_NO_CONTEXT == fContext) {
+            SkDebugf("eglCreateContext failed.  EGL Error: 0x%08x\n", eglGetError());
+            continue;
+        }
+
+        static const EGLint kSurfaceAttribs[] = {
+            EGL_WIDTH, 1,
+            EGL_HEIGHT, 1,
+            EGL_NONE
+        };
+
+        fSurface = eglCreatePbufferSurface(fDisplay, surfaceConfig, kSurfaceAttribs);
+        if (EGL_NO_SURFACE == fSurface) {
+            SkDebugf("eglCreatePbufferSurface failed. EGL Error: 0x%08x\n", eglGetError());
+            this->destroyGLContext();
+            continue;
+        }
+
+        if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
+            SkDebugf("eglMakeCurrent failed.  EGL Error: 0x%08x\n", eglGetError());
+            this->destroyGLContext();
+            continue;
+        }
+
+        gl.reset(GrGLCreateNativeInterface());
+        if (nullptr == gl.get()) {
+            SkDebugf("Failed to create gl interface.\n");
+            this->destroyGLContext();
+            continue;
+        }
+
+        if (!gl->validate()) {
+            SkDebugf("Failed to validate gl interface.\n");
+            this->destroyGLContext();
+            continue;
+        }
+
+        this->init(gl.release(), SkEGLFenceSync::CreateIfSupported(fDisplay));
+        break;
+    }
+}
+
+EGLGLContext::~EGLGLContext() {
+    this->teardown();
+    this->destroyGLContext();
+}
+
+void EGLGLContext::destroyGLContext() {
+    if (fDisplay) {
+        eglMakeCurrent(fDisplay, 0, 0, 0);
+
+        if (fContext) {
+            eglDestroyContext(fDisplay, fContext);
+            fContext = EGL_NO_CONTEXT;
+        }
+
+        if (fSurface) {
+            eglDestroySurface(fDisplay, fSurface);
+            fSurface = EGL_NO_SURFACE;
+        }
+
+        //TODO should we close the display?
+        fDisplay = EGL_NO_DISPLAY;
+    }
+}
+
+GrEGLImage EGLGLContext::texture2DToEGLImage(GrGLuint texID) const {
+    if (!this->gl()->hasExtension("EGL_KHR_gl_texture_2D_image")) {
+        return GR_EGL_NO_IMAGE;
+    }
+    GrEGLImage img;
+    GrEGLint attribs[] = { GR_EGL_GL_TEXTURE_LEVEL, 0, GR_EGL_NONE };
+    GrEGLClientBuffer clientBuffer = reinterpret_cast<GrEGLClientBuffer>(texID);
+    GR_GL_CALL_RET(this->gl(), img,
+                   EGLCreateImage(fDisplay, fContext, GR_EGL_GL_TEXTURE_2D, clientBuffer, attribs));
+    return img;
+}
+
+void EGLGLContext::destroyEGLImage(GrEGLImage image) const {
+    GR_GL_CALL(this->gl(), EGLDestroyImage(fDisplay, image));
+}
+
+GrGLuint EGLGLContext::eglImageToExternalTexture(GrEGLImage image) const {
+    GrGLClearErr(this->gl());
+    if (!this->gl()->hasExtension("GL_OES_EGL_image_external")) {
+        return 0;
+    }
+    typedef GrGLvoid (*EGLImageTargetTexture2DProc)(GrGLenum, GrGLeglImage);
+
+    EGLImageTargetTexture2DProc glEGLImageTargetTexture2D =
+        (EGLImageTargetTexture2DProc) eglGetProcAddress("glEGLImageTargetTexture2DOES");
+    if (!glEGLImageTargetTexture2D) {
+        return 0;
+    }
+    GrGLuint texID;
+    glGenTextures(1, &texID);
+    if (!texID) {
+        return 0;
+    }
+    glBindTexture(GR_GL_TEXTURE_EXTERNAL, texID);
+    if (glGetError() != GR_GL_NO_ERROR) {
+        glDeleteTextures(1, &texID);
+        return 0;
+    }
+    glEGLImageTargetTexture2D(GR_GL_TEXTURE_EXTERNAL, image);
+    if (glGetError() != GR_GL_NO_ERROR) {
+        glDeleteTextures(1, &texID);
+        return 0;
+    }
+    return texID;
+}
+
+sk_gpu_test::GLContext* EGLGLContext::createNew() const {
+    sk_gpu_test::GLContext* ctx = new EGLGLContext(this->gl()->fStandard);
+    if (ctx) {
+        ctx->makeCurrent();
+    }
+    return ctx;
+}
+
+void EGLGLContext::onPlatformMakeCurrent() const {
+    if (!eglMakeCurrent(fDisplay, fSurface, fSurface, fContext)) {
+        SkDebugf("Could not set the context.\n");
+    }
+}
+
+void EGLGLContext::onPlatformSwapBuffers() const {
+    if (!eglSwapBuffers(fDisplay, fSurface)) {
+        SkDebugf("Could not complete eglSwapBuffers.\n");
+    }
+}
+
+GrGLFuncPtr EGLGLContext::onPlatformGetProcAddress(const char* procName) const {
+    return eglGetProcAddress(procName);
+}
+
+static bool supports_egl_extension(EGLDisplay display, const char* extension) {
+    size_t extensionLength = strlen(extension);
+    const char* extensionsStr = eglQueryString(display, EGL_EXTENSIONS);
+    while (const char* match = strstr(extensionsStr, extension)) {
+        // Ensure the string we found is its own extension, not a substring of a larger extension
+        // (e.g. GL_ARB_occlusion_query / GL_ARB_occlusion_query2).
+        if ((match == extensionsStr || match[-1] == ' ') &&
+            (match[extensionLength] == ' ' || match[extensionLength] == '\0')) {
+            return true;
+        }
+        extensionsStr = match + extensionLength;
+    }
+    return false;
+}
+
+SkEGLFenceSync* SkEGLFenceSync::CreateIfSupported(EGLDisplay display) {
+    if (!display || !supports_egl_extension(display, "EGL_KHR_fence_sync")) {
+        return nullptr;
+    }
+    return new SkEGLFenceSync(display);
+}
+
+SkPlatformGpuFence SkEGLFenceSync::insertFence() const {
+    return eglCreateSyncKHR(fDisplay, EGL_SYNC_FENCE_KHR, nullptr);
+}
+
+bool SkEGLFenceSync::waitFence(SkPlatformGpuFence platformFence, bool flush) const {
+    EGLSyncKHR eglsync = static_cast<EGLSyncKHR>(platformFence);
+    return EGL_CONDITION_SATISFIED_KHR ==
+            eglClientWaitSyncKHR(fDisplay,
+                                 eglsync,
+                                 flush ? EGL_SYNC_FLUSH_COMMANDS_BIT_KHR : 0,
+                                 EGL_FOREVER_KHR);
+}
+
+void SkEGLFenceSync::deleteFence(SkPlatformGpuFence platformFence) const {
+    EGLSyncKHR eglsync = static_cast<EGLSyncKHR>(platformFence);
+    eglDestroySyncKHR(fDisplay, eglsync);
+}
+
+}  // anonymous namespace
+
+namespace sk_gpu_test {
+GLContext *CreatePlatformGLContext(GrGLStandard forcedGpuAPI, GLContext *shareContext) {
+    SkASSERT(!shareContext);
+    if (shareContext) {
+        return nullptr;
+    }
+    EGLGLContext *ctx = new EGLGLContext(forcedGpuAPI);
+    if (!ctx->isValid()) {
+        delete ctx;
+        return nullptr;
+    }
+    return ctx;
+}
+}  // namespace sk_gpu_test
+
diff --git a/tools/gpu/gl/glx/CreatePlatformGLContext_glx.cpp b/tools/gpu/gl/glx/CreatePlatformGLContext_glx.cpp
new file mode 100644
index 0000000..b2168e3
--- /dev/null
+++ b/tools/gpu/gl/glx/CreatePlatformGLContext_glx.cpp
@@ -0,0 +1,346 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "gl/GLContext.h"
+
+#include <X11/Xlib.h>
+#include <GL/glx.h>
+#include <GL/glu.h>
+
+namespace {
+
+/* Note: Skia requires glx 1.3 or newer */
+
+/* This struct is taken from a mesa demo.  Please update as required */
+static const struct { int major, minor; } gl_versions[] = {
+   {1, 0},
+   {1, 1},
+   {1, 2},
+   {1, 3},
+   {1, 4},
+   {1, 5},
+   {2, 0},
+   {2, 1},
+   {3, 0},
+   {3, 1},
+   {3, 2},
+   {3, 3},
+   {4, 0},
+   {4, 1},
+   {4, 2},
+   {4, 3},
+   {4, 4},
+   {0, 0} /* end of list */
+};
+#define NUM_GL_VERSIONS SK_ARRAY_COUNT(gl_versions)
+
+static bool ctxErrorOccurred = false;
+static int ctxErrorHandler(Display *dpy, XErrorEvent *ev) {
+    ctxErrorOccurred = true;
+    return 0;
+}
+
+class GLXGLContext : public sk_gpu_test::GLContext {
+public:
+    GLXGLContext(GrGLStandard forcedGpuAPI, GLXGLContext* shareList);
+    ~GLXGLContext() override;
+
+private:
+    void destroyGLContext();
+
+    void onPlatformMakeCurrent() const override;
+    void onPlatformSwapBuffers() const override;
+    GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
+
+    GLXContext fContext;
+    Display* fDisplay;
+    Pixmap fPixmap;
+    GLXPixmap fGlxPixmap;
+};
+
+GLXGLContext::GLXGLContext(GrGLStandard forcedGpuAPI, GLXGLContext* shareContext)
+    : fContext(nullptr)
+    , fDisplay(nullptr)
+    , fPixmap(0)
+    , fGlxPixmap(0) {
+    fDisplay = XOpenDisplay(0);
+
+    GLXContext glxShareContext = shareContext ? shareContext->fContext : nullptr;
+
+    if (!fDisplay) {
+        SkDebugf("Failed to open X display.\n");
+        this->destroyGLContext();
+        return;
+    }
+
+    // Get a matching FB config
+    static int visual_attribs[] = {
+        GLX_X_RENDERABLE    , True,
+        GLX_DRAWABLE_TYPE   , GLX_PIXMAP_BIT,
+        None
+    };
+
+    int glx_major, glx_minor;
+
+    // FBConfigs were added in GLX version 1.3.
+    if (!glXQueryVersion(fDisplay, &glx_major, &glx_minor) ||
+            ((glx_major == 1) && (glx_minor < 3)) || (glx_major < 1)) {
+        SkDebugf("GLX version 1.3 or higher required.\n");
+        this->destroyGLContext();
+        return;
+    }
+
+    //SkDebugf("Getting matching framebuffer configs.\n");
+    int fbcount;
+    GLXFBConfig *fbc = glXChooseFBConfig(fDisplay, DefaultScreen(fDisplay),
+                                          visual_attribs, &fbcount);
+    if (!fbc) {
+        SkDebugf("Failed to retrieve a framebuffer config.\n");
+        this->destroyGLContext();
+        return;
+    }
+    //SkDebugf("Found %d matching FB configs.\n", fbcount);
+
+    // Pick the FB config/visual with the most samples per pixel
+    //SkDebugf("Getting XVisualInfos.\n");
+    int best_fbc = -1, best_num_samp = -1;
+
+    int i;
+    for (i = 0; i < fbcount; ++i) {
+        XVisualInfo *vi = glXGetVisualFromFBConfig(fDisplay, fbc[i]);
+        if (vi) {
+            int samp_buf, samples;
+            glXGetFBConfigAttrib(fDisplay, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf);
+            glXGetFBConfigAttrib(fDisplay, fbc[i], GLX_SAMPLES, &samples);
+
+            //SkDebugf("  Matching fbconfig %d, visual ID 0x%2x: SAMPLE_BUFFERS = %d,"
+            //       " SAMPLES = %d\n",
+            //        i, (unsigned int)vi->visualid, samp_buf, samples);
+
+            if (best_fbc < 0 || (samp_buf && samples > best_num_samp))
+                best_fbc = i, best_num_samp = samples;
+        }
+        XFree(vi);
+    }
+
+    GLXFBConfig bestFbc = fbc[best_fbc];
+
+    // Be sure to free the FBConfig list allocated by glXChooseFBConfig()
+    XFree(fbc);
+
+    // Get a visual
+    XVisualInfo *vi = glXGetVisualFromFBConfig(fDisplay, bestFbc);
+    //SkDebugf("Chosen visual ID = 0x%x\n", (unsigned int)vi->visualid);
+
+    fPixmap = XCreatePixmap(fDisplay, RootWindow(fDisplay, vi->screen), 10, 10, vi->depth);
+
+    if (!fPixmap) {
+        SkDebugf("Failed to create pixmap.\n");
+        this->destroyGLContext();
+        return;
+    }
+
+    fGlxPixmap = glXCreateGLXPixmap(fDisplay, vi, fPixmap);
+
+    // Done with the visual info data
+    XFree(vi);
+
+    // Create the context
+
+    // Install an X error handler so the application won't exit if GL 3.0
+    // context allocation fails.
+    //
+    // Note this error handler is global.
+    // All display connections in all threads of a process use the same
+    // error handler, so be sure to guard against other threads issuing
+    // X commands while this code is running.
+    ctxErrorOccurred = false;
+    int (*oldHandler)(Display*, XErrorEvent*) =
+        XSetErrorHandler(&ctxErrorHandler);
+
+    // Get the default screen's GLX extension list
+    const char *glxExts = glXQueryExtensionsString(
+        fDisplay, DefaultScreen(fDisplay)
+    );
+
+
+    // Check for the GLX_ARB_create_context extension string and the function.
+    // If either is not present, use GLX 1.3 context creation method.
+    if (!gluCheckExtension(reinterpret_cast<const GLubyte*>("GLX_ARB_create_context"),
+                           reinterpret_cast<const GLubyte*>(glxExts))) {
+        if (kGLES_GrGLStandard != forcedGpuAPI) {
+            fContext = glXCreateNewContext(fDisplay, bestFbc, GLX_RGBA_TYPE, 0, True);
+        }
+    } else {
+        //SkDebugf("Creating context.\n");
+        PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB =
+            (PFNGLXCREATECONTEXTATTRIBSARBPROC) glXGetProcAddressARB((GrGLubyte*)"glXCreateContextAttribsARB");
+
+        if (kGLES_GrGLStandard == forcedGpuAPI) {
+            if (gluCheckExtension(
+                    reinterpret_cast<const GLubyte*>("GLX_EXT_create_context_es2_profile"),
+                    reinterpret_cast<const GLubyte*>(glxExts))) {
+                static const int context_attribs_gles[] = {
+                    GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
+                    GLX_CONTEXT_MINOR_VERSION_ARB, 0,
+                    GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_ES2_PROFILE_BIT_EXT,
+                    None
+                };
+                fContext = glXCreateContextAttribsARB(fDisplay, bestFbc, glxShareContext, True,
+                                                      context_attribs_gles);
+            }
+        } else {
+            // Well, unfortunately GLX will not just give us the highest context so instead we have
+            // to do this nastiness
+            for (i = NUM_GL_VERSIONS - 2; i > 0 ; i--) {
+                /* don't bother below GL 3.0 */
+                if (gl_versions[i].major == 3 && gl_versions[i].minor == 0) {
+                    break;
+                }
+                // On Nvidia GPUs, to use Nv Path rendering we need a compatibility profile for the
+                // time being.
+                // TODO when Nvidia implements NVPR on Core profiles, we should start requesting
+                // core here
+                static const int context_attribs_gl[] = {
+                      GLX_CONTEXT_MAJOR_VERSION_ARB, gl_versions[i].major,
+                      GLX_CONTEXT_MINOR_VERSION_ARB, gl_versions[i].minor,
+                      GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
+                      None
+                };
+                fContext =
+                        glXCreateContextAttribsARB(fDisplay, bestFbc, glxShareContext, True,
+                                                   context_attribs_gl);
+
+                // Sync to ensure any errors generated are processed.
+                XSync(fDisplay, False);
+
+                if (!ctxErrorOccurred && fContext) {
+                    break;
+                }
+                // try again
+                ctxErrorOccurred = false;
+            }
+
+            // Couldn't create GL 3.0 context.
+            // Fall back to old-style 2.x context.
+            // When a context version below 3.0 is requested,
+            // implementations will return the newest context version
+            // compatible with OpenGL versions less than version 3.0.
+            if (ctxErrorOccurred || !fContext) {
+                static const int context_attribs_gl_fallback[] = {
+                    GLX_CONTEXT_MAJOR_VERSION_ARB, 1,
+                    GLX_CONTEXT_MINOR_VERSION_ARB, 0,
+                    None
+                };
+
+                ctxErrorOccurred = false;
+
+                fContext = glXCreateContextAttribsARB(fDisplay, bestFbc, glxShareContext, True,
+                                                      context_attribs_gl_fallback);
+            }
+        }
+    }
+
+    // Sync to ensure any errors generated are processed.
+    XSync(fDisplay, False);
+
+    // Restore the original error handler
+    XSetErrorHandler(oldHandler);
+
+    if (ctxErrorOccurred || !fContext) {
+        SkDebugf("Failed to create an OpenGL context.\n");
+        this->destroyGLContext();
+        return;
+    }
+
+    // Verify that context is a direct context
+    if (!glXIsDirect(fDisplay, fContext)) {
+        //SkDebugf("Indirect GLX rendering context obtained.\n");
+    } else {
+        //SkDebugf("Direct GLX rendering context obtained.\n");
+    }
+
+    //SkDebugf("Making context current.\n");
+    if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) {
+      SkDebugf("Could not set the context.\n");
+        this->destroyGLContext();
+        return;
+    }
+
+    SkAutoTUnref<const GrGLInterface> gl(GrGLCreateNativeInterface());
+    if (nullptr == gl.get()) {
+        SkDebugf("Failed to create gl interface");
+        this->destroyGLContext();
+        return;
+    }
+
+    if (!gl->validate()) {
+        SkDebugf("Failed to validate gl interface");
+        this->destroyGLContext();
+        return;
+    }
+
+    this->init(gl.release());
+}
+
+
+GLXGLContext::~GLXGLContext() {
+    this->teardown();
+    this->destroyGLContext();
+}
+
+void GLXGLContext::destroyGLContext() {
+    if (fDisplay) {
+        glXMakeCurrent(fDisplay, 0, 0);
+
+        if (fContext) {
+            glXDestroyContext(fDisplay, fContext);
+            fContext = nullptr;
+        }
+
+        if (fGlxPixmap) {
+            glXDestroyGLXPixmap(fDisplay, fGlxPixmap);
+            fGlxPixmap = 0;
+        }
+
+        if (fPixmap) {
+            XFreePixmap(fDisplay, fPixmap);
+            fPixmap = 0;
+        }
+
+        XCloseDisplay(fDisplay);
+        fDisplay = nullptr;
+    }
+}
+
+void GLXGLContext::onPlatformMakeCurrent() const {
+    if (!glXMakeCurrent(fDisplay, fGlxPixmap, fContext)) {
+        SkDebugf("Could not set the context.\n");
+    }
+}
+
+void GLXGLContext::onPlatformSwapBuffers() const {
+    glXSwapBuffers(fDisplay, fGlxPixmap);
+}
+
+GrGLFuncPtr GLXGLContext::onPlatformGetProcAddress(const char* procName) const {
+    return glXGetProcAddress(reinterpret_cast<const GLubyte*>(procName));
+}
+
+}  // anonymous namespace
+
+namespace sk_gpu_test {
+GLContext *CreatePlatformGLContext(GrGLStandard forcedGpuAPI, GLContext *shareContext) {
+    GLXGLContext *glxShareContext = reinterpret_cast<GLXGLContext *>(shareContext);
+    GLXGLContext *ctx = new GLXGLContext(forcedGpuAPI, glxShareContext);
+    if (!ctx->isValid()) {
+        delete ctx;
+        return nullptr;
+    }
+    return ctx;
+}
+}  // namespace sk_gpu_test
diff --git a/tools/gpu/gl/iOS/CreatePlatformGLContext_iOS.mm b/tools/gpu/gl/iOS/CreatePlatformGLContext_iOS.mm
new file mode 100644
index 0000000..d6507f2
--- /dev/null
+++ b/tools/gpu/gl/iOS/CreatePlatformGLContext_iOS.mm
@@ -0,0 +1,108 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GLContext.h"
+#import <OpenGLES/EAGL.h>
+#include <dlfcn.h>
+
+#define EAGLCTX ((EAGLContext*)(fEAGLContext))
+
+namespace {
+
+class IOSGLContext : public sk_gpu_test::GLContext {
+public:
+    IOSGLContext();
+    ~IOSGLContext() override;
+
+private:
+    void destroyGLContext();
+
+    void onPlatformMakeCurrent() const override;
+    void onPlatformSwapBuffers() const override;
+    GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
+
+    void* fEAGLContext;
+    void* fGLLibrary;
+};
+
+IOSGLContext::IOSGLContext()
+    : fEAGLContext(NULL)
+    , fGLLibrary(RTLD_DEFAULT) {
+
+    fEAGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
+    [EAGLContext setCurrentContext:EAGLCTX];
+
+    SkAutoTUnref<const GrGLInterface> gl(GrGLCreateNativeInterface());
+    if (NULL == gl.get()) {
+        SkDebugf("Failed to create gl interface");
+        this->destroyGLContext();
+        return;
+    }
+    if (!gl->validate()) {
+        SkDebugf("Failed to validate gl interface");
+        this->destroyGLContext();
+        return;
+    }
+
+    fGLLibrary = dlopen(
+        "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib",
+        RTLD_LAZY);
+
+    this->init(gl.release());
+}
+
+IOSGLContext::~IOSGLContext() {
+    this->teardown();
+    this->destroyGLContext();
+}
+
+void IOSGLContext::destroyGLContext() {
+    if (fEAGLContext) {
+        if ([EAGLContext currentContext] == EAGLCTX) {
+            [EAGLContext setCurrentContext:nil];
+        }
+        [EAGLCTX release];
+        fEAGLContext = NULL;
+    }
+    if (RTLD_DEFAULT != fGLLibrary) {
+        dlclose(fGLLibrary);
+    }
+}
+
+
+void IOSGLContext::onPlatformMakeCurrent() const {
+    if (![EAGLContext setCurrentContext:EAGLCTX]) {
+        SkDebugf("Could not set the context.\n");
+    }
+}
+
+void IOSGLContext::onPlatformSwapBuffers() const { }
+
+GrGLFuncPtr IOSGLContext::onPlatformGetProcAddress(const char* procName) const {
+    return reinterpret_cast<GrGLFuncPtr>(dlsym(fGLLibrary, procName));
+}
+
+}  // anonymous namespace
+
+namespace sk_gpu_test {
+GLContext *CreatePlatformGLContext(GrGLStandard forcedGpuAPI, GLContext *shareContext) {
+    SkASSERT(!shareContext);
+    if (shareContext) {
+        return NULL;
+    }
+    if (kGL_GrGLStandard == forcedGpuAPI) {
+        return NULL;
+    }
+    IOSGLContext *ctx = new IOSGLContext;
+    if (!ctx->isValid()) {
+        delete ctx;
+        return NULL;
+    }
+    return ctx;
+}
+}
diff --git a/tools/gpu/gl/mac/CreatePlatformGLContext_mac.cpp b/tools/gpu/gl/mac/CreatePlatformGLContext_mac.cpp
new file mode 100644
index 0000000..7da99d7
--- /dev/null
+++ b/tools/gpu/gl/mac/CreatePlatformGLContext_mac.cpp
@@ -0,0 +1,128 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkTypes.h"
+
+#include "gl/GLContext.h"
+#include "AvailabilityMacros.h"
+
+#include <OpenGL/OpenGL.h>
+#include <dlfcn.h>
+
+namespace {
+class MacGLContext : public sk_gpu_test::GLContext {
+public:
+    MacGLContext();
+    ~MacGLContext() override;
+
+private:
+    void destroyGLContext();
+
+    void onPlatformMakeCurrent() const override;
+    void onPlatformSwapBuffers() const override;
+    GrGLFuncPtr onPlatformGetProcAddress(const char*) const override;
+
+    CGLContextObj fContext;
+    void* fGLLibrary;
+};
+
+MacGLContext::MacGLContext()
+    : fContext(nullptr)
+    , fGLLibrary(RTLD_DEFAULT) {
+    CGLPixelFormatAttribute attributes[] = {
+#if MAC_OS_X_VERSION_10_7
+        kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute) kCGLOGLPVersion_3_2_Core,
+#endif
+        kCGLPFADoubleBuffer,
+        (CGLPixelFormatAttribute)0
+    };
+    CGLPixelFormatObj pixFormat;
+    GLint npix;
+
+    CGLChoosePixelFormat(attributes, &pixFormat, &npix);
+
+    if (nullptr == pixFormat) {
+        SkDebugf("CGLChoosePixelFormat failed.");
+        return;
+    }
+
+    CGLCreateContext(pixFormat, nullptr, &fContext);
+    CGLReleasePixelFormat(pixFormat);
+
+    if (nullptr == fContext) {
+        SkDebugf("CGLCreateContext failed.");
+        return;
+    }
+
+    CGLSetCurrentContext(fContext);
+
+    SkAutoTUnref<const GrGLInterface> gl(GrGLCreateNativeInterface());
+    if (nullptr == gl.get()) {
+        SkDebugf("Context could not create GL interface.\n");
+        this->destroyGLContext();
+        return;
+    }
+    if (!gl->validate()) {
+        SkDebugf("Context could not validate GL interface.\n");
+        this->destroyGLContext();
+        return;
+    }
+
+    fGLLibrary = dlopen(
+        "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib",
+        RTLD_LAZY);
+
+    this->init(gl.release());
+}
+
+MacGLContext::~MacGLContext() {
+    this->teardown();
+    this->destroyGLContext();
+}
+
+void MacGLContext::destroyGLContext() {
+    if (fContext) {
+        CGLReleaseContext(fContext);
+        fContext = nullptr;
+    }
+    if (RTLD_DEFAULT != fGLLibrary) {
+        dlclose(fGLLibrary);
+    }
+}
+
+void MacGLContext::onPlatformMakeCurrent() const {
+    CGLSetCurrentContext(fContext);
+}
+
+void MacGLContext::onPlatformSwapBuffers() const {
+    CGLFlushDrawable(fContext);
+}
+
+GrGLFuncPtr MacGLContext::onPlatformGetProcAddress(const char* procName) const {
+    return reinterpret_cast<GrGLFuncPtr>(dlsym(fGLLibrary, procName));
+}
+
+}  // anonymous namespace
+
+namespace sk_gpu_test {
+GLContext* CreatePlatformGLContext(GrGLStandard forcedGpuAPI, GLContext* shareContext) {
+    SkASSERT(!shareContext);
+    if (shareContext) {
+        return nullptr;
+    }
+
+    if (kGLES_GrGLStandard == forcedGpuAPI) {
+        return nullptr;
+    }
+    MacGLContext* ctx = new MacGLContext;
+    if (!ctx->isValid()) {
+        delete ctx;
+        return nullptr;
+    }
+    return ctx;
+}
+}  // namespace sk_gpu_test
diff --git a/tools/gpu/gl/mesa/GLContext_mesa.cpp b/tools/gpu/gl/mesa/GLContext_mesa.cpp
new file mode 100644
index 0000000..e6cc7c7
--- /dev/null
+++ b/tools/gpu/gl/mesa/GLContext_mesa.cpp
@@ -0,0 +1,151 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <GL/osmesa.h>
+
+#include "gl/mesa/GLContext_mesa.h"
+#include "gl/GrGLDefines.h"
+
+#include "gl/GrGLAssembleInterface.h"
+#include "gl/GrGLUtil.h"
+#include "osmesa_wrapper.h"
+
+namespace {
+
+static GrGLFuncPtr osmesa_get(void* ctx, const char name[]) {
+    SkASSERT(nullptr == ctx);
+    SkASSERT(OSMesaGetCurrentContext());
+    return OSMesaGetProcAddress(name);
+}
+
+static const GrGLInterface* create_mesa_interface() {
+    if (nullptr == OSMesaGetCurrentContext()) {
+        return nullptr;
+    }
+    return GrGLAssembleInterface(nullptr, osmesa_get);
+}
+
+static const GrGLint gBOGUS_SIZE = 16;
+
+class MesaGLContext : public sk_gpu_test::GLContext {
+private:
+    typedef intptr_t Context;
+
+public:
+    MesaGLContext();
+    ~MesaGLContext() override;
+
+private:
+    void destroyGLContext();
+
+    void onPlatformMakeCurrent() const override;
+
+    void onPlatformSwapBuffers() const override;
+
+    GrGLFuncPtr onPlatformGetProcAddress(const char *) const override;
+
+    Context fContext;
+    GrGLubyte *fImage;
+};
+
+MesaGLContext::MesaGLContext() : fContext(static_cast<Context>(0)), fImage(nullptr) {
+    GR_STATIC_ASSERT(sizeof(Context) == sizeof(OSMesaContext));
+
+    /* Create an RGBA-mode context */
+#if OSMESA_MAJOR_VERSION * 100 + OSMESA_MINOR_VERSION >= 305
+    /* specify Z, stencil, accum sizes */
+    fContext = (Context)OSMesaCreateContextExt(OSMESA_BGRA, 0, 0, 0, nullptr);
+#else
+    fContext = (Context) OSMesaCreateContext(OSMESA_BGRA, nullptr);
+#endif
+    if (!fContext) {
+        SkDebugf("OSMesaCreateContext failed!\n");
+        this->destroyGLContext();
+        return;
+    }
+    // Allocate the image buffer
+    fImage = (GrGLubyte *) sk_malloc_throw(gBOGUS_SIZE * gBOGUS_SIZE *
+                                           4 * sizeof(GrGLubyte));
+    if (!fImage) {
+        SkDebugf("Alloc image buffer failed!\n");
+        this->destroyGLContext();
+        return;
+    }
+
+    // Bind the buffer to the context and make it current
+    if (!OSMesaMakeCurrent((OSMesaContext) fContext,
+                           fImage,
+                           GR_GL_UNSIGNED_BYTE,
+                           gBOGUS_SIZE,
+                           gBOGUS_SIZE)) {
+        SkDebugf("OSMesaMakeCurrent failed!\n");
+        this->destroyGLContext();
+        return;
+    }
+
+    SkAutoTUnref<const GrGLInterface> gl(create_mesa_interface());
+    if (nullptr == gl.get()) {
+        SkDebugf("Could not create GL interface!\n");
+        this->destroyGLContext();
+        return;
+    }
+
+    if (!gl->validate()) {
+        SkDebugf("Could not validate GL interface!\n");
+        this->destroyGLContext();
+        return;
+    }
+
+    this->init(gl.release());
+}
+
+MesaGLContext::~MesaGLContext() {
+    this->teardown();
+    this->destroyGLContext();
+}
+
+void MesaGLContext::destroyGLContext() {
+    if (fImage) {
+        sk_free(fImage);
+        fImage = nullptr;
+    }
+
+    if (fContext) {
+        OSMesaDestroyContext((OSMesaContext) fContext);
+        fContext = static_cast<Context>(0);
+    }
+}
+
+
+void MesaGLContext::onPlatformMakeCurrent() const {
+    if (fContext) {
+        if (!OSMesaMakeCurrent((OSMesaContext) fContext, fImage,
+                               GR_GL_UNSIGNED_BYTE, gBOGUS_SIZE, gBOGUS_SIZE)) {
+            SkDebugf("Could not make MESA context current.");
+        }
+    }
+}
+
+void MesaGLContext::onPlatformSwapBuffers() const { }
+
+GrGLFuncPtr MesaGLContext::onPlatformGetProcAddress(const char *procName) const {
+    return OSMesaGetProcAddress(procName);
+}
+}  // anonymous namespace
+
+
+namespace sk_gpu_test {
+GLContext *CreateMesaGLContext() {
+    MesaGLContext *ctx = new MesaGLContext;
+    if (!ctx->isValid()) {
+        delete ctx;
+        return nullptr;
+    }
+    return ctx;
+}
+}  // sk_gpu_test
diff --git a/tools/gpu/gl/mesa/GLContext_mesa.h b/tools/gpu/gl/mesa/GLContext_mesa.h
new file mode 100644
index 0000000..0d6ee4d
--- /dev/null
+++ b/tools/gpu/gl/mesa/GLContext_mesa.h
@@ -0,0 +1,17 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef GLContext_mesa_DEFINED
+#define GLContext_mesa_DEFINED
+
+#include "gl/GLContext.h"
+
+namespace sk_gpu_test {
+GLContext* CreateMesaGLContext();
+}  // namespace sk_gpu_test
+
+#endif
diff --git a/tools/gpu/gl/mesa/osmesa_wrapper.h b/tools/gpu/gl/mesa/osmesa_wrapper.h
new file mode 100644
index 0000000..70de993
--- /dev/null
+++ b/tools/gpu/gl/mesa/osmesa_wrapper.h
@@ -0,0 +1,16 @@
+
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+// Older versions of XQuartz have a bug where a header included by osmesa.h
+// defines GL_GLEXT_PROTOTYPES. This will cause a redefinition warning if
+// the file that includes osmesa.h already defined it. XCode 3 uses a version
+// of gcc (4.2.1) that does not support the diagnostic pragma to disable a
+// warning (added in 4.2.4). So we use the system_header pragma to shut GCC
+// up about warnings in osmesa.h
+#pragma GCC system_header
+#include <GL/osmesa.h>
diff --git a/tools/gpu/gl/null/NullGLContext.cpp b/tools/gpu/gl/null/NullGLContext.cpp
new file mode 100644
index 0000000..4781c90
--- /dev/null
+++ b/tools/gpu/gl/null/NullGLContext.cpp
@@ -0,0 +1,630 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "NullGLContext.h"
+#include "gl/GrGLTestInterface.h"
+#include "gl/GrGLDefines.h"
+#include "gl/GrGLInterface.h"
+#include "gl/GrGLTypes.h"
+#include "SkMutex.h"
+#include "SkTDArray.h"
+
+namespace {
+
+class BufferObj {
+public:
+    BufferObj(GrGLuint id) : fID(id), fDataPtr(nullptr), fSize(0), fMapped(false) {}
+    ~BufferObj() { delete[] fDataPtr; }
+
+    void allocate(GrGLsizeiptr size, const GrGLchar* dataPtr) {
+        if (fDataPtr) {
+            SkASSERT(0 != fSize);
+            delete[] fDataPtr;
+        }
+
+        fSize = size;
+        fDataPtr = new char[size];
+    }
+
+    GrGLuint id() const          { return fID; }
+    GrGLchar* dataPtr()          { return fDataPtr; }
+    GrGLsizeiptr size() const    { return fSize; }
+
+    void setMapped(bool mapped)  { fMapped = mapped; }
+    bool mapped() const          { return fMapped; }
+
+private:
+    GrGLuint     fID;
+    GrGLchar*    fDataPtr;
+    GrGLsizeiptr fSize;         // size in bytes
+    bool         fMapped;
+};
+
+// This class maintains a sparsely populated array of buffer pointers.
+class BufferManager {
+public:
+    BufferManager() : fFreeListHead(kFreeListEnd) {}
+
+    ~BufferManager() {
+        // nullptr out the entries that are really free list links rather than ptrs before deleting.
+        intptr_t curr = fFreeListHead;
+        while (kFreeListEnd != curr) {
+            intptr_t next = reinterpret_cast<intptr_t>(fBuffers[SkToS32(curr)]);
+            fBuffers[SkToS32(curr)] = nullptr;
+            curr = next;
+        }
+
+        fBuffers.deleteAll();
+    }
+
+    BufferObj* lookUp(GrGLuint id) {
+        BufferObj* buffer = fBuffers[id];
+        SkASSERT(buffer && buffer->id() == id);
+        return buffer;
+    }
+
+    BufferObj* create() {
+        GrGLuint id;
+        BufferObj* buffer;
+
+        if (kFreeListEnd == fFreeListHead) {
+            // no free slots - create a new one
+            id = fBuffers.count();
+            buffer = new BufferObj(id);
+            *fBuffers.append() = buffer;
+        } else {
+            // grab the head of the free list and advance the head to the next free slot.
+            id = static_cast<GrGLuint>(fFreeListHead);
+            fFreeListHead = reinterpret_cast<intptr_t>(fBuffers[id]);
+
+            buffer = new BufferObj(id);
+            fBuffers[id] = buffer;
+        }
+
+        return buffer;
+    }
+
+    void free(BufferObj* buffer) {
+        SkASSERT(fBuffers.count() > 0);
+
+        GrGLuint id = buffer->id();
+        delete buffer;
+
+        fBuffers[id] = reinterpret_cast<BufferObj*>(fFreeListHead);
+        fFreeListHead = id;
+    }
+
+private:
+    static const intptr_t kFreeListEnd = -1;
+    // Index of the first entry of fBuffers in the free list. Free slots in fBuffers are indices to
+    // the next free slot. The last free slot has a value of kFreeListEnd.
+    intptr_t                fFreeListHead;
+    SkTDArray<BufferObj*>   fBuffers;
+};
+
+/** Null interface implementation */
+class NullInterface : public GrGLTestInterface {
+public:
+    NullInterface()
+        : fCurrArrayBuffer(0)
+        , fCurrElementArrayBuffer(0)
+        , fCurrPixelPackBuffer(0)
+        , fCurrPixelUnpackBuffer(0)
+        , fCurrShaderID(0)
+        , fCurrGenericID(0)
+        , fCurrUniformLocation(0) {
+        this->init(kGL_GrGLStandard);
+    }
+
+    GrGLenum checkFramebufferStatus(GrGLenum target) override {
+        return GR_GL_FRAMEBUFFER_COMPLETE;
+    }
+
+    GrGLvoid genBuffers(GrGLsizei n, GrGLuint* ids) override {
+        for (int i = 0; i < n; ++i) {
+            BufferObj* buffer = fBufferManager.create();
+            ids[i] = buffer->id();
+        }
+    }
+
+    GrGLvoid bufferData(GrGLenum target, GrGLsizeiptr size, const GrGLvoid* data,
+                        GrGLenum usage) override {
+        GrGLuint id = 0;
+
+        switch (target) {
+            case GR_GL_ARRAY_BUFFER:
+                id = fCurrArrayBuffer;
+                break;
+            case GR_GL_ELEMENT_ARRAY_BUFFER:
+                id = fCurrElementArrayBuffer;
+                break;
+            case GR_GL_PIXEL_PACK_BUFFER:
+                id = fCurrPixelPackBuffer;
+                break;
+            case GR_GL_PIXEL_UNPACK_BUFFER:
+                id = fCurrPixelUnpackBuffer;
+                break;
+            default:
+                SkFAIL("Unexpected target to nullGLBufferData");
+                break;
+        }
+
+        if (id > 0) {
+            BufferObj* buffer = fBufferManager.lookUp(id);
+            buffer->allocate(size, (const GrGLchar*) data);
+        }
+    }
+
+    GrGLuint createProgram() override {
+        return ++fCurrProgramID;
+    }
+
+    GrGLuint createShader(GrGLenum type) override {
+        return ++fCurrShaderID;
+    }
+
+    GrGLvoid bindBuffer(GrGLenum target, GrGLuint buffer) override {
+        switch (target) {
+            case GR_GL_ARRAY_BUFFER:
+                fCurrArrayBuffer = buffer;
+                break;
+            case GR_GL_ELEMENT_ARRAY_BUFFER:
+                fCurrElementArrayBuffer = buffer;
+                break;
+            case GR_GL_PIXEL_PACK_BUFFER:
+                fCurrPixelPackBuffer = buffer;
+                break;
+            case GR_GL_PIXEL_UNPACK_BUFFER:
+                fCurrPixelUnpackBuffer = buffer;
+                break;
+        }
+    }
+
+    // deleting a bound buffer has the side effect of binding 0
+    GrGLvoid deleteBuffers(GrGLsizei n, const GrGLuint* ids) override {
+        for (int i = 0; i < n; ++i) {
+            if (ids[i] == fCurrArrayBuffer) {
+                fCurrArrayBuffer = 0;
+            }
+            if (ids[i] == fCurrElementArrayBuffer) {
+                fCurrElementArrayBuffer = 0;
+            }
+            if (ids[i] == fCurrPixelPackBuffer) {
+                fCurrPixelPackBuffer = 0;
+            }
+            if (ids[i] == fCurrPixelUnpackBuffer) {
+                fCurrPixelUnpackBuffer = 0;
+            }
+
+            BufferObj* buffer = fBufferManager.lookUp(ids[i]);
+            fBufferManager.free(buffer);
+        }
+    }
+
+    GrGLvoid genFramebuffers(GrGLsizei n, GrGLuint *framebuffers) override {
+        this->genGenericIds(n, framebuffers);
+    }
+
+    GrGLvoid genQueries(GrGLsizei n, GrGLuint *ids) override { this->genGenericIds(n, ids); }
+
+    GrGLvoid genRenderbuffers(GrGLsizei n, GrGLuint *renderbuffers) override {
+        this->genGenericIds(n, renderbuffers);
+    }
+
+    GrGLvoid genTextures(GrGLsizei n, GrGLuint *textures) override {
+        this->genGenericIds(n, textures);
+    }
+
+    GrGLvoid genVertexArrays(GrGLsizei n, GrGLuint *arrays) override {
+        this->genGenericIds(n, arrays);
+    }
+
+    GrGLenum getError() override { return GR_GL_NO_ERROR; }
+
+    GrGLvoid getIntegerv(GrGLenum pname, GrGLint* params) override {
+        // TODO: remove from Ganesh the #defines for gets we don't use.
+        // We would like to minimize gets overall due to performance issues
+        switch (pname) {
+            case GR_GL_CONTEXT_PROFILE_MASK:
+                *params = GR_GL_CONTEXT_COMPATIBILITY_PROFILE_BIT;
+                break;
+            case GR_GL_STENCIL_BITS:
+                *params = 8;
+                break;
+            case GR_GL_SAMPLES:
+                *params = 1;
+                break;
+            case GR_GL_FRAMEBUFFER_BINDING:
+                *params = 0;
+                break;
+            case GR_GL_VIEWPORT:
+                params[0] = 0;
+                params[1] = 0;
+                params[2] = 800;
+                params[3] = 600;
+                break;
+            case GR_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
+            case GR_GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS:
+            case GR_GL_MAX_TEXTURE_IMAGE_UNITS:
+            case GR_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
+                *params = 8;
+                break;
+            case GR_GL_MAX_TEXTURE_COORDS:
+                *params = 8;
+                break;
+            case GR_GL_MAX_VERTEX_UNIFORM_VECTORS:
+                *params = kDefaultMaxVertexUniformVectors;
+                break;
+            case GR_GL_MAX_FRAGMENT_UNIFORM_VECTORS:
+                *params = kDefaultMaxFragmentUniformVectors;
+                break;
+            case GR_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
+                *params = 16 * 4;
+                break;
+            case GR_GL_NUM_COMPRESSED_TEXTURE_FORMATS:
+                *params = 0;
+                break;
+            case GR_GL_COMPRESSED_TEXTURE_FORMATS:
+                break;
+            case GR_GL_MAX_TEXTURE_SIZE:
+                *params = 8192;
+                break;
+            case GR_GL_MAX_RENDERBUFFER_SIZE:
+                *params = 8192;
+                break;
+            case GR_GL_MAX_SAMPLES:
+                *params = 32;
+                break;
+            case GR_GL_MAX_VERTEX_ATTRIBS:
+                *params = kDefaultMaxVertexAttribs;
+                break;
+            case GR_GL_MAX_VARYING_VECTORS:
+                *params = kDefaultMaxVaryingVectors;
+                break;
+            case GR_GL_NUM_EXTENSIONS: {
+                GrGLint i = 0;
+                while (kExtensions[i++]);
+                *params = i;
+                break;
+            }
+            default:
+                SkFAIL("Unexpected pname to GetIntegerv");
+        }
+    }
+
+    GrGLvoid getProgramiv(GrGLuint program, GrGLenum pname, GrGLint* params) override {
+        this->getShaderOrProgramiv(program, pname, params);
+    }
+
+    GrGLvoid getProgramInfoLog(GrGLuint program, GrGLsizei bufsize, GrGLsizei* length,
+                               char* infolog) override {
+        this->getInfoLog(program, bufsize, length, infolog);
+    }
+
+    GrGLvoid getMultisamplefv(GrGLenum pname, GrGLuint index, GrGLfloat* val) override {
+        val[0] = val[1] = 0.5f;
+    }
+
+    GrGLvoid getQueryiv(GrGLenum GLtarget, GrGLenum pname, GrGLint *params) override {
+        switch (pname) {
+            case GR_GL_CURRENT_QUERY:
+                *params = 0;
+                break;
+            case GR_GL_QUERY_COUNTER_BITS:
+                *params = 32;
+                break;
+            default:
+                SkFAIL("Unexpected pname passed GetQueryiv.");
+        }
+    }
+
+    GrGLvoid getQueryObjecti64v(GrGLuint id, GrGLenum pname, GrGLint64 *params) override {
+        this->queryResult(id, pname, params);
+    }
+
+    GrGLvoid getQueryObjectiv(GrGLuint id, GrGLenum pname, GrGLint *params) override {
+        this->queryResult(id, pname, params);
+    }
+
+    GrGLvoid getQueryObjectui64v(GrGLuint id, GrGLenum pname, GrGLuint64 *params) override {
+        this->queryResult(id, pname, params);
+    }
+
+    GrGLvoid getQueryObjectuiv(GrGLuint id, GrGLenum pname, GrGLuint *params) override {
+        this->queryResult(id, pname, params);
+    }
+
+    GrGLvoid getShaderiv(GrGLuint shader, GrGLenum pname, GrGLint* params) override {
+        this->getShaderOrProgramiv(shader, pname, params);
+    }
+
+    GrGLvoid getShaderInfoLog(GrGLuint shader, GrGLsizei bufsize, GrGLsizei* length,
+                              char* infolog) override {
+        this->getInfoLog(shader, bufsize, length, infolog);
+    }
+
+    const GrGLubyte* getString(GrGLenum name) override {
+        switch (name) {
+            case GR_GL_EXTENSIONS:
+                return CombinedExtensionString();
+            case GR_GL_VERSION:
+                return (const GrGLubyte*)"4.0 Null GL";
+            case GR_GL_SHADING_LANGUAGE_VERSION:
+                return (const GrGLubyte*)"4.20.8 Null GLSL";
+            case GR_GL_VENDOR:
+                return (const GrGLubyte*)"Null Vendor";
+            case GR_GL_RENDERER:
+                return (const GrGLubyte*)"The Null (Non-)Renderer";
+            default:
+                SkFAIL("Unexpected name passed to GetString");
+                return nullptr;
+        }
+    }
+
+    const GrGLubyte* getStringi(GrGLenum name, GrGLuint i) override {
+        switch (name) {
+            case GR_GL_EXTENSIONS: {
+                GrGLint count;
+                this->getIntegerv(GR_GL_NUM_EXTENSIONS, &count);
+                if ((GrGLint)i <= count) {
+                    return (const GrGLubyte*) kExtensions[i];
+                } else {
+                    return nullptr;
+                }
+            }
+            default:
+                SkFAIL("Unexpected name passed to GetStringi");
+                return nullptr;
+        }
+    }
+
+    GrGLint getUniformLocation(GrGLuint program, const char* name) override {
+        return ++fCurrUniformLocation;
+    }
+
+    GrGLvoid* mapBufferRange(GrGLenum target, GrGLintptr offset, GrGLsizeiptr length,
+                             GrGLbitfield access) override {
+        GrGLuint id = 0;
+        switch (target) {
+            case GR_GL_ARRAY_BUFFER:
+                id = fCurrArrayBuffer;
+                break;
+            case GR_GL_ELEMENT_ARRAY_BUFFER:
+                id = fCurrElementArrayBuffer;
+                break;
+            case GR_GL_PIXEL_PACK_BUFFER:
+                id = fCurrPixelPackBuffer;
+                break;
+            case GR_GL_PIXEL_UNPACK_BUFFER:
+                id = fCurrPixelUnpackBuffer;
+                break;
+        }
+
+        if (id > 0) {
+            // We just ignore the offset and length here.
+            BufferObj* buffer = fBufferManager.lookUp(id);
+            SkASSERT(!buffer->mapped());
+            buffer->setMapped(true);
+            return buffer->dataPtr();
+        }
+        return nullptr;
+    }
+
+    GrGLvoid* mapBuffer(GrGLenum target, GrGLenum access) override {
+        GrGLuint id = 0;
+        switch (target) {
+            case GR_GL_ARRAY_BUFFER:
+                id = fCurrArrayBuffer;
+                break;
+            case GR_GL_ELEMENT_ARRAY_BUFFER:
+                id = fCurrElementArrayBuffer;
+                break;
+            case GR_GL_PIXEL_PACK_BUFFER:
+                id = fCurrPixelPackBuffer;
+                break;
+            case GR_GL_PIXEL_UNPACK_BUFFER:
+                id = fCurrPixelUnpackBuffer;
+                break;
+        }
+
+        if (id > 0) {
+            BufferObj* buffer = fBufferManager.lookUp(id);
+            SkASSERT(!buffer->mapped());
+            buffer->setMapped(true);
+            return buffer->dataPtr();
+        }
+
+        SkASSERT(false);
+        return nullptr;            // no buffer bound to target
+    }
+
+    GrGLboolean unmapBuffer(GrGLenum target) override {
+        GrGLuint id = 0;
+        switch (target) {
+            case GR_GL_ARRAY_BUFFER:
+                id = fCurrArrayBuffer;
+                break;
+            case GR_GL_ELEMENT_ARRAY_BUFFER:
+                id = fCurrElementArrayBuffer;
+                break;
+            case GR_GL_PIXEL_PACK_BUFFER:
+                id = fCurrPixelPackBuffer;
+                break;
+            case GR_GL_PIXEL_UNPACK_BUFFER:
+                id = fCurrPixelUnpackBuffer;
+                break;
+        }
+        if (id > 0) {
+            BufferObj* buffer = fBufferManager.lookUp(id);
+            SkASSERT(buffer->mapped());
+            buffer->setMapped(false);
+            return GR_GL_TRUE;
+        }
+
+        GrAlwaysAssert(false);
+        return GR_GL_FALSE; // GR_GL_INVALID_OPERATION;
+    }
+
+    GrGLvoid getBufferParameteriv(GrGLenum target, GrGLenum pname, GrGLint* params) override {
+        switch (pname) {
+            case GR_GL_BUFFER_MAPPED: {
+                *params = GR_GL_FALSE;
+                GrGLuint id = 0;
+                switch (target) {
+                    case GR_GL_ARRAY_BUFFER:
+                        id = fCurrArrayBuffer;
+                        break;
+                    case GR_GL_ELEMENT_ARRAY_BUFFER:
+                        id = fCurrElementArrayBuffer;
+                        break;
+                    case GR_GL_PIXEL_PACK_BUFFER:
+                        id = fCurrPixelPackBuffer;
+                        break;
+                    case GR_GL_PIXEL_UNPACK_BUFFER:
+                        id = fCurrPixelUnpackBuffer;
+                        break;
+                }
+                if (id > 0) {
+                    BufferObj* buffer = fBufferManager.lookUp(id);
+                    if (buffer->mapped()) {
+                        *params = GR_GL_TRUE;
+                    }
+                }
+                break; }
+            default:
+                SkFAIL("Unexpected pname to GetBufferParamateriv");
+                break;
+        }
+    };
+
+private:
+    BufferManager   fBufferManager;
+    GrGLuint        fCurrArrayBuffer;
+    GrGLuint        fCurrElementArrayBuffer;
+    GrGLuint        fCurrPixelPackBuffer;
+    GrGLuint        fCurrPixelUnpackBuffer;
+    GrGLuint        fCurrProgramID;
+    GrGLuint        fCurrShaderID;
+    GrGLuint        fCurrGenericID;
+    GrGLuint        fCurrUniformLocation;
+
+    // the OpenGLES 2.0 spec says this must be >= 128
+    static const GrGLint kDefaultMaxVertexUniformVectors = 128;
+
+    // the OpenGLES 2.0 spec says this must be >=16
+    static const GrGLint kDefaultMaxFragmentUniformVectors = 16;
+
+    // the OpenGLES 2.0 spec says this must be >= 8
+    static const GrGLint kDefaultMaxVertexAttribs = 8;
+
+    // the OpenGLES 2.0 spec says this must be >= 8
+    static const GrGLint kDefaultMaxVaryingVectors = 8;
+
+    static const char* kExtensions[];
+
+    static const GrGLubyte* CombinedExtensionString() {
+        static SkString gExtString;
+        static SkMutex gMutex;
+        gMutex.acquire();
+        if (0 == gExtString.size()) {
+            int i = 0;
+            while (kExtensions[i]) {
+                if (i > 0) {
+                    gExtString.append(" ");
+                }
+                gExtString.append(kExtensions[i]);
+                ++i;
+            }
+        }
+        gMutex.release();
+        return (const GrGLubyte*) gExtString.c_str();
+    }
+
+    GrGLvoid genGenericIds(GrGLsizei n, GrGLuint* ids) {
+        for (int i = 0; i < n; ++i) {
+            ids[i] = ++fCurrGenericID;
+        }
+    }
+
+    GrGLvoid getInfoLog(GrGLuint object, GrGLsizei bufsize, GrGLsizei* length,
+                        char* infolog) {
+        if (length) {
+            *length = 0;
+        }
+        if (bufsize > 0) {
+            *infolog = 0;
+        }
+    }
+
+    GrGLvoid getShaderOrProgramiv(GrGLuint object,  GrGLenum pname, GrGLint* params) {
+        switch (pname) {
+            case GR_GL_LINK_STATUS:  // fallthru
+            case GR_GL_COMPILE_STATUS:
+                *params = GR_GL_TRUE;
+                break;
+            case GR_GL_INFO_LOG_LENGTH:
+                *params = 0;
+                break;
+                // we don't expect any other pnames
+            default:
+                SkFAIL("Unexpected pname to GetProgramiv");
+                break;
+        }
+    }
+
+    template <typename T>
+    void queryResult(GrGLenum GLtarget, GrGLenum pname, T *params) {
+        switch (pname) {
+            case GR_GL_QUERY_RESULT_AVAILABLE:
+                *params = GR_GL_TRUE;
+                break;
+            case GR_GL_QUERY_RESULT:
+                *params = 0;
+                break;
+            default:
+                SkFAIL("Unexpected pname passed to GetQueryObject.");
+                break;
+        }
+    }
+
+    typedef GrGLTestInterface INHERITED;
+};
+
+const char* NullInterface::kExtensions[] = {
+    "GL_ARB_framebuffer_object",
+    "GL_ARB_blend_func_extended",
+    "GL_ARB_timer_query",
+    "GL_ARB_draw_buffers",
+    "GL_ARB_occlusion_query",
+    "GL_EXT_stencil_wrap",
+    nullptr, // signifies the end of the array.
+};
+
+class NullGLContext : public sk_gpu_test::GLContext {
+public:
+    NullGLContext() { this->init(new NullInterface); }
+   ~NullGLContext() override { this->teardown(); }
+
+private:    
+    void onPlatformMakeCurrent() const override {};
+    void onPlatformSwapBuffers() const override {}
+    GrGLFuncPtr onPlatformGetProcAddress(const char*) const override { return nullptr; }
+};
+}  // anonymous namespace
+
+namespace sk_gpu_test {
+GLContext* CreateNullGLContext() {
+    GLContext* ctx = new NullGLContext();
+    if (ctx->isValid()) {
+        return ctx;
+    }
+    delete ctx;
+    return nullptr;
+}
+}  // namespace sk_gpu_test
+
diff --git a/tools/gpu/gl/null/NullGLContext.h b/tools/gpu/gl/null/NullGLContext.h
new file mode 100644
index 0000000..16fb9fd
--- /dev/null
+++ b/tools/gpu/gl/null/NullGLContext.h
@@ -0,0 +1,17 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#ifndef NullGLContext_DEFINED
+#define NullGLContext_DEFINED
+
+#include "gl/GLContext.h"
+
+namespace sk_gpu_test {
+GLContext* CreateNullGLContext();
+}  // namespace sk_gpu_test
+
+#endif
diff --git a/tools/gpu/gl/win/CreatePlatformGLContext_win.cpp b/tools/gpu/gl/win/CreatePlatformGLContext_win.cpp
new file mode 100644
index 0000000..efee28b
--- /dev/null
+++ b/tools/gpu/gl/win/CreatePlatformGLContext_win.cpp
@@ -0,0 +1,204 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gl/GLContext.h"
+
+#include <windows.h>
+#include <GL/GL.h>
+#include "win/SkWGL.h"
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+namespace {
+
+class WinGLContext : public sk_gpu_test::GLContext {
+public:
+    WinGLContext(GrGLStandard forcedGpuAPI);
+	~WinGLContext() override;
+
+private:
+    void destroyGLContext();
+
+    void onPlatformMakeCurrent() const override;
+    void onPlatformSwapBuffers() const override;
+    GrGLFuncPtr onPlatformGetProcAddress(const char* name) const override;
+
+    HWND fWindow;
+    HDC fDeviceContext;
+    HGLRC fGlRenderContext;
+    static ATOM gWC;
+    SkWGLPbufferContext* fPbufferContext;
+};
+
+ATOM WinGLContext::gWC = 0;
+
+WinGLContext::WinGLContext(GrGLStandard forcedGpuAPI)
+    : fWindow(nullptr)
+    , fDeviceContext(nullptr)
+    , fGlRenderContext(0)
+    , fPbufferContext(nullptr) {
+    HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(nullptr);
+
+    if (!gWC) {
+        WNDCLASS wc;
+        wc.cbClsExtra = 0;
+        wc.cbWndExtra = 0;
+        wc.hbrBackground = nullptr;
+        wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
+        wc.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
+        wc.hInstance = hInstance;
+        wc.lpfnWndProc = (WNDPROC) DefWindowProc;
+        wc.lpszClassName = TEXT("Griffin");
+        wc.lpszMenuName = nullptr;
+        wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
+
+        gWC = RegisterClass(&wc);
+        if (!gWC) {
+            SkDebugf("Could not register window class.\n");
+            return;
+        }
+    }
+
+    if (!(fWindow = CreateWindow(TEXT("Griffin"),
+                                 TEXT("The Invisible Man"),
+                                 WS_OVERLAPPEDWINDOW,
+                                 0, 0, 1, 1,
+                                 nullptr, nullptr,
+                                 hInstance, nullptr))) {
+        SkDebugf("Could not create window.\n");
+        return;
+    }
+
+    if (!(fDeviceContext = GetDC(fWindow))) {
+        SkDebugf("Could not get device context.\n");
+        this->destroyGLContext();
+        return;
+    }
+    // Requesting a Core profile would bar us from using NVPR. So we request
+    // compatibility profile or GL ES.
+    SkWGLContextRequest contextType =
+        kGLES_GrGLStandard == forcedGpuAPI ?
+        kGLES_SkWGLContextRequest : kGLPreferCompatibilityProfile_SkWGLContextRequest;
+
+    fPbufferContext = SkWGLPbufferContext::Create(fDeviceContext, 0, contextType);
+
+    HDC dc;
+    HGLRC glrc;
+
+    if (nullptr == fPbufferContext) {
+        if (!(fGlRenderContext = SkCreateWGLContext(fDeviceContext, 0, contextType))) {
+            SkDebugf("Could not create rendering context.\n");
+            this->destroyGLContext();
+            return;
+        }
+        dc = fDeviceContext;
+        glrc = fGlRenderContext;
+    } else {
+        ReleaseDC(fWindow, fDeviceContext);
+        fDeviceContext = 0;
+        DestroyWindow(fWindow);
+        fWindow = 0;
+
+        dc = fPbufferContext->getDC();
+        glrc = fPbufferContext->getGLRC();
+    }
+
+    if (!(wglMakeCurrent(dc, glrc))) {
+        SkDebugf("Could not set the context.\n");
+        this->destroyGLContext();
+        return;
+    }
+
+    SkAutoTUnref<const GrGLInterface> gl(GrGLCreateNativeInterface());
+    if (nullptr == gl.get()) {
+        SkDebugf("Could not create GL interface.\n");
+        this->destroyGLContext();
+        return;
+    }
+    if (!gl->validate()) {
+        SkDebugf("Could not validate GL interface.\n");
+        this->destroyGLContext();
+        return;
+    }
+
+    this->init(gl.release());
+}
+
+WinGLContext::~WinGLContext() {
+    this->teardown();
+    this->destroyGLContext();
+}
+
+void WinGLContext::destroyGLContext() {
+    SkSafeSetNull(fPbufferContext);
+    if (fGlRenderContext) {
+        wglDeleteContext(fGlRenderContext);
+        fGlRenderContext = 0;
+    }
+    if (fWindow && fDeviceContext) {
+        ReleaseDC(fWindow, fDeviceContext);
+        fDeviceContext = 0;
+    }
+    if (fWindow) {
+        DestroyWindow(fWindow);
+        fWindow = 0;
+    }
+}
+
+void WinGLContext::onPlatformMakeCurrent() const {
+    HDC dc;
+    HGLRC glrc;
+
+    if (nullptr == fPbufferContext) {
+        dc = fDeviceContext;
+        glrc = fGlRenderContext;
+    } else {
+        dc = fPbufferContext->getDC();
+        glrc = fPbufferContext->getGLRC();
+    }
+
+    if (!wglMakeCurrent(dc, glrc)) {
+        SkDebugf("Could not create rendering context.\n");
+    }
+}
+
+void WinGLContext::onPlatformSwapBuffers() const {
+    HDC dc;
+
+    if (nullptr == fPbufferContext) {
+        dc = fDeviceContext;
+    } else {
+        dc = fPbufferContext->getDC();
+    }
+    if (!SwapBuffers(dc)) {
+        SkDebugf("Could not complete SwapBuffers.\n");
+    }
+}
+
+GrGLFuncPtr WinGLContext::onPlatformGetProcAddress(const char* name) const {
+    return reinterpret_cast<GrGLFuncPtr>(wglGetProcAddress(name));
+}
+
+} // anonymous namespace
+
+namespace sk_gpu_test {
+GLContext* CreatePlatformGLContext(GrGLStandard forcedGpuAPI, GLContext *shareContext) {
+    SkASSERT(!shareContext);
+    if (shareContext) {
+        return nullptr;
+    }
+    WinGLContext *ctx = new WinGLContext(forcedGpuAPI);
+    if (!ctx->isValid()) {
+        delete ctx;
+        return nullptr;
+    }
+    return ctx;
+}
+}  // namespace sk_gpu_test
+
diff --git a/tools/kilobench/kilobench.cpp b/tools/kilobench/kilobench.cpp
index c0422d8..8123835 100644
--- a/tools/kilobench/kilobench.cpp
+++ b/tools/kilobench/kilobench.cpp
@@ -20,6 +20,7 @@
 #include "Timer.h"
 #include "VisualSKPBench.h"
 #include "gl/GrGLDefines.h"
+#include "gl/GrGLUtil.h"
 #include "../private/SkMutex.h"
 #include "../private/SkSemaphore.h"
 #include "../private/SkGpuFenceSync.h"
@@ -29,6 +30,8 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 
+using namespace sk_gpu_test;
+
 /*
  * This is an experimental GPU only benchmarking program.  The initial implementation will only
  * support SKPs.
@@ -144,14 +147,14 @@
     void setup() {
         fGL->makeCurrent();
         // Make sure we're done with whatever came before.
-        SK_GL(*fGL, Finish());
+        GR_GL_CALL(fGL->gl(), Finish());
     }
 
     SkCanvas* beginTiming(SkCanvas* canvas) { return canvas; }
 
     void endTiming(bool usePlatformSwapBuffers) {
         if (fGL) {
-            SK_GL(*fGL, Flush());
+            GR_GL_CALL(fGL->gl(), Flush());
             if (usePlatformSwapBuffers) {
                 fGL->swapBuffers();
             } else {
@@ -160,7 +163,7 @@
         }
     }
     void finish() {
-        SK_GL(*fGL, Finish());
+        GR_GL_CALL(fGL->gl(), Finish());
     }
 
     bool needsFrameTiming(int* maxFrameLag) const {
@@ -215,10 +218,10 @@
         return true;
     }
 
-    SkGLContext* gl() { return fGL; }
+    GLContext* gl() { return fGL; }
 
 private:
-    SkGLContext* fGL;
+    GLContext* fGL;
     SkAutoTDelete<SkSurface> fSurface;
 };
 
@@ -279,7 +282,7 @@
 static double now_ms() { return SkTime::GetNSecs() * 1e-6; }
 
 struct TimingThread {
-    TimingThread(SkGLContext* mainContext)
+    TimingThread(GLContext* mainContext)
         : fFenceSync(mainContext->fenceSync())
         ,  fMainContext(mainContext)
         ,  fDone(false) {}
@@ -305,8 +308,8 @@
 
     void timingLoop() {
         // Create a context which shares display lists with the main thread
-        SkAutoTDelete<SkGLContext> glContext(SkCreatePlatformGLContext(kNone_GrGLStandard,
-                                                                       fMainContext));
+        SkAutoTDelete<GLContext> glContext(CreatePlatformGLContext(kNone_GrGLStandard,
+                                                                   fMainContext));
         glContext->makeCurrent();
 
         // Basic timing methodology is:
@@ -402,7 +405,7 @@
     SyncQueue fFrameEndSyncs;
     SkTArray<double> fTimings;
     SkMutex fDoneMutex;
-    SkGLContext* fMainContext;
+    GLContext* fMainContext;
     bool fDone;
 };
 
diff --git a/tools/skiaserve/Request.cpp b/tools/skiaserve/Request.cpp
index 1d946ab..d9e1bda 100644
--- a/tools/skiaserve/Request.cpp
+++ b/tools/skiaserve/Request.cpp
@@ -10,6 +10,8 @@
 #include "SkPictureRecorder.h"
 #include "SkPixelSerializer.h"
 
+using namespace sk_gpu_test;
+
 static int kDefaultWidth = 1920;
 static int kDefaultHeight = 1080;
 
@@ -63,8 +65,8 @@
 SkCanvas* Request::getCanvas() {
 #if SK_SUPPORT_GPU
     GrContextFactory* factory = fContextFactory;
-    SkGLContext* gl = factory->getContextInfo(GrContextFactory::kNative_GLContextType,
-                                              GrContextFactory::kNone_GLContextOptions).fGLContext;
+    GLContext* gl = factory->getContextInfo(GrContextFactory::kNative_GLContextType,
+                                            GrContextFactory::kNone_GLContextOptions).fGLContext;
     gl->makeCurrent();
 #endif
     SkASSERT(fDebugCanvas);
diff --git a/tools/skiaserve/Request.h b/tools/skiaserve/Request.h
index e3bc373..d19c2ba 100644
--- a/tools/skiaserve/Request.h
+++ b/tools/skiaserve/Request.h
@@ -19,7 +19,9 @@
 
 #include "UrlDataManager.h"
 
+namespace sk_gpu_test {
 class GrContextFactory;
+}
 struct MHD_Connection;
 struct MHD_PostProcessor;
 
@@ -69,7 +71,7 @@
     GrContext* getContext();
 
     sk_sp<SkPicture> fPicture;
-    GrContextFactory* fContextFactory;
+    sk_gpu_test::GrContextFactory* fContextFactory;
     SkAutoTUnref<SkSurface> fSurface;
     bool fGPUEnabled;
 };