Support using OpenGL ES context on desktop

Support using OpenGL ES context on desktop for unix and Android platforms. This
is mainly useful in development.

Add --gpuAPI flag to gm, dm, bench, bench_pictures and render_pictures. The
possible parameters for the flag are "gl" and "gles".

R=bsalomon@google.com, mtklein@google.com, robertphillips@google.com

Author: kkinnunen@nvidia.com

Review URL: https://codereview.chromium.org/319043005
diff --git a/bench/benchmain.cpp b/bench/benchmain.cpp
index 5c3b790..016ad2d 100644
--- a/bench/benchmain.cpp
+++ b/bench/benchmain.cpp
@@ -50,6 +50,11 @@
 
 static const char kDefaultsConfigStr[] = "defaults";
 
+#if SK_SUPPORT_GPU
+static const char kGpuAPINameGL[] = "gl";
+static const char kGpuAPINameGLES[] = "gles";
+#endif
+
 ///////////////////////////////////////////////////////////////////////////////
 
 class Iter {
@@ -227,6 +232,10 @@
 DEFINE_string(forceDither, "default", "Force dithering: true, false, or default?");
 DEFINE_bool(forceBlend,     false,    "Force alpha blending?");
 
+DEFINE_string(gpuAPI, "", "Force use of specific gpu API.  Using \"gl\" "
+              "forces OpenGL API. Using \"gles\" forces OpenGL ES API. "
+              "Defaults to empty string, which selects the API native to the "
+              "system.");
 DEFINE_int32(gpuCacheBytes, -1, "GPU cache size limit in bytes.  0 to disable cache.");
 DEFINE_int32(gpuCacheCount, -1, "GPU cache size limit in object count.  0 to disable cache.");
 
@@ -348,11 +357,24 @@
     }
 
 #if SK_SUPPORT_GPU
+    GrGLStandard gpuAPI = kNone_GrGLStandard;
+    if (1 == FLAGS_gpuAPI.count()) {
+        if (FLAGS_gpuAPI.contains(kGpuAPINameGL)) {
+            gpuAPI = kGL_GrGLStandard;
+        } else if (FLAGS_gpuAPI.contains(kGpuAPINameGLES)) {
+            gpuAPI = kGLES_GrGLStandard;
+        } else {
+            SkDebugf("Selected gpu API could not be used. Using the default.\n");
+        }
+    } else if (FLAGS_gpuAPI.count() > 1)  {
+        SkDebugf("Selected gpu API could not be used. Using the default.\n");
+    }
+
     for (int i = 0; i < configs.count(); ++i) {
         const Config& config = gConfigs[configs[i]];
 
         if (Benchmark::kGPU_Backend == config.backend) {
-            GrContext* context = gContextFactory.get(config.contextType);
+            GrContext* context = gContextFactory.get(config.contextType, gpuAPI);
             if (NULL == context) {
                 SkDebugf("GrContext could not be created for config %s. Config will be skipped.\n",
                     config.name);
@@ -412,7 +434,7 @@
         if (Benchmark::kGPU_Backend != config.backend) {
             continue;
         }
-        GrContext* context = gContextFactory.get(config.contextType);
+        GrContext* context = gContextFactory.get(config.contextType, gpuAPI);
         if (NULL == context) {
             continue;
         }
@@ -458,7 +480,7 @@
 #if SK_SUPPORT_GPU
             SkGLContextHelper* glContext = NULL;
             if (Benchmark::kGPU_Backend == config.backend) {
-                context = gContextFactory.get(config.contextType);
+                context = gContextFactory.get(config.contextType, gpuAPI);
                 if (NULL == context) {
                     continue;
                 }
diff --git a/dm/DM.cpp b/dm/DM.cpp
index 2981013..2e7966e 100644
--- a/dm/DM.cpp
+++ b/dm/DM.cpp
@@ -37,8 +37,15 @@
 using skiatest::Test;
 using skiatest::TestRegistry;
 
+static const char kGpuAPINameGL[] = "gl";
+static const char kGpuAPINameGLES[] = "gles";
+
 DEFINE_int32(threads, -1, "Threads for CPU work. Default NUM_CPUS.");
 DEFINE_int32(gpuThreads, 1, "Threads for GPU work.");
+DEFINE_string(gpuAPI, "", "Force use of specific gpu API.  Using \"gl\" "
+              "forces OpenGL API. Using \"gles\" forces OpenGL ES API. "
+              "Defaults to empty string, which selects the API native to the "
+              "system.");
 DEFINE_string2(expectations, r, "",
                "If a directory, compare generated images against images under this path. "
                "If a file, compare generated images against JSON expectations at this path."
@@ -95,6 +102,7 @@
 
 static void kick_off_gms(const SkTDArray<GMRegistry::Factory>& gms,
                          const SkTArray<SkString>& configs,
+                         GrGLStandard gpuAPI,
                          const DM::Expectations& expectations,
                          DM::Reporter* reporter,
                          DM::TaskRunner* tasks) {
@@ -104,17 +112,18 @@
     }
     for (int i = 0; i < gms.count(); i++) {
         for (int j = 0; j < configs.count(); j++) {
+
             START("565",        CpuGMTask, expectations, kRGB_565_SkColorType);
             START("8888",       CpuGMTask, expectations, kN32_SkColorType);
-            START("gpu",        GpuGMTask, expectations, native, 0);
-            START("msaa4",      GpuGMTask, expectations, native, 4);
-            START("msaa16",     GpuGMTask, expectations, native, 16);
-            START("nvprmsaa4",  GpuGMTask, expectations, nvpr,   4);
-            START("nvprmsaa16", GpuGMTask, expectations, nvpr,   16);
-            START("gpunull",    GpuGMTask, expectations, null,   0);
-            START("gpudebug",   GpuGMTask, expectations, debug,  0);
-            START("angle",      GpuGMTask, expectations, angle,  0);
-            START("mesa",       GpuGMTask, expectations, mesa,   0);
+            START("gpu",        GpuGMTask, expectations, native, gpuAPI, 0);
+            START("msaa4",      GpuGMTask, expectations, native, gpuAPI, 4);
+            START("msaa16",     GpuGMTask, expectations, native, gpuAPI, 16);
+            START("nvprmsaa4",  GpuGMTask, expectations, nvpr,   gpuAPI, 4);
+            START("nvprmsaa16", GpuGMTask, expectations, nvpr,   gpuAPI, 16);
+            START("gpunull",    GpuGMTask, expectations, null,   gpuAPI, 0);
+            START("gpudebug",   GpuGMTask, expectations, debug,  gpuAPI, 0);
+            START("angle",      GpuGMTask, expectations, angle,  gpuAPI, 0);
+            START("mesa",       GpuGMTask, expectations, mesa,   gpuAPI, 0);
             START("pdf",        PDFTask,   RASTERIZE_PDF_PROC);
         }
     }
@@ -123,6 +132,7 @@
 
 static void kick_off_benches(const SkTDArray<BenchRegistry::Factory>& benches,
                              const SkTArray<SkString>& configs,
+                             GrGLStandard gpuAPI,
                              DM::Reporter* reporter,
                              DM::TaskRunner* tasks) {
 #define START(name, type, ...)                                                                 \
@@ -134,15 +144,15 @@
             START("nonrendering", NonRenderingBenchTask);
             START("565",          CpuBenchTask, kRGB_565_SkColorType);
             START("8888",         CpuBenchTask, kN32_SkColorType);
-            START("gpu",          GpuBenchTask, native, 0);
-            START("msaa4",        GpuBenchTask, native, 4);
-            START("msaa16",       GpuBenchTask, native, 16);
-            START("nvprmsaa4",    GpuBenchTask, nvpr,   4);
-            START("nvprmsaa16",   GpuBenchTask, nvpr,   16);
-            START("gpunull",      GpuBenchTask, null,   0);
-            START("gpudebug",     GpuBenchTask, debug,  0);
-            START("angle",        GpuBenchTask, angle,  0);
-            START("mesa",         GpuBenchTask, mesa,   0);
+            START("gpu",          GpuBenchTask, native, gpuAPI, 0);
+            START("msaa4",        GpuBenchTask, native, gpuAPI, 4);
+            START("msaa16",       GpuBenchTask, native, gpuAPI, 16);
+            START("nvprmsaa4",    GpuBenchTask, nvpr,   gpuAPI, 4);
+            START("nvprmsaa16",   GpuBenchTask, nvpr,   gpuAPI, 16);
+            START("gpunull",      GpuBenchTask, null,   gpuAPI, 0);
+            START("gpudebug",     GpuBenchTask, debug,  gpuAPI, 0);
+            START("angle",        GpuBenchTask, angle,  gpuAPI, 0);
+            START("mesa",         GpuBenchTask, mesa,   gpuAPI, 0);
         }
     }
 #undef START
@@ -204,6 +214,16 @@
     SkDebugf("%d failures.\n", failures.count());
 }
 
+static GrGLStandard get_gl_standard() {
+  if (FLAGS_gpuAPI.contains(kGpuAPINameGL)) {
+      return kGL_GrGLStandard;
+  }
+  if (FLAGS_gpuAPI.contains(kGpuAPINameGLES)) {
+      return kGLES_GrGLStandard;
+  }
+  return kNone_GrGLStandard;
+}
+
 template <typename T, typename Registry>
 static void append_matching_factories(Registry* head, SkTDArray<typename Registry::Factory>* out) {
     for (const Registry* reg = head; reg != NULL; reg = reg->next()) {
@@ -232,6 +252,8 @@
         SkStrSplit(FLAGS_config[i], ", ", &configs);
     }
 
+    GrGLStandard gpuAPI = get_gl_standard();
+
     SkTDArray<GMRegistry::Factory> gms;
     SkAutoTDelete<DM::Expectations> expectations(SkNEW(DM::NoExpectations));
     if (FLAGS_gms) {
@@ -261,8 +283,8 @@
              gms.count(), benches.count(), configs.count(), tests.count());
     DM::Reporter reporter;
     DM::TaskRunner tasks(FLAGS_threads, FLAGS_gpuThreads);
-    kick_off_gms(gms, configs, *expectations, &reporter, &tasks);
-    kick_off_benches(benches, configs, &reporter, &tasks);
+    kick_off_gms(gms, configs, gpuAPI, *expectations, &reporter, &tasks);
+    kick_off_benches(benches, configs, gpuAPI, &reporter, &tasks);
     kick_off_tests(tests, &reporter, &tasks);
     kick_off_skps(&reporter, &tasks);
     tasks.wait();
diff --git a/dm/DMBenchTask.cpp b/dm/DMBenchTask.cpp
index 7cd2fdc..9bdbbf2 100644
--- a/dm/DMBenchTask.cpp
+++ b/dm/DMBenchTask.cpp
@@ -33,11 +33,13 @@
                            TaskRunner* tasks,
                            BenchRegistry::Factory factory,
                            GrContextFactory::GLContextType contextType,
+                           GrGLStandard gpuAPI,
                            int sampleCount)
     : GpuTask(reporter, tasks)
     , fBench(factory(NULL))
     , fName(bench_name(fBench->getName(), config))
     , fContextType(contextType)
+    , fGpuAPI(gpuAPI)
     , fSampleCount(sampleCount) {}
 
 bool NonRenderingBenchTask::shouldSkip() const {
@@ -74,8 +76,12 @@
                                          fBench->getSize().y(),
                                          kN32_SkColorType,
                                          kPremul_SkAlphaType);
-    SkAutoTUnref<SkSurface> surface(NewGpuSurface(grFactory, fContextType, info, fSampleCount));
-
+    SkAutoTUnref<SkSurface> surface(NewGpuSurface(grFactory, fContextType, fGpuAPI, info,
+                                                  fSampleCount));
+    if (!surface) {
+        this->fail("Could not create context for the config and the api.");
+        return;
+    }
     fBench->preDraw();
     fBench->draw(1, surface->getCanvas());
 }
diff --git a/dm/DMBenchTask.h b/dm/DMBenchTask.h
index 3c71cd7..d2b5800 100644
--- a/dm/DMBenchTask.h
+++ b/dm/DMBenchTask.h
@@ -46,6 +46,7 @@
                  TaskRunner*,
                  BenchRegistry::Factory,
                  GrContextFactory::GLContextType,
+                 GrGLStandard gpuAPI,
                  int sampleCount);
 
     virtual void draw(GrContextFactory*) SK_OVERRIDE;
@@ -56,6 +57,7 @@
     SkAutoTDelete<Benchmark> fBench;
     const SkString fName;
     const GrContextFactory::GLContextType fContextType;
+    const GrGLStandard fGpuAPI;
     int fSampleCount;
 };
 
