Incorporate glStencilThenCover* nvpr methods

Adds the glStencilThenCover* nvpr methods to GrGLInterface and starts
using them. When drawing multible paths, this will make it so we only
have to send the index/transform data once. It will also allow the
driver to save time internally.

The glStencilThenCover* methods are a newer addition, so they aren't
available on every driver. In the event that they are not present, we
emulate them using the existing glStencil*/glCover* methods.

BUG=skia:
R=markkilgard@gmail.com, bsalomon@google.com

Author: cdalton@nvidia.com

Review URL: https://codereview.chromium.org/423173004
diff --git a/include/gpu/gl/GrGLFunctions.h b/include/gpu/gl/GrGLFunctions.h
index 093c7d1..584ad27 100644
--- a/include/gpu/gl/GrGLFunctions.h
+++ b/include/gpu/gl/GrGLFunctions.h
@@ -245,6 +245,10 @@
     typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLCoverStrokePathProc)(GrGLuint name, GrGLenum coverMode);
     typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLCoverFillPathInstancedProc)(GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths, GrGLuint pathBase, GrGLenum coverMode, GrGLenum transformType, const GrGLfloat *transformValues);
     typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLCoverStrokePathInstancedProc)(GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths, GrGLuint pathBase, GrGLenum coverMode, GrGLenum transformType, const GrGLfloat* transformValues);
+    typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLStencilThenCoverFillPathProc)(GrGLuint path, GrGLenum fillMode, GrGLuint mask, GrGLenum coverMode);
+    typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLStencilThenCoverStrokePathProc)(GrGLuint path, GrGLint reference, GrGLuint mask, GrGLenum coverMode);
+    typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLStencilThenCoverFillPathInstancedProc)(GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths, GrGLuint pathBase, GrGLenum fillMode, GrGLuint mask, GrGLenum coverMode, GrGLenum transformType, const GrGLfloat *transformValues);
+    typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLStencilThenCoverStrokePathInstancedProc)(GrGLsizei numPaths, GrGLenum pathNameType, const GrGLvoid *paths, GrGLuint pathBase, GrGLint reference, GrGLuint mask, GrGLenum coverMode, GrGLenum transformType, const GrGLfloat *transformValues);
 
     typedef GrGLvoid (GR_GL_FUNCTION_TYPE* GrGLProgramPathFragmentInputGenProc)(GrGLuint program, GrGLint location, GrGLenum genMode, GrGLint components,const GrGLfloat *coeffs);
 }  // extern "C"
diff --git a/include/gpu/gl/GrGLInterface.h b/include/gpu/gl/GrGLInterface.h
index 515f34d..835b374 100644
--- a/include/gpu/gl/GrGLInterface.h
+++ b/include/gpu/gl/GrGLInterface.h
@@ -335,6 +335,10 @@
         GLPtr<GrGLCoverStrokePathProc> fCoverStrokePath;
         GLPtr<GrGLCoverFillPathInstancedProc> fCoverFillPathInstanced;
         GLPtr<GrGLCoverStrokePathInstancedProc> fCoverStrokePathInstanced;
+        GLPtr<GrGLStencilThenCoverFillPathProc> fStencilThenCoverFillPath;
+        GLPtr<GrGLStencilThenCoverStrokePathProc> fStencilThenCoverStrokePath;
+        GLPtr<GrGLStencilThenCoverFillPathInstancedProc> fStencilThenCoverFillPathInstanced;
+        GLPtr<GrGLStencilThenCoverStrokePathInstancedProc> fStencilThenCoverStrokePathInstanced;
         GLPtr<GrGLProgramPathFragmentInputGenProc> fProgramPathFragmentInputGen;
     } fFunctions;
 
diff --git a/src/gpu/gl/GrGLAssembleGLESInterface.h b/src/gpu/gl/GrGLAssembleGLESInterface.h
index d3ebebd..8162c2d 100644
--- a/src/gpu/gl/GrGLAssembleGLESInterface.h
+++ b/src/gpu/gl/GrGLAssembleGLESInterface.h
@@ -276,6 +276,10 @@
         GET_PROC_SUFFIX(CoverStrokePath, NV);
         GET_PROC_SUFFIX(CoverFillPathInstanced, NV);
         GET_PROC_SUFFIX(CoverStrokePathInstanced, NV);
+        GET_PROC_SUFFIX(StencilThenCoverFillPath, NV);
+        GET_PROC_SUFFIX(StencilThenCoverStrokePath, NV);
+        GET_PROC_SUFFIX(StencilThenCoverFillPathInstanced, NV);
+        GET_PROC_SUFFIX(StencilThenCoverStrokePathInstanced, NV);
         GET_PROC_SUFFIX(ProgramPathFragmentInputGen, NV);
     }
 
