Implement SkGLContext swapBuffers with fence syncs

Improves the GPU measuring accuracy of nanobench by using fence syncs.
Fence syncs are very widely supported and available on almost every
platform.

NO_MERGE_BUILDS
BUG=skia:

Review URL: https://codereview.chromium.org/1194783003
diff --git a/include/gpu/gl/GrGLInterface.h b/include/gpu/gl/GrGLInterface.h
index e510551..8c72526 100644
--- a/include/gpu/gl/GrGLInterface.h
+++ b/include/gpu/gl/GrGLInterface.h
@@ -30,6 +30,8 @@
  * comments in GrGLConfig.h
  */
 
+typedef void(*GrGLFuncPtr)();
+
 struct GrGLInterface;
 
 const GrGLInterface* GrGLDefaultInterface();
diff --git a/include/gpu/gl/SkGLContext.h b/include/gpu/gl/SkGLContext.h
index 6ca7bf5..8209c31 100644
--- a/include/gpu/gl/SkGLContext.h
+++ b/include/gpu/gl/SkGLContext.h
@@ -9,6 +9,7 @@
 #define SkGLContext_DEFINED
 
 #include "GrGLInterface.h"
+#include "../../src/gpu/SkGpuFenceSync.h"
 
 /**
  * Create an offscreen opengl context with an RGBA8 / 8bit stencil FBO.
@@ -25,19 +26,32 @@
 
     const GrGLInterface* gl() const { return fGL.get(); }
 
-    virtual void makeCurrent() const = 0;
+    bool fenceSyncSupport() const { return SkToBool(fFenceSync); }
+
+    bool getMaxGpuFrameLag(int* maxFrameLag) const {
+        if (!fFenceSync) {
+            return false;
+        }
+        *maxFrameLag = kMaxFrameLag;
+        return true;
+    }
+
+    void makeCurrent() const;
 
     /**
-     * The primary purpose of this function it to provide a means of scheduling
+     * 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 drawing surface provided by the platform is double buffered this
-     * call will cause the platform to swap which buffer is currently being
-     * targeted.  If the current surface does not include a back buffer, this
-     * call has no effect.
+     * 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.
      */
-    virtual void swapBuffers() const = 0;
+    void swapBuffers();
 
     /**
      * This notifies the context that we are deliberately testing abandoning
@@ -47,13 +61,37 @@
      */
     void testAbandon();
 
+    class GLFenceSync;  // SkGpuFenceSync implementation that uses the OpenGL functionality.
+
 protected:
     SkGLContext();
 
+    /*
+     * 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.
+
     typedef SkRefCnt INHERITED;
 };
 
diff --git a/include/gpu/gl/SkNullGLContext.h b/include/gpu/gl/SkNullGLContext.h
index ca71dde..1f63438 100644
--- a/include/gpu/gl/SkNullGLContext.h
+++ b/include/gpu/gl/SkNullGLContext.h
@@ -13,8 +13,6 @@
 class SK_API SkNullGLContext : public SkGLContext {
 public:
     ~SkNullGLContext() override;
-    void makeCurrent() const override;
-    void swapBuffers() const override {};
 
     static SkNullGLContext* Create(GrGLStandard);
 
@@ -23,6 +21,10 @@
 private:
     SkNullGLContext();
 
+    void onPlatformMakeCurrent() const override;
+    void onPlatformSwapBuffers() const override {}
+    GrGLFuncPtr onPlatformGetProcAddress(const char*) const override { return NULL; }
+
     ContextState* fState;
 };
 
diff --git a/include/gpu/gl/angle/SkANGLEGLContext.h b/include/gpu/gl/angle/SkANGLEGLContext.h
index f54f29e..8850cd0 100644
--- a/include/gpu/gl/angle/SkANGLEGLContext.h
+++ b/include/gpu/gl/angle/SkANGLEGLContext.h
@@ -15,8 +15,6 @@
 class SkANGLEGLContext : public SkGLContext {
 public:
     ~SkANGLEGLContext() override;
-    void makeCurrent() const override;
-    void swapBuffers() const override;
 
     static SkANGLEGLContext* Create(GrGLStandard forcedGpuAPI) {
         if (kGL_GrGLStandard == forcedGpuAPI) {
@@ -37,6 +35,10 @@
     SkANGLEGLContext();
     void destroyGLContext();
 
+    void onPlatformMakeCurrent() const override;
+    void onPlatformSwapBuffers() const override;
+    GrGLFuncPtr onPlatformGetProcAddress(const char* name) const override;
+
     void* fContext;
     void* fDisplay;
     void* fSurface;