diff --git a/dm/DMGpuGMTask.cpp b/dm/DMGpuGMTask.cpp
index b384485..4c44fae 100644
--- a/dm/DMGpuGMTask.cpp
+++ b/dm/DMGpuGMTask.cpp
@@ -15,12 +15,14 @@
                      skiagm::GMRegistry::Factory gmFactory,
                      const Expectations& expectations,
                      GrContextFactory::GLContextType contextType,
+                     GrGLStandard gpuAPI,
                      int sampleCount)
     : GpuTask(reporter, taskRunner)
     , fGM(gmFactory(NULL))
     , fName(UnderJoin(fGM->getName(), config))
     , fExpectations(expectations)
     , fContextType(contextType)
+    , fGpuAPI(gpuAPI)
     , fSampleCount(sampleCount)
     {}
 
@@ -29,7 +31,12 @@
                                          SkScalarCeilToInt(fGM->height()),
                                          kN32_SkColorType,
                                          kPremul_SkAlphaType);
-    SkAutoTUnref<SkSurface> surface(NewGpuSurface(grFactory, fContextType, info, fSampleCount));
+    SkAutoTUnref<SkSurface> surface(NewGpuSurface(grFactory, fContextType, fGpuAPI, info,
+                                                  fSampleCount));
+    if (!surface) {
+        this->fail("Could not create context for the config and the api.");
+        return;
+    }
     SkCanvas* canvas = surface->getCanvas();
 
     canvas->concat(fGM->getInitialTransform());
diff --git a/dm/DMGpuGMTask.h b/dm/DMGpuGMTask.h
index 6621a498..46b4c98 100644
--- a/dm/DMGpuGMTask.h
+++ b/dm/DMGpuGMTask.h
@@ -23,6 +23,7 @@
               skiagm::GMRegistry::Factory,
               const Expectations&,
               GrContextFactory::GLContextType,
+              GrGLStandard gpuAPI,
               int sampleCount);
 
     virtual void draw(GrContextFactory*) SK_OVERRIDE;
@@ -34,6 +35,7 @@
     const SkString fName;
     const Expectations& fExpectations;
     const GrContextFactory::GLContextType fContextType;
+    GrGLStandard fGpuAPI;
     const int fSampleCount;
 };
 
diff --git a/dm/DMGpuSupport.h b/dm/DMGpuSupport.h
index 46896b4..bcc00c2 100644
--- a/dm/DMGpuSupport.h
+++ b/dm/DMGpuSupport.h
@@ -19,9 +19,10 @@
 
 static inline SkSurface* NewGpuSurface(GrContextFactory* grFactory,
                                        GrContextFactory::GLContextType type,
+                                       GrGLStandard gpuAPI,
                                        SkImageInfo info,
                                        int samples) {
-    return SkSurface::NewRenderTarget(grFactory->get(type), info, samples);
+    return SkSurface::NewRenderTarget(grFactory->get(type, gpuAPI), info, samples);
 }
 
 }  // namespace DM
@@ -30,6 +31,12 @@
 
 // Ganesh is not available.  Fake it.
 