diff --git a/src/gpu/gl/GrGLAssembleInterface.cpp b/src/gpu/gl/GrGLAssembleInterface.cpp
index c6b3f93..4ae50ba 100644
--- a/src/gpu/gl/GrGLAssembleInterface.cpp
+++ b/src/gpu/gl/GrGLAssembleInterface.cpp
@@ -14,6 +14,12 @@
 #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)
 
+// The glStencilThenCover* methods are a new addition to NV_path_rendering. They
+// aren't available on all drivers. In the event that they are not present, this
+// function can be used to add methods to the given GrGLInterface that emulate
+// them using the existing glStencil*/glCover* methods.
+static void emulate_nvpr_stencil_then_cover(GrGLInterface*);
+
 const GrGLInterface* GrGLAssembleGLInterface(void* ctx, GrGLGetProc get) {
     GET_PROC_LOCAL(GetString);
     GET_PROC_LOCAL(GetStringi);
@@ -239,7 +245,18 @@
         GET_PROC_SUFFIX(CoverStrokePath, NV);
         GET_PROC_SUFFIX(CoverFillPathInstanced, NV);
         GET_PROC_SUFFIX(CoverStrokePathInstanced, NV);
+        GET_PROC_SUFFIX(StencilThenCoverFillPath, NV);
+        GET_PROC_SUFFIX(StencilThenCoverStrokePath, NV);
+        GET_PROC_SUFFIX(StencilThenCoverFillPathInstanced, NV);
+        GET_PROC_SUFFIX(StencilThenCoverStrokePathInstanced, NV);
         GET_PROC_SUFFIX(ProgramPathFragmentInputGen, NV);
+
+        if (NULL == interface->fFunctions.fStencilThenCoverFillPath ||
+            NULL == interface->fFunctions.fStencilThenCoverStrokePath ||
+            NULL == interface->fFunctions.fStencilThenCoverFillPathInstanced ||
+            NULL == interface->fFunctions.fStencilThenCoverFillPathInstanced) {
+            emulate_nvpr_stencil_then_cover(interface);
+        }
     }
 
     if (extensions.has("GL_EXT_debug_marker")) {
@@ -266,3 +283,101 @@
 
     return interface;
 }