+enum GrGLStandard {
+    kNone_GrGLStandard,
+    kGL_GrGLStandard,
+    kGLES_GrGLStandard
+};
+
 class GrContextFactory {
 public:
     typedef int GLContextType;
@@ -48,6 +55,7 @@
 
 static inline SkSurface* NewGpuSurface(GrContextFactory*,
                                        GrContextFactory::GLContextType,
+                                       GrGLStandard,
                                        SkImageInfo,
                                        int) {
     return NULL;
diff --git a/experimental/PdfViewer/pdf_viewer_main.cpp b/experimental/PdfViewer/pdf_viewer_main.cpp
index 2f1a055..c1b0284 100644
--- a/experimental/PdfViewer/pdf_viewer_main.cpp
+++ b/experimental/PdfViewer/pdf_viewer_main.cpp
@@ -168,7 +168,8 @@
 #if SK_SUPPORT_GPU
         else if (strcmp(FLAGS_config[0], "gpu") == 0) {
             SkAutoTUnref<GrSurface> target;
-            GrContext* gr = gContextFactory.get(GrContextFactory::kNative_GLContextType);
+            GrContext* gr = gContextFactory.get(GrContextFactory::kNative_GLContextType,
+                                                kNone_GrGLStandard);
             if (gr) {
                 // create a render target to back the device
                 GrTextureDesc desc;
diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp
index 364e771..96a3454 100644
--- a/gm/gmmain.cpp
+++ b/gm/gmmain.cpp
@@ -67,6 +67,7 @@
 class GrContext;
 class GrSurface;
 typedef int GLContextType;
+typedef int GrGLStandard;
 #endif
 
 #define DEBUGFAIL_SEE_STDERR SkDEBUGFAIL("see stderr for message")
@@ -1335,6 +1336,10 @@
 
 static const char kDefaultsConfigStr[] = "defaults";
 static const char kExcludeConfigChar = '~';
+#if SK_SUPPORT_GPU
+static const char kGpuAPINameGL[] = "gl";
+static const char kGpuAPINameGLES[] = "gles";
+#endif
 
 static SkString configUsage() {
     SkString result;
@@ -1424,6 +1429,10 @@
 DEFINE_string(excludeConfig, "", "Space delimited list of configs to skip.");
 DEFINE_bool(forceBWtext, false, "Disable text anti-aliasing.");
 #if SK_SUPPORT_GPU
+DEFINE_string(gpuAPI, "", "Force use of specific gpu API.  Using \"gl\" "
+              "forces OpenGL API. Using \"gles\" forces OpenGL ES API. "
+              "Defaults to empty string, which selects the API native to the "
+              "system.");
 DEFINE_string(gpuCacheSize, "", "<bytes> <count>: Limit the gpu cache to byte size or "
               "object count. " TOSTRING(DEFAULT_CACHE_VALUE) " for either value means "
               "use the default. 0 for either disables the cache.");
@@ -1701,12 +1710,14 @@
                                       const SkTDArray<size_t> &configs,
                                       const SkTDArray<const PDFRasterizerData*> &pdfRasterizers,
                                       const SkTDArray<SkScalar> &tileGridReplayScales,
-                                      GrContextFactory *grFactory);
+                                      GrContextFactory *grFactory,
+                                      GrGLStandard gpuAPI);
 ErrorCombination run_multiple_configs(GMMain &gmmain, GM *gm,
                                       const SkTDArray<size_t> &configs,
                                       const SkTDArray<const PDFRasterizerData*> &pdfRasterizers,
                                       const SkTDArray<SkScalar> &tileGridReplayScales,
-                                      GrContextFactory *grFactory) {
+                                      GrContextFactory *grFactory,
+                                      GrGLStandard gpuAPI) {
     const char renderModeDescriptor[] = "";
     ErrorCombination errorsForAllConfigs;
     uint32_t gmFlags = gm->getFlags();
@@ -1756,7 +1767,7 @@
             if (FLAGS_resetGpuContext) {
                 grFactory->destroyContexts();
             }
-            GrContext* gr = grFactory->get(config.fGLContextType);
+            GrContext* gr = grFactory->get(config.fGLContextType, gpuAPI);
             bool grSuccess = false;
             if (gr) {
                 // create a render target to back the device
@@ -1927,7 +1938,7 @@
 }
 
 static bool parse_flags_configs(SkTDArray<size_t>* outConfigs,
-                         GrContextFactory* grFactory) {
+                         GrContextFactory* grFactory, GrGLStandard gpuAPI) {
     SkTDArray<size_t> excludeConfigs;
 
     for (int i = 0; i < FLAGS_config.count(); i++) {
@@ -1994,7 +2005,7 @@
     for (int i = 0; i < outConfigs->count(); ++i) {
         size_t index = (*outConfigs)[i];
         if (kGPU_Backend == gRec[index].fBackend) {
-            GrContext* ctx = grFactory->get(gRec[index].fGLContextType);
+            GrContext* ctx = grFactory->get(gRec[index].fGLContextType, gpuAPI);
             if (NULL == ctx) {
                 SkDebugf("GrContext could not be created for config %s. Config will be skipped.\n",
                          gRec[index].fName);
@@ -2148,6 +2159,25 @@
     }
     return true;
 }
+
+static bool parse_flags_gl_standard(GrGLStandard* gpuAPI) {
+    if (0 == FLAGS_gpuAPI.count()) {
+        *gpuAPI = kNone_GrGLStandard;
+        return true;
+    }
+    if (1 == FLAGS_gpuAPI.count()) {
+        if (FLAGS_gpuAPI.contains(kGpuAPINameGL)) {
+            *gpuAPI = kGL_GrGLStandard;
+            return true;
+        }
+        if (FLAGS_gpuAPI.contains(kGpuAPINameGLES)) {
+            *gpuAPI = kGLES_GrGLStandard;
+            return true;
+        }
+    }
+    SkDebugf("--gpuAPI invalid api value");
+    return false;
+}
 #endif
 
 static bool parse_flags_tile_grid_replay_scales(SkTDArray<SkScalar>* outScales) {
@@ -2238,8 +2268,10 @@
     SkTDArray<const PDFRasterizerData*> pdfRasterizers;
     SkTDArray<SkScalar> tileGridReplayScales;
 #if SK_SUPPORT_GPU
+    GrGLStandard gpuAPI = kNone_GrGLStandard;
     GrContextFactory* grFactory = new GrContextFactory;
 #else
+    GrGLStandard gpuAPI = 0;
     GrContextFactory* grFactory = NULL;
 #endif
 
@@ -2252,10 +2284,11 @@
         !parse_flags_ignore_tests(gmmain.fIgnorableTestNames) ||
 #if SK_SUPPORT_GPU
         !parse_flags_gpu_cache(&gGpuCacheSizeBytes, &gGpuCacheSizeCount) ||
+        !parse_flags_gl_standard(&gpuAPI) ||
 #endif
         !parse_flags_tile_grid_replay_scales(&tileGridReplayScales) ||
         !parse_flags_jpeg_quality() ||
-        !parse_flags_configs(&configs, grFactory) ||
+        !parse_flags_configs(&configs, grFactory, gpuAPI) ||
         !parse_flags_pdf_rasterizers(configs, &pdfRasterizers) ||
         !parse_flags_gmmain_paths(&gmmain)) {
         return -1;
@@ -2337,7 +2370,8 @@
         SkDebugf("%sdrawing... %s [%d %d]\n", moduloStr.c_str(), shortName,
                  size.width(), size.height());
         if (!FLAGS_dryRun)
-            run_multiple_configs(gmmain, gm, configs, pdfRasterizers, tileGridReplayScales, grFactory);
+            run_multiple_configs(gmmain, gm, configs, pdfRasterizers, tileGridReplayScales, 
+                                 grFactory, gpuAPI);
     }
 
     if (FLAGS_dryRun)
@@ -2414,7 +2448,7 @@
         ConfigData config = gRec[configs[i]];
 
         if (FLAGS_verbose && (kGPU_Backend == config.fBackend)) {
-            GrContext* gr = grFactory->get(config.fGLContextType);
+            GrContext* gr = grFactory->get(config.fGLContextType, gpuAPI);
 
             SkDebugf("config: %s %x\n", config.fName, gr);
             gr->printCacheStats();
@@ -2427,7 +2461,7 @@
         ConfigData config = gRec[configs[i]];
 
         if (kGPU_Backend == config.fBackend) {
-            GrContext* gr = grFactory->get(config.fGLContextType);
+            GrContext* gr = grFactory->get(config.fGLContextType, gpuAPI);
 
            gr->dumpFontCache();
         }
diff --git a/include/gpu/GrContextFactory.h b/include/gpu/GrContextFactory.h
index f09bad9..1f1f89d 100644
--- a/include/gpu/GrContextFactory.h
+++ b/include/gpu/GrContextFactory.h
@@ -88,8 +88,7 @@
         }
     }
 
-    GrContextFactory() {
-    }
+    GrContextFactory() { }
 
     ~GrContextFactory() { this->destroyContexts(); }
 
@@ -105,9 +104,12 @@
     /**
      * Get a GrContext initialized with a type of GL context. It also makes the GL context current.
      */
-    GrContext* get(GLContextType type) {
-
+    GrContext* get(GLContextType type, GrGLStandard forcedGpuAPI = kNone_GrGLStandard) {
         for (int i = 0; i < fContexts.count(); ++i) {
+            if (forcedGpuAPI != kNone_GrGLStandard &&
+                forcedGpuAPI != fContexts[i].fGLContext->gl()->fStandard)
+                continue;
+
             if (fContexts[i].fType == type) {
                 fContexts[i].fGLContext->makeCurrent();
                 return fContexts[i].fGrContext;
@@ -141,7 +143,7 @@
         if (!glCtx.get()) {
             return NULL;
         }
-        if (!glCtx.get()->init(kBogusSize, kBogusSize)) {
+        if (!glCtx.get()->init(forcedGpuAPI, kBogusSize, kBogusSize)) {
             return NULL;
         }
 
diff --git a/include/gpu/gl/SkANGLEGLContext.h b/include/gpu/gl/SkANGLEGLContext.h
index 99ef4e9..c5f62ff 100644
--- a/include/gpu/gl/SkANGLEGLContext.h
+++ b/include/gpu/gl/SkANGLEGLContext.h
@@ -36,7 +36,8 @@
     };
 
 protected:
-    virtual const GrGLInterface* createGLContext() SK_OVERRIDE;
+    virtual const GrGLInterface* createGLContext(
+        GrGLStandard forcedGpuAPI) SK_OVERRIDE;
     virtual void destroyGLContext() SK_OVERRIDE;
 
 private:
diff --git a/include/gpu/gl/SkDebugGLContext.h b/include/gpu/gl/SkDebugGLContext.h
index 545ef40..9318cb4 100644
--- a/include/gpu/gl/SkDebugGLContext.h
+++ b/include/gpu/gl/SkDebugGLContext.h
@@ -19,7 +19,7 @@
     virtual void swapBuffers() const SK_OVERRIDE {};
 
 protected:
-    virtual const GrGLInterface* createGLContext() SK_OVERRIDE;
+    virtual const GrGLInterface* createGLContext(GrGLStandard forcedGpuAPI) SK_OVERRIDE;
 
     virtual void destroyGLContext() SK_OVERRIDE {};
 };
diff --git a/include/gpu/gl/SkGLContextHelper.h b/include/gpu/gl/SkGLContextHelper.h
index ea940c8..9da8741 100644
--- a/include/gpu/gl/SkGLContextHelper.h
+++ b/include/gpu/gl/SkGLContextHelper.h
@@ -25,7 +25,7 @@
     /**
      * Initializes the context and makes it current.
      */
-    bool init(const int width, const int height);
+    bool init(GrGLStandard forcedGpuAPI, const int width, const int height);
 
     int getFBOID() const { return fFBO; }
 
@@ -57,7 +57,7 @@
      * format and size of backbuffers does not matter since an FBO will be
      * created.
      */
-    virtual const GrGLInterface* createGLContext() = 0;
+    virtual const GrGLInterface* createGLContext(GrGLStandard forcedGpuAPI) = 0;
 
     /**
      * Subclass should destroy the underlying GL context.
diff --git a/include/gpu/gl/SkMesaGLContext.h b/include/gpu/gl/SkMesaGLContext.h
index 55235fa..28349dd 100644
--- a/include/gpu/gl/SkMesaGLContext.h
+++ b/include/gpu/gl/SkMesaGLContext.h
@@ -38,7 +38,7 @@
     };
 
 protected:
-    virtual const GrGLInterface* createGLContext() SK_OVERRIDE;
+    virtual const GrGLInterface* createGLContext(GrGLStandard forcedGpuAPI) SK_OVERRIDE;
     virtual void destroyGLContext() SK_OVERRIDE;
 
 private:
diff --git a/include/gpu/gl/SkNativeGLContext.h b/include/gpu/gl/SkNativeGLContext.h
index 7254de1..fac52b3 100644
--- a/include/gpu/gl/SkNativeGLContext.h
+++ b/include/gpu/gl/SkNativeGLContext.h
@@ -58,7 +58,7 @@
     };
 
 protected:
-    virtual const GrGLInterface* createGLContext() SK_OVERRIDE;
+    virtual const GrGLInterface* createGLContext(GrGLStandard forcedGpuAPI) SK_OVERRIDE;
     virtual void destroyGLContext() SK_OVERRIDE;
 
 private:
diff --git a/include/gpu/gl/SkNullGLContext.h b/include/gpu/gl/SkNullGLContext.h
index 02d968e..6c2a1d7 100644
--- a/include/gpu/gl/SkNullGLContext.h
+++ b/include/gpu/gl/SkNullGLContext.h
@@ -20,7 +20,7 @@
     virtual void swapBuffers() const SK_OVERRIDE {};
 
 protected:
-    virtual const GrGLInterface* createGLContext() SK_OVERRIDE;
+    virtual const GrGLInterface* createGLContext(GrGLStandard forcedGpuAPI) SK_OVERRIDE;
 
     virtual void destroyGLContext() SK_OVERRIDE {};
 };
diff --git a/include/utils/SkWGL.h b/include/utils/SkWGL.h
index 5f630a1..5272f17 100644
--- a/include/utils/SkWGL.h
+++ b/include/utils/SkWGL.h
@@ -104,12 +104,22 @@
     CreateContextAttribsProc fCreateContextAttribs;
 };
 
+enum SkWGLContextRequest {
+    /** Requests to create core profile context if possible, otherwise
+        compatibility profile. */
+    kGLPreferCoreProfile_SkWGLContextRequest,
+    /** Requests to create compatibility profile context if possible, otherwise
+        core profile. */
+    kGLPreferCompatibilityProfile_SkWGLContextRequest,
+    /** Requests to create GL ES profile context. */
+    kGLES_SkWGLContextRequest
+};
 /**
  * Helper to create an OpenGL context for a DC using WGL. Configs with a sample count >= to
  * msaaSampleCount are preferred but if none is available then a context with a lower sample count
  * (including non-MSAA) will be created. If preferCoreProfile is true but a core profile cannot be
  * created then a compatible profile context will be created.
  */
-HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, bool preferCoreProfile);
+HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, SkWGLContextRequest context);
 
 #endif
diff --git a/src/gpu/gl/GrGLAssembleGLESInterface.h b/src/gpu/gl/GrGLAssembleGLESInterface.h
new file mode 100644
index 0000000..ddbc980
--- /dev/null
+++ b/src/gpu/gl/GrGLAssembleGLESInterface.h
@@ -0,0 +1,240 @@
+
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+const GrGLInterface* GrGLAssembleGLESInterface(void* ctx, GrGLGetProc get) {
+    GET_PROC_LOCAL(GetString);
+    const char* verStr = reinterpret_cast<const char*>(GetString(GR_GL_VERSION));
+    GrGLVersion version = GrGLGetVersionFromString(verStr);
+
+    if (version < GR_GL_VER(2,0)) {
+        return NULL;
+    }
+
+    GET_PROC_LOCAL(GetIntegerv);
+    GET_PROC_LOCAL(GetStringi);
+    GrGLExtensions extensions;
+    if (!extensions.init(kGLES_GrGLStandard, GetString, GetStringi, GetIntegerv)) {
+        return NULL;
+    }
+
+    GrGLInterface* interface = SkNEW(GrGLInterface);
+    GrGLInterface::Functions* functions = &interface->fFunctions;
+
+    GET_LINKED(ActiveTexture);
+    GET_LINKED(AttachShader);
+    GET_LINKED(BindAttribLocation);
+    GET_LINKED(BindBuffer);
+    GET_LINKED(BindTexture);
+    GET_LINKED_SUFFIX(BindVertexArray, OES);
+    GET_LINKED(BlendColor);
+    GET_LINKED(BlendFunc);
+    GET_LINKED(BufferData);
+    GET_LINKED(BufferSubData);
+    GET_LINKED(Clear);
+    GET_LINKED(ClearColor);
+    GET_LINKED(ClearStencil);
+    GET_LINKED(ColorMask);
+    GET_LINKED(CompileShader);
+    GET_LINKED(CompressedTexImage2D);
+    GET_LINKED(CompressedTexSubImage2D);
+    GET_LINKED(CopyTexSubImage2D);
+    GET_LINKED(CreateProgram);
+    GET_LINKED(CreateShader);
+    GET_LINKED(CullFace);
+    GET_LINKED(DeleteBuffers);
+    GET_LINKED(DeleteProgram);
+    GET_LINKED(DeleteShader);
+    GET_LINKED(DeleteTextures);
+    GET_LINKED_SUFFIX(DeleteVertexArrays, OES);
+    GET_LINKED(DepthMask);
+    GET_LINKED(Disable);
+    GET_LINKED(DisableVertexAttribArray);
+    GET_LINKED(DrawArrays);
+    GET_LINKED(DrawElements);
+    GET_LINKED(Enable);
+    GET_LINKED(EnableVertexAttribArray);
+    GET_LINKED(Finish);
+    GET_LINKED(Flush);
+    GET_LINKED(FrontFace);
+    GET_LINKED(GenBuffers);
+    GET_LINKED(GenerateMipmap);
+    GET_LINKED(GenTextures);
+    GET_LINKED_SUFFIX(GenVertexArrays, OES);
+    GET_LINKED(GetBufferParameteriv);
+    GET_LINKED(GetError);
+    GET_LINKED(GetIntegerv);
+    GET_LINKED(GetProgramInfoLog);
+    GET_LINKED(GetProgramiv);
+    GET_LINKED(GetShaderInfoLog);
+    GET_LINKED(GetShaderiv);
+    GET_LINKED(GetString);
+#if USE_LINKED && GL_ES_VERSION_3_0
+    GET_LINKED(GetStringi);
+#else
+    GET_PROC(GetStringi);
+#endif
+    GET_LINKED(GetUniformLocation);
+    GET_LINKED(LineWidth);
+    GET_LINKED(LinkProgram);
+    GET_LINKED(PixelStorei);
+    GET_LINKED(ReadPixels);
+    GET_LINKED(Scissor);
+#if GR_GL_USE_NEW_SHADER_SOURCE_SIGNATURE
+    functions->fShaderSource = (GrGLShaderSourceProc) glShaderSource;
+#else
+    GET_LINKED(ShaderSource);
+#endif
+    GET_LINKED(StencilFunc);
+    GET_LINKED(StencilFuncSeparate);
+    GET_LINKED(StencilMask);
+    GET_LINKED(StencilMaskSeparate);
+    GET_LINKED(StencilOp);
+    GET_LINKED(StencilOpSeparate);
+    GET_LINKED(TexImage2D);
+    GET_LINKED(TexParameteri);
+    GET_LINKED(TexParameteriv);
+    GET_LINKED(TexSubImage2D);
+
+    if (version >= GR_GL_VER(3,0)) {
+#if USE_LINKED && GL_ES_VERSION_3_0
+        GET_LINKED(TexStorage2D);
+#else
+        GET_PROC(TexStorage2D);
+#endif
+    } else {
+#if USE_LINKED && GL_EXT_texture_storage
+        GET_LINKED_SUFFIX(TexStorage2D, EXT);
+#else
+        GET_PROC_SUFFIX(TexStorage2D, EXT);
+#endif
+    }
+
+#if USE_LINKED && GL_EXT_discard_framebuffer
+    GET_LINKED_SUFFIX(DiscardFramebuffer, EXT);
+#endif
+    GET_LINKED(Uniform1f);
+    GET_LINKED(Uniform1i);
+    GET_LINKED(Uniform1fv);
+    GET_LINKED(Uniform1iv);
+    GET_LINKED(Uniform2f);
+    GET_LINKED(Uniform2i);
+    GET_LINKED(Uniform2fv);
+    GET_LINKED(Uniform2iv);
+    GET_LINKED(Uniform3f);
+    GET_LINKED(Uniform3i);
+    GET_LINKED(Uniform3fv);
+    GET_LINKED(Uniform3iv);
+    GET_LINKED(Uniform4f);
+    GET_LINKED(Uniform4i);
+    GET_LINKED(Uniform4fv);
+    GET_LINKED(Uniform4iv);
+    GET_LINKED(UniformMatrix2fv);
+    GET_LINKED(UniformMatrix3fv);
+    GET_LINKED(UniformMatrix4fv);
+    GET_LINKED(UseProgram);
+    GET_LINKED(VertexAttrib4fv);
+    GET_LINKED(VertexAttribPointer);
+    GET_LINKED(Viewport);
+    GET_LINKED(BindFramebuffer);
+    GET_LINKED(BindRenderbuffer);
+    GET_LINKED(CheckFramebufferStatus);
+    GET_LINKED(DeleteFramebuffers);
+    GET_LINKED(DeleteRenderbuffers);
+    GET_LINKED(FramebufferRenderbuffer);
+    GET_LINKED(FramebufferTexture2D);
+
+    if (version >= GR_GL_VER(3,0)) {
+#if USE_LINKED && GL_ES_VERSION_3_0
+        GET_LINKED(RenderbufferStorageMultisample);
+        GET_LINKED(BlitFramebuffer);
+#else
+        GET_PROC(RenderbufferStorageMultisample);
+        GET_PROC(BlitFramebuffer);
+#endif
+    }
+
+    if (extensions.has("GL_EXT_multisampled_render_to_texture")) {
+#if USE_LINKED && GL_EXT_multisampled_render_to_texture
+        GET_LINKED_SUFFIX(FramebufferTexture2DMultisample, EXT);
+        functions->fRenderbufferStorageMultisampleES2EXT = glRenderbufferStorageMultisampleEXT;
+#else
+        GET_PROC_SUFFIX(FramebufferTexture2DMultisample, EXT);
+        functions->fRenderbufferStorageMultisampleES2EXT = (GrGLRenderbufferStorageMultisampleProc) get(ctx, "glRenderbufferStorageMultisampleEXT");
+#endif
+    } else if (extensions.has("GL_IMG_multisampled_render_to_texture")) {
+#if USE_LINKED && GL_IMG_multisampled_render_to_texture
+        GET_LINKED_SUFFIX(FramebufferTexture2DMultisample, IMG);
+        functions->fRenderbufferStorageMultisampleES2EXT = glRenderbufferStorageMultisampleIMG;
+#else
+        GET_PROC_SUFFIX(FramebufferTexture2DMultisample, IMG);
+        functions->fRenderbufferStorageMultisampleES2EXT = (GrGLRenderbufferStorageMultisampleProc) get(ctx, "glRenderbufferStorageMultisampleIMG");
+#endif
+    }
+
+    GET_LINKED(GenFramebuffers);
+    GET_LINKED(GenRenderbuffers);
+    GET_LINKED(GetFramebufferAttachmentParameteriv);
+    GET_LINKED(GetRenderbufferParameteriv);
+    GET_LINKED(RenderbufferStorage);
+
+#if USE_LINKED && GL_OES_mapbuffer
+    GET_LINKED_SUFFIX(MapBuffer, OES);
+    GET_LINKED_SUFFIX(UnmapBuffer, OES);
+#else
+    GET_PROC_SUFFIX(MapBuffer, OES);
+    GET_PROC_SUFFIX(UnmapBuffer, OES);
+#endif
+
+    if (version >= GR_GL_VER(3,0)) {
+#if USE_LINKED && GL_ES_VERSION_3_0
+        GET_LINKED(MapBufferRange);
+        GET_LINKED(FlushMappedBufferRange);
+#else
+        GET_PROC(MapBufferRange);
+        GET_PROC(FlushMappedBufferRange);
+#endif
+    } else if (extensions.has("GL_EXT_map_buffer_range")) {
+#if USE_LINKED && GL_EXT_map_buffer_range
+        GET_LINKED_SUFFIX(MapBufferRange, EXT);
+        GET_LINKED_SUFFIX(FlushMappedBufferRange, EXT);
+#else
+        GET_PROC_SUFFIX(MapBufferRange, EXT);
+        GET_PROC_SUFFIX(FlushMappedBufferRange, EXT);
+#endif
+    }
+
+    if (extensions.has("GL_EXT_debug_marker")) {
+        GET_PROC(InsertEventMarker);
+        GET_PROC(PushGroupMarker);
+        GET_PROC(PopGroupMarker);
+        // The below check is here because a device has been found that has the extension string but
+        // returns NULL from the eglGetProcAddress for the functions
+        if (NULL == functions->fInsertEventMarker ||
+            NULL == functions->fPushGroupMarker ||
+            NULL == functions->fPopGroupMarker) {
+            extensions.remove("GL_EXT_debug_marker");
+        }
+    }
+
+#if USE_LINKED && GL_ES_VERSION_3_0
+    GET_LINKED(InvalidateFramebuffer);
+    GET_LINKED(InvalidateSubFramebuffer);
+#else
+    GET_PROC(InvalidateFramebuffer);
+    GET_PROC(InvalidateSubFramebuffer);
+#endif
+    GET_PROC(InvalidateBufferData);
+    GET_PROC(InvalidateBufferSubData);
+    GET_PROC(InvalidateTexImage);
+    GET_PROC(InvalidateTexSubImage);
+
+    interface->fStandard = kGLES_GrGLStandard;
+    interface->fExtensions.swap(&extensions);
+
+    return interface;
+}
diff --git a/src/gpu/gl/GrGLAssembleInterface.h b/src/gpu/gl/GrGLAssembleInterface.h
index 36a4513..4bd8836 100644
--- a/src/gpu/gl/GrGLAssembleInterface.h
+++ b/src/gpu/gl/GrGLAssembleInterface.h
@@ -16,3 +16,10 @@
  * get() to get each function address. ctx is a generic ptr passed to and interpreted by get().
  */
 const GrGLInterface* GrGLAssembleGLInterface(void* ctx, GrGLGetProc get);
+
+/**
+ * Generic function for creating a GrGLInterface for an OpenGL ES (but not Open GL) context. It
+ * calls get() to get each function address. ctx is a generic ptr passed to and interpreted by
+ * get().
+ */
+const GrGLInterface* GrGLAssembleGLESInterface(void* ctx, GrGLGetProc get);
diff --git a/src/gpu/gl/SkGLContextHelper.cpp b/src/gpu/gl/SkGLContextHelper.cpp
index b06f755..2381a84 100644
--- a/src/gpu/gl/SkGLContextHelper.cpp
+++ b/src/gpu/gl/SkGLContextHelper.cpp
@@ -27,13 +27,14 @@
     SkSafeUnref(fGL);
 }
 
-bool SkGLContextHelper::init(int width, int height) {
+bool SkGLContextHelper::init(GrGLStandard forcedGpuAPI, int width,
+                             int height) {
     if (fGL) {
         fGL->unref();
         this->destroyGLContext();
     }
 
-    fGL = this->createGLContext();
+    fGL = this->createGLContext(forcedGpuAPI);
     if (fGL) {
         const GrGLubyte* temp;
 
diff --git a/src/gpu/gl/SkNullGLContext.cpp b/src/gpu/gl/SkNullGLContext.cpp
index 86c09b2..576ee52 100644
--- a/src/gpu/gl/SkNullGLContext.cpp
+++ b/src/gpu/gl/SkNullGLContext.cpp
@@ -8,6 +8,9 @@
 
 #include "gl/SkNullGLContext.h"
 
-const GrGLInterface* SkNullGLContext::createGLContext() {
+const GrGLInterface* SkNullGLContext::createGLContext(GrGLStandard forcedGpuAPI) {
+    if (kGLES_GrGLStandard == forcedGpuAPI) {
+        return NULL;
+    }
     return GrGLCreateNullInterface();
 };
diff --git a/src/gpu/gl/android/GrGLCreateNativeInterface_android.cpp b/src/gpu/gl/android/GrGLCreateNativeInterface_android.cpp
index 781e29b..ba1c4be 100644
--- a/src/gpu/gl/android/GrGLCreateNativeInterface_android.cpp
+++ b/src/gpu/gl/android/GrGLCreateNativeInterface_android.cpp
@@ -18,258 +18,30 @@
 
 #include <EGL/egl.h>
 
-static GrGLInterface* create_es_interface(GrGLVersion version,
-                                          GrGLExtensions* extensions) {
-    if (version < GR_GL_VER(2,0)) {
-        return NULL;
-    }
+#define GET_PROC(F) functions->f ## F = (GrGL ## F ## Proc) get(ctx, "gl" #F)
+#define GET_PROC_SUFFIX(F, S) functions->f ## F = (GrGL ## F ## Proc) get(ctx, "gl" #F #S)
+#define GET_PROC_LOCAL(F) GrGL ## F ## Proc F = (GrGL ## F ## Proc) get(ctx, "gl" #F)
 
-    GrGLInterface* interface = SkNEW(GrGLInterface);
-    interface->fStandard = kGLES_GrGLStandard;
-    GrGLInterface::Functions* functions = &interface->fFunctions;
+#define GET_LINKED(F) functions->f ## F = gl ## F
+#define GET_LINKED_SUFFIX(F, S) functions->f ## F = gl ## F ##S
+#define USE_LINKED 1
 
-    functions->fActiveTexture = glActiveTexture;
-    functions->fAttachShader = glAttachShader;
-    functions->fBindAttribLocation = glBindAttribLocation;
-    functions->fBindBuffer = glBindBuffer;
-    functions->fBindTexture = glBindTexture;
-    functions->fBindVertexArray = glBindVertexArrayOES;
-    functions->fBlendColor = glBlendColor;
-    functions->fBlendFunc = glBlendFunc;
-    functions->fBufferData = glBufferData;
-    functions->fBufferSubData = glBufferSubData;
-    functions->fClear = glClear;
-    functions->fClearColor = glClearColor;
-    functions->fClearStencil = glClearStencil;
-    functions->fColorMask = glColorMask;
-    functions->fCompileShader = glCompileShader;
-    functions->fCompressedTexImage2D = glCompressedTexImage2D;
-    functions->fCompressedTexSubImage2D = glCompressedTexSubImage2D;
-    functions->fCopyTexSubImage2D = glCopyTexSubImage2D;
-    functions->fCreateProgram = glCreateProgram;
-    functions->fCreateShader = glCreateShader;
-    functions->fCullFace = glCullFace;
-    functions->fDeleteBuffers = glDeleteBuffers;
-    functions->fDeleteProgram = glDeleteProgram;
-    functions->fDeleteShader = glDeleteShader;
-    functions->fDeleteTextures = glDeleteTextures;
-    functions->fDeleteVertexArrays = glDeleteVertexArraysOES;
-    functions->fDepthMask = glDepthMask;
-    functions->fDisable = glDisable;
-    functions->fDisableVertexAttribArray = glDisableVertexAttribArray;
-    functions->fDrawArrays = glDrawArrays;
-    functions->fDrawElements = glDrawElements;
-    functions->fEnable = glEnable;
-    functions->fEnableVertexAttribArray = glEnableVertexAttribArray;
-    functions->fFinish = glFinish;
-    functions->fFlush = glFlush;
-    functions->fFrontFace = glFrontFace;
-    functions->fGenBuffers = glGenBuffers;
-    functions->fGenerateMipmap = glGenerateMipmap;
-    functions->fGenTextures = glGenTextures;
-    functions->fGenVertexArrays = glGenVertexArraysOES;
-    functions->fGetBufferParameteriv = glGetBufferParameteriv;
-    functions->fGetError = glGetError;
-    functions->fGetIntegerv = glGetIntegerv;
-    functions->fGetProgramInfoLog = glGetProgramInfoLog;
-    functions->fGetProgramiv = glGetProgramiv;
-    functions->fGetShaderInfoLog = glGetShaderInfoLog;
-    functions->fGetShaderiv = glGetShaderiv;
-    functions->fGetString = glGetString;
-#if GL_ES_VERSION_3_0
-    functions->fGetStringi = glGetStringi;
-#else
-    functions->fGetStringi = (GrGLGetStringiProc) eglGetProcAddress("glGetStringi");
-#endif
-    functions->fGetUniformLocation = glGetUniformLocation;
-    functions->fLineWidth = glLineWidth;
-    functions->fLinkProgram = glLinkProgram;
-    functions->fPixelStorei = glPixelStorei;
-    functions->fReadPixels = glReadPixels;
-    functions->fScissor = glScissor;
-#if GR_GL_USE_NEW_SHADER_SOURCE_SIGNATURE
-    functions->fShaderSource = (GrGLShaderSourceProc) glShaderSource;
-#else
-    functions->fShaderSource = glShaderSource;
-#endif
-    functions->fStencilFunc = glStencilFunc;
-    functions->fStencilFuncSeparate = glStencilFuncSeparate;
-    functions->fStencilMask = glStencilMask;
-    functions->fStencilMaskSeparate = glStencilMaskSeparate;
-    functions->fStencilOp = glStencilOp;
-    functions->fStencilOpSeparate = glStencilOpSeparate;
-    functions->fTexImage2D = glTexImage2D;
-    functions->fTexParameteri = glTexParameteri;
-    functions->fTexParameteriv = glTexParameteriv;
-    functions->fTexSubImage2D = glTexSubImage2D;
-
-    if (version >= GR_GL_VER(3,0)) {
-#if GL_ES_VERSION_3_0
-        functions->fTexStorage2D = glTexStorage2D;
-#else
-        functions->fTexStorage2D = (GrGLTexStorage2DProc) eglGetProcAddress("glTexStorage2D");
-#endif
-    } else {
-#if GL_EXT_texture_storage
-        functions->fTexStorage2D = glTexStorage2DEXT;
-#else
-        functions->fTexStorage2D = (GrGLTexStorage2DProc) eglGetProcAddress("glTexStorage2DEXT");
-#endif
-    }
-
-#if GL_EXT_discard_framebuffer
-    functions->fDiscardFramebuffer = glDiscardFramebufferEXT;
-#endif
-    functions->fUniform1f = glUniform1f;
-    functions->fUniform1i = glUniform1i;
-    functions->fUniform1fv = glUniform1fv;
-    functions->fUniform1iv = glUniform1iv;
-    functions->fUniform2f = glUniform2f;
-    functions->fUniform2i = glUniform2i;
-    functions->fUniform2fv = glUniform2fv;
-    functions->fUniform2iv = glUniform2iv;
-    functions->fUniform3f = glUniform3f;
-    functions->fUniform3i = glUniform3i;
-    functions->fUniform3fv = glUniform3fv;
-    functions->fUniform3iv = glUniform3iv;
-    functions->fUniform4f = glUniform4f;
-    functions->fUniform4i = glUniform4i;
-    functions->fUniform4fv = glUniform4fv;
-    functions->fUniform4iv = glUniform4iv;
-    functions->fUniformMatrix2fv = glUniformMatrix2fv;
-    functions->fUniformMatrix3fv = glUniformMatrix3fv;
-    functions->fUniformMatrix4fv = glUniformMatrix4fv;
-    functions->fUseProgram = glUseProgram;
-    functions->fVertexAttrib4fv = glVertexAttrib4fv;
-    functions->fVertexAttribPointer = glVertexAttribPointer;
-    functions->fViewport = glViewport;
-    functions->fBindFramebuffer = glBindFramebuffer;
-    functions->fBindRenderbuffer = glBindRenderbuffer;
-    functions->fCheckFramebufferStatus = glCheckFramebufferStatus;
-    functions->fDeleteFramebuffers = glDeleteFramebuffers;
-    functions->fDeleteRenderbuffers = glDeleteRenderbuffers;
-    functions->fFramebufferRenderbuffer = glFramebufferRenderbuffer;
-    functions->fFramebufferTexture2D = glFramebufferTexture2D;
-
-    if (version >= GR_GL_VER(3,0)) {
-#if GL_ES_VERSION_3_0
-        functions->fRenderbufferStorageMultisample = glRenderbufferStorageMultisample;
-        functions->fBlitFramebuffer = glBlitFramebuffer;
-#else
-        functions->fRenderbufferStorageMultisample = (GrGLRenderbufferStorageMultisampleProc) eglGetProcAddress("glRenderbufferStorageMultisample");
-        functions->fBlitFramebuffer = (GrGLBlitFramebufferProc) eglGetProcAddress("glBlitFramebuffer");
-#endif
-    }
-
-    if (extensions->has("GL_EXT_multisampled_render_to_texture")) {
-#if GL_EXT_multisampled_render_to_texture
-        functions->fFramebufferTexture2DMultisample = glFramebufferTexture2DMultisampleEXT;
-        functions->fRenderbufferStorageMultisampleES2EXT = glRenderbufferStorageMultisampleEXT;
-#else
-        functions->fFramebufferTexture2DMultisample = (GrGLFramebufferTexture2DMultisampleProc) eglGetProcAddress("glFramebufferTexture2DMultisampleEXT");
-        functions->fRenderbufferStorageMultisampleES2EXT = (GrGLRenderbufferStorageMultisampleProc) eglGetProcAddress("glRenderbufferStorageMultisampleEXT");
-#endif
-    } else if (extensions->has("GL_IMG_multisampled_render_to_texture")) {
-#if GL_IMG_multisampled_render_to_texture
-        functions->fFramebufferTexture2DMultisample = glFramebufferTexture2DMultisampleIMG;
-        functions->fRenderbufferStorageMultisampleES2EXT = glRenderbufferStorageMultisampleIMG;
-#else
-        functions->fFramebufferTexture2DMultisample = (GrGLFramebufferTexture2DMultisampleProc) eglGetProcAddress("glFramebufferTexture2DMultisampleIMG");
-        functions->fRenderbufferStorageMultisampleES2EXT = (GrGLRenderbufferStorageMultisampleProc) eglGetProcAddress("glRenderbufferStorageMultisampleIMG");
-#endif
-    }
-
-    functions->fGenFramebuffers = glGenFramebuffers;
-    functions->fGenRenderbuffers = glGenRenderbuffers;
-    functions->fGetFramebufferAttachmentParameteriv = glGetFramebufferAttachmentParameteriv;
-    functions->fGetRenderbufferParameteriv = glGetRenderbufferParameteriv;
-    functions->fRenderbufferStorage = glRenderbufferStorage;
-
-#if GL_OES_mapbuffer
-    functions->fMapBuffer = glMapBufferOES;
-    functions->fUnmapBuffer = glUnmapBufferOES;
-#else
-    functions->fMapBuffer = (GrGLMapBufferProc) eglGetProcAddress("glMapBufferOES");
-    functions->fUnmapBuffer = (GrGLUnmapBufferProc) eglGetProcAddress("glUnmapBufferOES");
-
-#endif
-
-    if (version >= GR_GL_VER(3,0)) {
-#if GL_ES_VERSION_3_0
-        functions->fMapBufferRange = glMapBufferRange;
-        functions->fFlushMappedBufferRange = glFlushMappedBufferRange;
-#else
-        functions->fMapBufferRange = (GrGLMapBufferRangeProc) eglGetProcAddress("glMapBufferRange");
-        functions->fFlushMappedBufferRange = (GrGLFlushMappedBufferRangeProc) eglGetProcAddress("glFlushMappedBufferRange");
-#endif
-    } else if (extensions->has("GL_EXT_map_buffer_range")) {
-#if GL_EXT_map_buffer_range
-        functions->fMapBufferRange = glMapBufferRangeEXT;
-        functions->fFlushMappedBufferRange = glFlushMappedBufferRangeEXT;
-#else
-        functions->fMapBufferRange = (GrGLMapBufferRangeProc) eglGetProcAddress("glMapBufferRangeEXT");
-        functions->fFlushMappedBufferRange = (GrGLFlushMappedBufferRangeProc) eglGetProcAddress("glFlushMappedBufferRangeEXT");
-#endif
-    }
-
-    if (extensions->has("GL_EXT_debug_marker")) {
-        functions->fInsertEventMarker = (GrGLInsertEventMarkerProc) eglGetProcAddress("glInsertEventMarker");
-        functions->fPushGroupMarker = (GrGLInsertEventMarkerProc) eglGetProcAddress("glPushGroupMarker");
-        functions->fPopGroupMarker = (GrGLPopGroupMarkerProc) eglGetProcAddress("glPopGroupMarker");
-        // The below check is here because a device has been found that has the extension string but
-        // returns NULL from the eglGetProcAddress for the functions
-        if (NULL == functions->fInsertEventMarker ||
-            NULL == functions->fPushGroupMarker ||
-            NULL == functions->fPopGroupMarker) {
-            extensions->remove("GL_EXT_debug_marker");
-        }
-    }
-
-#if GL_ES_VERSION_3_0
-    functions->fInvalidateFramebuffer = glInvalidateFramebuffer;
-    functions->fInvalidateSubFramebuffer = glInvalidateSubFramebuffer;
-#else
-    functions->fInvalidateFramebuffer = (GrGLInvalidateFramebufferProc) eglGetProcAddress("glInvalidateFramebuffer");
-    functions->fInvalidateSubFramebuffer = (GrGLInvalidateSubFramebufferProc) eglGetProcAddress("glInvalidateSubFramebuffer");
-#endif
-    functions->fInvalidateBufferData = (GrGLInvalidateBufferDataProc) eglGetProcAddress("glInvalidateBufferData");
-    functions->fInvalidateBufferSubData = (GrGLInvalidateBufferSubDataProc) eglGetProcAddress("glInvalidateBufferSubData");
-    functions->fInvalidateTexImage = (GrGLInvalidateTexImageProc) eglGetProcAddress("glInvalidateTexImage");
-    functions->fInvalidateTexSubImage = (GrGLInvalidateTexSubImageProc) eglGetProcAddress("glInvalidateTexSubImage");
-
-    return interface;
-}
+#include "gl/GrGLAssembleGLESInterface.h"
 
 static GrGLFuncPtr android_get_gl_proc(void* ctx, const char name[]) {
     SkASSERT(NULL == ctx);
     return eglGetProcAddress(name);
 }
 
-static const GrGLInterface* create_desktop_interface() {
-    return GrGLAssembleGLInterface(NULL, android_get_gl_proc);
-}
-
 const GrGLInterface* GrGLCreateNativeInterface() {
 
     const char* verStr = reinterpret_cast<const char*>(glGetString(GR_GL_VERSION));
     GrGLStandard standard = GrGLGetStandardInUseFromString(verStr);
 
     if (kGLES_GrGLStandard == standard) {
-        GrGLVersion version = GrGLGetVersionFromString(verStr);
-        GrGLExtensions extensions;
-        GrGLGetStringiProc getStringi = (GrGLGetStringiProc) eglGetProcAddress("glGetStringi");
-        if (!extensions.init(standard, glGetString, getStringi, glGetIntegerv)) {
-            return NULL;
-        }
-        GrGLInterface* interface = create_es_interface(version, &extensions);
-
-        if (NULL != interface) {
-            interface->fExtensions.swap(&extensions);
-        }
-
-        return interface;
+        return GrGLAssembleGLESInterface(NULL, android_get_gl_proc);
     } else if (kGL_GrGLStandard == standard) {
-        return create_desktop_interface();
+        return GrGLAssembleGLInterface(NULL, android_get_gl_proc);
     }
 
     return NULL;
diff --git a/src/gpu/gl/android/SkNativeGLContext_android.cpp b/src/gpu/gl/android/SkNativeGLContext_android.cpp
index 462109a..705bd8f 100644
--- a/src/gpu/gl/android/SkNativeGLContext_android.cpp
+++ b/src/gpu/gl/android/SkNativeGLContext_android.cpp
@@ -51,7 +51,7 @@
     }
 }
 
-const GrGLInterface* SkNativeGLContext::createGLContext() {
+const GrGLInterface* SkNativeGLContext::createGLContext(GrGLStandard forcedGpuAPI) {
     static const EGLint kEGLContextAttribsForOpenGL[] = {
         EGL_NONE
     };
@@ -81,9 +81,18 @@
         },
     };
 
+    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);
+
     const GrGLInterface* interface = NULL;
 
-    for (size_t api = 0; NULL == interface && api < SK_ARRAY_COUNT(kAPIs); ++api) {
+    for (size_t i = 0; NULL == interface && i < apiLimit; ++api) {
         fDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
 
         EGLint majorVersion;
diff --git a/src/gpu/gl/angle/SkANGLEGLContext.cpp b/src/gpu/gl/angle/SkANGLEGLContext.cpp
index 2600ec4..884fe7c 100644
--- a/src/gpu/gl/angle/SkANGLEGLContext.cpp
+++ b/src/gpu/gl/angle/SkANGLEGLContext.cpp
@@ -52,7 +52,10 @@
     }
 }
 
-const GrGLInterface* SkANGLEGLContext::createGLContext() {
+const GrGLInterface* SkANGLEGLContext::createGLContext(GrGLStandard forcedGpuAPI) {
+    if (kGL_GrGLStandard == forcedGpuAPI) {
+        return NULL;
+    }
 
     fDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
 
diff --git a/src/gpu/gl/debug/SkDebugGLContext.cpp b/src/gpu/gl/debug/SkDebugGLContext.cpp
index ae42227..93c0b30 100644
--- a/src/gpu/gl/debug/SkDebugGLContext.cpp
+++ b/src/gpu/gl/debug/SkDebugGLContext.cpp
@@ -8,6 +8,10 @@
 
 #include "gl/SkDebugGLContext.h"
 
-const GrGLInterface* SkDebugGLContext::createGLContext() {
+const GrGLInterface* SkDebugGLContext::createGLContext(GrGLStandard forcedGpuAPI) {
+    if (kGLES_GrGLStandard == forcedGpuAPI) {
+        return NULL;
+    }
+
     return GrGLCreateDebugInterface();
 };
diff --git a/src/gpu/gl/iOS/SkNativeGLContext_iOS.mm b/src/gpu/gl/iOS/SkNativeGLContext_iOS.mm
index a276fd0..1e11c0d 100644
--- a/src/gpu/gl/iOS/SkNativeGLContext_iOS.mm
+++ b/src/gpu/gl/iOS/SkNativeGLContext_iOS.mm
@@ -42,7 +42,11 @@
     [EAGLCTX release];
 }
 
-const GrGLInterface* SkNativeGLContext::createGLContext() {
+const GrGLInterface* SkNativeGLContext::createGLContext(GrGLStandard forcedGpuAPI) {
+    if (kGL_GrGLStandard == forcedGpuAPI) {
+        return NULL;
+    }
+
     fEAGLContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
     [EAGLContext setCurrentContext:EAGLCTX];
     
@@ -61,4 +65,4 @@
     }
 }
 
-void SkNativeGLContext::swapBuffers() const { }
\ No newline at end of file
+void SkNativeGLContext::swapBuffers() const { }
diff --git a/src/gpu/gl/mac/SkNativeGLContext_mac.cpp b/src/gpu/gl/mac/SkNativeGLContext_mac.cpp
index df316d7..fefbb4c 100644
--- a/src/gpu/gl/mac/SkNativeGLContext_mac.cpp
+++ b/src/gpu/gl/mac/SkNativeGLContext_mac.cpp
@@ -32,8 +32,11 @@
     }
 }
 
-const GrGLInterface* SkNativeGLContext::createGLContext() {
+const GrGLInterface* SkNativeGLContext::createGLContext(GrGLStandard forcedGpuAPI) {
     SkASSERT(NULL == fContext);
+    if (kGLES_GrGLStandard == forcedGpuAPI) {
+        return NULL;
+    }
 
     CGLPixelFormatAttribute attributes[] = {
 #if MAC_OS_X_VERSION_10_7
diff --git a/src/gpu/gl/mesa/SkMesaGLContext.cpp b/src/gpu/gl/mesa/SkMesaGLContext.cpp
index 0199d12..58e325d 100644
--- a/src/gpu/gl/mesa/SkMesaGLContext.cpp
+++ b/src/gpu/gl/mesa/SkMesaGLContext.cpp
@@ -53,7 +53,11 @@
 
 static const GrGLint gBOGUS_SIZE = 16;
 
-const GrGLInterface* SkMesaGLContext::createGLContext() {
+const GrGLInterface* SkMesaGLContext::createGLContext(GrGLStandard forcedGpuAPI) {
+    if (kGLES_GrGLStandard == forcedGpuAPI) {
+        return NULL;
+    }
+
     /* Create an RGBA-mode context */
 #if OSMESA_MAJOR_VERSION * 100 + OSMESA_MINOR_VERSION >= 305
     /* specify Z, stencil, accum sizes */
diff --git a/src/gpu/gl/nacl/SkNativeGLContext_nacl.cpp b/src/gpu/gl/nacl/SkNativeGLContext_nacl.cpp
index 69a74ca..334be1d 100644
--- a/src/gpu/gl/nacl/SkNativeGLContext_nacl.cpp
+++ b/src/gpu/gl/nacl/SkNativeGLContext_nacl.cpp
@@ -26,7 +26,7 @@
 void SkNativeGLContext::destroyGLContext() {
 }
 
-const GrGLInterface* SkNativeGLContext::createGLContext() {
+const GrGLInterface* SkNativeGLContext::createGLContext(GrGLStandard forcedGpuAPI) {
     return NULL;
 }
 
diff --git a/src/gpu/gl/unix/GrGLCreateNativeInterface_unix.cpp b/src/gpu/gl/unix/GrGLCreateNativeInterface_unix.cpp
index ddbfe5d..45be793 100644
--- a/src/gpu/gl/unix/GrGLCreateNativeInterface_unix.cpp
+++ b/src/gpu/gl/unix/GrGLCreateNativeInterface_unix.cpp
@@ -8,9 +8,20 @@
 
 #include "gl/GrGLInterface.h"
 #include "gl/GrGLAssembleInterface.h"
+#include "gl/GrGLUtil.h"
 
 #include <GL/glx.h>
 
+#define GET_PROC(F) functions->f ## F = (GrGL ## F ## Proc) get(ctx, "gl" #F)
+#define GET_PROC_SUFFIX(F, S) functions->f ## F = (GrGL ## F ## Proc) get(ctx, "gl" #F #S)
+#define GET_PROC_LOCAL(F) GrGL ## F ## Proc F = (GrGL ## F ## Proc) get(ctx, "gl" #F)
+
+#define GET_LINKED GET_PROC
+#define GET_LINKED_SUFFIX GET_PROC_SUFFIX
+#define USE_LINKED 0
+
+#include "gl/GrGLAssembleGLESInterface.h"
+
 static GrGLFuncPtr glx_get(void* ctx, const char name[]) {
     SkASSERT(NULL == ctx);
     SkASSERT(NULL != glXGetCurrentContext());
@@ -21,5 +32,14 @@
     if (NULL == glXGetCurrentContext()) {
         return NULL;
     }
-    return GrGLAssembleGLInterface(NULL, glx_get);
+
+    const char* verStr = reinterpret_cast<const char*>(glGetString(GR_GL_VERSION));
+    GrGLStandard standard = GrGLGetStandardInUseFromString(verStr);
+
+    if (kGLES_GrGLStandard == standard) {
+        return GrGLAssembleGLESInterface(NULL, glx_get);
+    } else if (kGL_GrGLStandard == standard) {
+        return GrGLAssembleGLInterface(NULL, glx_get);
+    }
+    return NULL;
 }
diff --git a/src/gpu/gl/unix/SkNativeGLContext_unix.cpp b/src/gpu/gl/unix/SkNativeGLContext_unix.cpp
index c4bd6f9..4da1eb2 100644
--- a/src/gpu/gl/unix/SkNativeGLContext_unix.cpp
+++ b/src/gpu/gl/unix/SkNativeGLContext_unix.cpp
@@ -66,7 +66,7 @@
     }
 }
 
-const GrGLInterface* SkNativeGLContext::createGLContext() {
+const GrGLInterface* SkNativeGLContext::createGLContext(GrGLStandard forcedGpuAPI) {
     fDisplay = XOpenDisplay(0);
 
     if (!fDisplay) {
@@ -187,60 +187,68 @@
     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)))
-    {
-        //SkDebugf("GLX_ARB_create_context not found."
-        //       " Using old-style GLX context.\n");
-#ifdef GLX_1_3
-        fContext = glXCreateNewContext(fDisplay, bestFbc, GLX_RGBA_TYPE, 0, True);
-#else
-        fContext = glXCreateContext(fDisplay, vi, 0, True);
-#endif
 
+    if (!gluCheckExtension(reinterpret_cast<const GLubyte*>("GLX_ARB_create_context"),
+                           reinterpret_cast<const GLubyte*>(glxExts))) {
+        if (kGLES_GrGLStandard != forcedGpuAPI) {
+#ifdef GLX_1_3
+            fContext = glXCreateNewContext(fDisplay, bestFbc, GLX_RGBA_TYPE, 0, True);
+#else
+            fContext = glXCreateContext(fDisplay, vi, 0, True);
+#endif
+        }
     }
 #ifdef GLX_1_3
     else {
         //SkDebugf("Creating context.\n");
-
         PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB =
             (PFNGLXCREATECONTEXTATTRIBSARBPROC) glXGetProcAddressARB((GrGLubyte*)"glXCreateContextAttribsARB");
-        int context_attribs[] = {
+
+        static const int context_attribs_gl[] = {
             GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
             GLX_CONTEXT_MINOR_VERSION_ARB, 0,
-            //GLX_CONTEXT_FLAGS_ARB        , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
             None
         };
-        fContext = glXCreateContextAttribsARB(
-            fDisplay, bestFbc, 0, True, context_attribs
-        );
+        static const int context_attribs_gl_fallback[] = {
+            GLX_CONTEXT_MAJOR_VERSION_ARB, 1,
+            GLX_CONTEXT_MINOR_VERSION_ARB, 0,
+            None
+        };
+        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
+        };
 
-        // Sync to ensure any errors generated are processed.
-        XSync(fDisplay, False);
-        if (!ctxErrorOccurred && fContext) {
-           //SkDebugf( "Created GL 3.0 context.\n" );
+        if (kGLES_GrGLStandard == forcedGpuAPI) {
+            if (gluCheckExtension(
+                    reinterpret_cast<const GLubyte*>("GLX_EXT_create_context_es2_profile"),
+                    reinterpret_cast<const GLubyte*>(glxExts))) {
+                fContext = glXCreateContextAttribsARB(fDisplay, bestFbc, 0, True,
+                                                      context_attribs_gles);
+            }
         } else {
-            // 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.
+            fContext = glXCreateContextAttribsARB(fDisplay, bestFbc, 0, True, context_attribs_gl);
 
-            // GLX_CONTEXT_MAJOR_VERSION_ARB = 1
-            context_attribs[1] = 1;
-            // GLX_CONTEXT_MINOR_VERSION_ARB = 0
-            context_attribs[3] = 0;
+            // Sync to ensure any errors generated are processed.
+            XSync(fDisplay, False);
+            if (ctxErrorOccurred || !fContext) {
+                // 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.
 
-            ctxErrorOccurred = false;
+                ctxErrorOccurred = false;
 
-            //SkDebugf("Failed to create GL 3.0 context."
-            //       " Using old-style GLX context.\n");
-            fContext = glXCreateContextAttribsARB(
-                fDisplay, bestFbc, 0, True, context_attribs
-            );
+                fContext = glXCreateContextAttribsARB(fDisplay, bestFbc, 0, True,
+                                                      context_attribs_gl_fallback);
+            }
         }
     }
 #endif
diff --git a/src/gpu/gl/win/GrGLCreateNativeInterface_win.cpp b/src/gpu/gl/win/GrGLCreateNativeInterface_win.cpp
index 6adaf19..4a8af51 100644
--- a/src/gpu/gl/win/GrGLCreateNativeInterface_win.cpp
+++ b/src/gpu/gl/win/GrGLCreateNativeInterface_win.cpp
@@ -8,9 +8,22 @@
 
 #include "gl/GrGLInterface.h"
 #include "gl/GrGLAssembleInterface.h"
+#include "gl/GrGLUtil.h"
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 
+#include <GL/gl.h>
+
+#define GET_PROC(F) functions->f ## F = (GrGL ## F ## Proc) get(ctx, "gl" #F)
+#define GET_PROC_SUFFIX(F, S) functions->f ## F = (GrGL ## F ## Proc) get(ctx, "gl" #F #S)
+#define GET_PROC_LOCAL(F) GrGL ## F ## Proc F = (GrGL ## F ## Proc) get(ctx, "gl" #F)
+
+#define GET_LINKED GET_PROC
+#define GET_LINKED_SUFFIX GET_PROC_SUFFIX
+#define USE_LINKED 0
+
+#include "gl/GrGLAssembleGLESInterface.h"
+
 class AutoLibraryUnload {
 public:
     AutoLibraryUnload(const char* moduleName) {
@@ -70,5 +83,13 @@
         return NULL;
     }
 
-    return GrGLAssembleGLInterface(&getter, win_get_gl_proc);
+    const char* verStr = reinterpret_cast<const char*>(glGetString(GR_GL_VERSION));
+    GrGLStandard standard = GrGLGetStandardInUseFromString(verStr);
+
+    if (kGLES_GrGLStandard == standard) {
+        return GrGLAssembleGLESInterface(&getter, win_get_gl_proc);
+    } else if (kGL_GrGLStandard == standard) {
+        return GrGLAssembleGLInterface(&getter, win_get_gl_proc);
+    }
+    return NULL;
 }
diff --git a/src/gpu/gl/win/SkNativeGLContext_win.cpp b/src/gpu/gl/win/SkNativeGLContext_win.cpp
index bae97a78..f085fdc 100644
--- a/src/gpu/gl/win/SkNativeGLContext_win.cpp
+++ b/src/gpu/gl/win/SkNativeGLContext_win.cpp
@@ -47,7 +47,7 @@
     }
 }
 
-const GrGLInterface* SkNativeGLContext::createGLContext() {
+const GrGLInterface* SkNativeGLContext::createGLContext(GrGLStandard forcedGpuAPI) {
     HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL);
 
     if (!gWC) {
@@ -85,9 +85,13 @@
         this->destroyGLContext();
         return NULL;
     }
+    // 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;
 
-    // Requesting a Core profile would bar us from using NVPR. So we pass false.
-    if (!(fGlRenderContext = SkCreateWGLContext(fDeviceContext, 0, false))) {
+    if (!(fGlRenderContext = SkCreateWGLContext(fDeviceContext, 0, contextType))) {
         SkDebugf("Could not create rendering context.\n");
         this->destroyGLContext();
         return NULL;
diff --git a/src/utils/win/SkWGL_win.cpp b/src/utils/win/SkWGL_win.cpp
index 3b1966d..a8552a8 100644
--- a/src/utils/win/SkWGL_win.cpp
+++ b/src/utils/win/SkWGL_win.cpp
@@ -245,7 +245,7 @@
     wglMakeCurrent(prevDC, prevGLRC);
 }
 
-HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, bool preferCoreProfile) {
+HGLRC SkCreateWGLContext(HDC dc, int msaaSampleCount, SkWGLContextRequest contextType) {
     SkWGLExtensions extensions;
     if (!extensions.hasExtension(dc, "WGL_ARB_pixel_format")) {
         return NULL;
@@ -307,27 +307,44 @@
     }
 
     HGLRC glrc = NULL;
-    if (preferCoreProfile && extensions.hasExtension(dc, "WGL_ARB_create_context")) {
-        static const int kCoreGLVersions[] = {
-            4, 3,
-            4, 2,
-            4, 1,
-            4, 0,
-            3, 3,
-            3, 2,
-        };
-        int coreProfileAttribs[] = {
-            SK_WGL_CONTEXT_MAJOR_VERSION, -1,
-            SK_WGL_CONTEXT_MINOR_VERSION, -1,
-            SK_WGL_CONTEXT_PROFILE_MASK,  SK_WGL_CONTEXT_CORE_PROFILE_BIT,
+    if (kGLES_SkWGLContextRequest == contextType) {
+        if (!extensions.hasExtension(dc, "WGL_EXT_create_context_es2_profile")) {
+            return NULL;
+        }
+        static const int glesAttribs[] = {
+            SK_WGL_CONTEXT_MAJOR_VERSION, 3,
+            SK_WGL_CONTEXT_MINOR_VERSION, 0,
+            SK_WGL_CONTEXT_PROFILE_MASK,  SK_WGL_CONTEXT_ES2_PROFILE_BIT,
             0,
         };
-        for (int v = 0; v < SK_ARRAY_COUNT(kCoreGLVersions) / 2; ++v) {
-            coreProfileAttribs[1] = kCoreGLVersions[2 * v];
-            coreProfileAttribs[3] = kCoreGLVersions[2 * v + 1];
-            glrc = extensions.createContextAttribs(dc, NULL, coreProfileAttribs);
-            if (NULL != glrc) {
-                break;
+        glrc = extensions.createContextAttribs(dc, NULL, glesAttribs);
+        if (NULL == glrc) {
+            return NULL;
+        }
+    } else {
+        if (kGLPreferCoreProfile_SkWGLContextRequest == contextType &&
+            extensions.hasExtension(dc, "WGL_ARB_create_context")) {
+            static const int kCoreGLVersions[] = {
+                4, 3,
+                4, 2,
+                4, 1,
+                4, 0,
+                3, 3,
+                3, 2,
+            };
+            int coreProfileAttribs[] = {
+                SK_WGL_CONTEXT_MAJOR_VERSION, -1,
+                SK_WGL_CONTEXT_MINOR_VERSION, -1,
+                SK_WGL_CONTEXT_PROFILE_MASK,  SK_WGL_CONTEXT_CORE_PROFILE_BIT,
+                0,
+            };
+            for (int v = 0; v < SK_ARRAY_COUNT(kCoreGLVersions) / 2; ++v) {
+                coreProfileAttribs[1] = kCoreGLVersions[2 * v];
+                coreProfileAttribs[3] = kCoreGLVersions[2 * v + 1];
+                glrc = extensions.createContextAttribs(dc, NULL, coreProfileAttribs);
+                if (NULL != glrc) {
+                    break;
+                }
             }
         }
     }
diff --git a/src/views/win/SkOSWindow_win.cpp b/src/views/win/SkOSWindow_win.cpp
index 027bc66..1b47dea 100644
--- a/src/views/win/SkOSWindow_win.cpp
+++ b/src/views/win/SkOSWindow_win.cpp
@@ -331,7 +331,8 @@
 bool SkOSWindow::attachGL(int msaaSampleCount, AttachmentInfo* info) {
     HDC dc = GetDC((HWND)fHWND);
     if (NULL == fHGLRC) {
-        fHGLRC = SkCreateWGLContext(dc, msaaSampleCount, false);
+        fHGLRC = SkCreateWGLContext(dc, msaaSampleCount,
+                kGLPreferCompatibilityProfile_SkWGLContextRequest);
         if (NULL == fHGLRC) {
             return false;
         }
diff --git a/tools/PictureRenderer.h b/tools/PictureRenderer.h
index efe118f..b4e08aa 100644
--- a/tools/PictureRenderer.h
+++ b/tools/PictureRenderer.h
@@ -165,7 +165,11 @@
     /**
      * Set the backend type. Returns true on success and false on failure.
      */
+#if SK_SUPPORT_GPU
+    bool setDeviceType(SkDeviceTypes deviceType, GrGLStandard gpuAPI = kNone_GrGLStandard) {
+#else
     bool setDeviceType(SkDeviceTypes deviceType) {
+#endif
         fDeviceType = deviceType;
 #if SK_SUPPORT_GPU
         // In case this function is called more than once
@@ -200,7 +204,7 @@
                 return false;
         }
 #if SK_SUPPORT_GPU
-        fGrContext = fGrContextFactory.get(glContextType);
+        fGrContext = fGrContextFactory.get(glContextType, gpuAPI);
         if (NULL == fGrContext) {
             return false;
         } else {
diff --git a/tools/PictureRenderingFlags.cpp b/tools/PictureRenderingFlags.cpp
index 5acec26..4ffa16f 100644
--- a/tools/PictureRenderingFlags.cpp
+++ b/tools/PictureRenderingFlags.cpp
@@ -26,6 +26,8 @@
 
 
 #if SK_SUPPORT_GPU
+static const char kGpuAPINameGL[] = "gl";
+static const char kGpuAPINameGLES[] = "gles";
 #define GPU_CONFIG_STRING "|gpu|msaa4|msaa16|nvprmsaa4|nvprmsaa16"
 #else
 #define GPU_CONFIG_STRING ""
@@ -74,6 +76,12 @@
 DEFINE_string(tiles, "", "Used with --mode copyTile to specify number of tiles per larger tile "
               "in the x and y directions.");
 DEFINE_string(viewport, "", "width height: Set the viewport.");
+#if SK_SUPPORT_GPU
+DEFINE_string(gpuAPI, "", "Force use of specific gpu API.  Using \"gl\" "
+              "forces OpenGL API. Using \"gles\" forces OpenGL ES API. "
+              "Defaults to empty string, which selects the API native to the "
+              "system.");
+#endif
 
 sk_tools::PictureRenderer* parseRenderer(SkString& error, PictureTool tool) {
     error.reset();
@@ -261,6 +269,21 @@
     sk_tools::PictureRenderer::SkDeviceTypes deviceType =
         sk_tools::PictureRenderer::kBitmap_DeviceType;
 #if SK_SUPPORT_GPU
+    GrGLStandard gpuAPI = kNone_GrGLStandard;
+    if (1 == FLAGS_gpuAPI.count()) {
+        if (FLAGS_gpuAPI.contains(kGpuAPINameGL)) {
+            gpuAPI = kGL_GrGLStandard;
+        } else if (FLAGS_gpuAPI.contains(kGpuAPINameGLES)) {
+            gpuAPI = kGLES_GrGLStandard;
+        } else {
+            error.printf("--gpuAPI invalid api value.\n");
+            return NULL;
+        }
+    } else if (FLAGS_gpuAPI.count() > 1) {
+        error.printf("--gpuAPI invalid api value.\n");
+        return NULL;
+    }
+
     int sampleCount = 0;
 #endif
     if (FLAGS_config.count() > 0) {
@@ -330,7 +353,14 @@
             error.printf("%s is not a valid mode for --config\n", FLAGS_config[0]);
             return NULL;
         }
-        renderer->setDeviceType(deviceType);
+#if SK_SUPPORT_GPU
+        if (!renderer->setDeviceType(deviceType, gpuAPI)) {
+#else
+        if (!renderer->setDeviceType(deviceType)) {
+#endif
+            error.printf("Could not create backend for --config %s\n", FLAGS_config[0]);
+            return NULL;
+        }
 #if SK_SUPPORT_GPU
         renderer->setSampleCount(sampleCount);
 #endif