+
+static GrGLStencilFillPathProc gStencilFillPath;
+static GrGLCoverFillPathProc gCoverFillPath;
+static GrGLvoid GR_GL_FUNCTION_TYPE stencil_then_cover_fill_path(
+                                        GrGLuint path, GrGLenum fillMode,
+                                        GrGLuint mask, GrGLenum coverMode) {
+    gStencilFillPath(path, fillMode, mask);
+    gCoverFillPath(path, coverMode);
+}
+
+
+static GrGLStencilStrokePathProc gStencilStrokePath;
+static GrGLCoverStrokePathProc gCoverStrokePath;
+static GrGLvoid GR_GL_FUNCTION_TYPE stencil_then_cover_stroke_path(
+                                        GrGLuint path, GrGLint reference,
+                                        GrGLuint mask, GrGLenum coverMode) {
+    gStencilStrokePath(path, reference, mask);
+    gCoverStrokePath(path, coverMode);
+}
+
+static GrGLStencilFillPathInstancedProc gStencilFillPathInstanced;
+static GrGLCoverFillPathInstancedProc gCoverFillPathInstanced;
+static GrGLvoid GR_GL_FUNCTION_TYPE stencil_then_cover_fill_path_instanced(
+                                        GrGLsizei numPaths, GrGLenum pathNameType,
+                                        const GrGLvoid *paths, GrGLuint pathBase,
+                                        GrGLenum fillMode, GrGLuint mask,
+                                        GrGLenum coverMode, GrGLenum transformType,
+                                        const GrGLfloat *transformValues) {
+    gStencilFillPathInstanced(numPaths, pathNameType, paths, pathBase,
+                              fillMode, mask, transformType, transformValues);
+    gCoverFillPathInstanced(numPaths, pathNameType, paths, pathBase,
+                            coverMode, transformType, transformValues);
+}
+
+static GrGLStencilStrokePathInstancedProc gStencilStrokePathInstanced;
+static GrGLCoverStrokePathInstancedProc gCoverStrokePathInstanced;
+static GrGLvoid GR_GL_FUNCTION_TYPE stencil_then_cover_stroke_path_instanced(
+                                        GrGLsizei numPaths, GrGLenum pathNameType,
+                                        const GrGLvoid *paths, GrGLuint pathBase,
+                                        GrGLint reference, GrGLuint mask,
+                                        GrGLenum coverMode, GrGLenum transformType,
+                                        const GrGLfloat *transformValues) {
+    gStencilStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
+                                reference, mask, transformType, transformValues);
+    gCoverStrokePathInstanced(numPaths, pathNameType, paths, pathBase,
+                              coverMode, transformType, transformValues);
+}
+
+static void emulate_nvpr_stencil_then_cover(GrGLInterface* interface) {
+    if (NULL == gStencilFillPath) {
+        gStencilFillPath = (GrGLStencilFillPathProc)interface->fFunctions.fStencilFillPath;
+    }
+    if (NULL == gCoverFillPath) {
+        gCoverFillPath = (GrGLCoverFillPathProc)interface->fFunctions.fCoverFillPath;
+    }
+    if (NULL == gStencilStrokePath) {
+        gStencilStrokePath = (GrGLStencilStrokePathProc)interface->fFunctions.fStencilStrokePath;
+    }
+    if (NULL == gCoverStrokePath) {
+        gCoverStrokePath = (GrGLCoverStrokePathProc)interface->fFunctions.fCoverStrokePath;
+    }
+    if (NULL == gStencilFillPathInstanced) {
+        gStencilFillPathInstanced = (GrGLStencilFillPathInstancedProc)
+            interface->fFunctions.fStencilFillPathInstanced;
+    }
+    if (NULL == gCoverFillPathInstanced) {
+        gCoverFillPathInstanced = (GrGLCoverFillPathInstancedProc)
+            interface->fFunctions.fCoverFillPathInstanced;
+    }
+    if (NULL == gStencilStrokePathInstanced) {
+        gStencilStrokePathInstanced = (GrGLStencilStrokePathInstancedProc)
+            interface->fFunctions.fStencilStrokePathInstanced;
+    }
+    if (NULL == gCoverStrokePathInstanced) {
+        gCoverStrokePathInstanced = (GrGLCoverStrokePathInstancedProc)
+            interface->fFunctions.fCoverStrokePathInstanced;
+    }
+
+    if (interface->fFunctions.fStencilFillPath != gStencilFillPath ||
+        interface->fFunctions.fCoverFillPath != gCoverFillPath ||
+        interface->fFunctions.fStencilStrokePath != gStencilStrokePath ||
+        interface->fFunctions.fCoverStrokePath != gCoverStrokePath ||
+        interface->fFunctions.fStencilFillPathInstanced != gStencilFillPathInstanced ||
+        interface->fFunctions.fCoverFillPathInstanced != gCoverFillPathInstanced ||
+        interface->fFunctions.fStencilStrokePathInstanced != gStencilStrokePathInstanced ||
+        interface->fFunctions.fCoverStrokePathInstanced != gCoverStrokePathInstanced) {
+        // While not every windowing system requires GetProcAddress to return
+        // the same addresses in different contexts, it is guaranteed to do so
+        // in any context that supports NV_path_rendering.
+        SkFAIL("GetProcAddress returned different addresses for the same nvpr functions");
+        return;
+    }
+
+    interface->fFunctions.fStencilThenCoverFillPath = &stencil_then_cover_fill_path;
+    interface->fFunctions.fStencilThenCoverStrokePath = &stencil_then_cover_stroke_path;
+    interface->fFunctions.fStencilThenCoverFillPathInstanced = &stencil_then_cover_fill_path_instanced;
+    interface->fFunctions.fStencilThenCoverStrokePathInstanced = &stencil_then_cover_stroke_path_instanced;
+}
diff --git a/src/gpu/gl/GrGLInterface.cpp b/src/gpu/gl/GrGLInterface.cpp
index 823b73e..e9ba32e 100644
--- a/src/gpu/gl/GrGLInterface.cpp
+++ b/src/gpu/gl/GrGLInterface.cpp
@@ -467,7 +467,11 @@
             NULL == fFunctions.fCoverFillPath ||
             NULL == fFunctions.fCoverStrokePath ||
             NULL == fFunctions.fCoverFillPathInstanced ||
-            NULL == fFunctions.fCoverStrokePathInstanced) {
+            NULL == fFunctions.fCoverStrokePathInstanced ||
+            NULL == fFunctions.fStencilThenCoverFillPath ||
+            NULL == fFunctions.fStencilThenCoverStrokePath ||
+            NULL == fFunctions.fStencilThenCoverFillPathInstanced ||
+            NULL == fFunctions.fStencilThenCoverStrokePathInstanced) {
             RETURN_FALSE_INTERFACE
         }
         // Currently ProgramPathFragmentInputGen is not used on
diff --git a/src/gpu/gl/GrGpuGL.cpp b/src/gpu/gl/GrGpuGL.cpp
index f079abc..404e7ab 100644
--- a/src/gpu/gl/GrGpuGL.cpp
+++ b/src/gpu/gl/GrGpuGL.cpp
@@ -1894,20 +1894,23 @@
         gr_stencil_op_to_gl_path_rendering_fill_mode(fHWPathStencilSettings.passOp(GrStencilSettings::kFront_Face));
     GrGLint writeMask = fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
 
-    if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
-        GL_CALL(StencilFillPath(id, fillMode, writeMask));
-    }
-    if (stroke.needToApply()) {
-        GL_CALL(StencilStrokePath(id, 0xffff, writeMask));
-    }
-
     if (nonInvertedFill == fill) {
         if (stroke.needToApply()) {
-            GL_CALL(CoverStrokePath(id, GR_GL_BOUNDING_BOX));
+            if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
+                GL_CALL(StencilFillPath(id, fillMode, writeMask));
+            }
+            GL_CALL(StencilThenCoverStrokePath(id, 0xffff, writeMask, GR_GL_BOUNDING_BOX));
         } else {
-            GL_CALL(CoverFillPath(id, GR_GL_BOUNDING_BOX));
+            GL_CALL(StencilThenCoverFillPath(id, fillMode, writeMask, GR_GL_BOUNDING_BOX));
         }
     } else {
+        if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
+            GL_CALL(StencilFillPath(id, fillMode, writeMask));
+        }
+        if (stroke.needToApply()) {
+            GL_CALL(StencilStrokePath(id, 0xffff, writeMask));
+        }
+
         GrDrawState* drawState = this->drawState();
         GrDrawState::AutoViewMatrixRestore avmr;
         SkRect bounds = SkRect::MakeLTRB(0, 0,
@@ -1953,30 +1956,38 @@
     GrGLint writeMask =
         fHWPathStencilSettings.writeMask(GrStencilSettings::kFront_Face);
 
-    if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
-        GL_CALL(StencilFillPathInstanced(count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode,
-                                         writeMask, gXformType2GLType[transformsType],
-                                         transforms));
-    }
-    if (stroke.needToApply()) {
-        GL_CALL(StencilStrokePathInstanced(count, GR_GL_UNSIGNED_INT, indices, baseID, 0xffff,
-                                           writeMask, gXformType2GLType[transformsType],
-                                           transforms));
-    }
-
     if (nonInvertedFill == fill) {
         if (stroke.needToApply()) {
-            GL_CALL(CoverStrokePathInstanced(
-                        count, GR_GL_UNSIGNED_INT, indices, baseID,
+            if (SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
+                GL_CALL(StencilFillPathInstanced(
+                            count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode,
+                            writeMask, gXformType2GLType[transformsType],
+                            transforms));
+            }
+            GL_CALL(StencilThenCoverStrokePathInstanced(
+                        count, GR_GL_UNSIGNED_INT, indices, baseID, 0xffff, writeMask,
                         GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
                         gXformType2GLType[transformsType], transforms));
         } else {
-            GL_CALL(CoverFillPathInstanced(
-                        count, GR_GL_UNSIGNED_INT, indices, baseID,
+            GL_CALL(StencilThenCoverFillPathInstanced(
+                        count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode, writeMask,
                         GR_GL_BOUNDING_BOX_OF_BOUNDING_BOXES,
                         gXformType2GLType[transformsType], transforms));
         }
     } else {
+        if (stroke.isFillStyle() || SkStrokeRec::kStrokeAndFill_Style == stroke.getStyle()) {
+            GL_CALL(StencilFillPathInstanced(
+                        count, GR_GL_UNSIGNED_INT, indices, baseID, fillMode,
+                        writeMask, gXformType2GLType[transformsType],
+                        transforms));
+        }
+        if (stroke.needToApply()) {
+            GL_CALL(StencilStrokePathInstanced(
+                        count, GR_GL_UNSIGNED_INT, indices, baseID, 0xffff,
+                        writeMask, gXformType2GLType[transformsType],
+                        transforms));
+        }
+
         GrDrawState* drawState = this->drawState();
         GrDrawState::AutoViewMatrixRestore avmr;
         SkRect bounds = SkRect::MakeLTRB(0, 0,