Implement NV_path_rendering on OpenGL ES

Implement support for NV_path_rendering on OpenGL ES. Use
glProgramPathFragmentInputGenNV function call instead of glPathTexGenNV to
communicate transforms to fragment shader.

The intention is that the NVPR paths will be drawn with the same shader program
as non-NVPR geometry. For NVPR calls, the GPU will skip the vertex shader and
just run the fragment shader.

After program is linked, query the locations of the fragment shader inputs with
glGetResourceLocation. The location will be used to set the transforms with
glProgramPathFragmentInputGenNV.

The functions and their workings are documented in:

glProgramPathFragmentInputGenNV
https://www.opengl.org/registry/specs/NV/path_rendering.txt
(note: addition as of API version 1.3)

glGetResourceLocation
https://www.opengl.org/registry/specs/ARB/program_interface_query.txt
http://www.opengl.org/registry/doc/glspec44.core.pdf
(function is in core Open GL 4.4)

Note: glProgramPathFragmentInputGenNV could be used also for OpenGL. However,
using seems to trigger a bug in the driver. Disable this feature on OpenGL at
least until the driver is fixed and released. The bug manifests in shadertext
test, where the lower-left text pair is missing. Valgrind catches a bad read
for the test and causes the context to OOM reproducibly.

R=bsalomon@google.com, cdalton@nvidia.com, joshualitt@google.com, joshualitt@chromium.org

Author: kkinnunen@nvidia.com

Review URL: https://codereview.chromium.org/367643004
diff --git a/src/gpu/gl/GrGLProgramEffects.cpp b/src/gpu/gl/GrGLProgramEffects.cpp
index efb64fe..8d97b42 100644
--- a/src/gpu/gl/GrGLProgramEffects.cpp
+++ b/src/gpu/gl/GrGLProgramEffects.cpp
@@ -9,6 +9,8 @@
 #include "GrGLProgramEffects.h"
 #include "GrDrawEffect.h"
 #include "gl/GrGLEffect.h"
+#include "gl/GrGLPathRendering.h"
+#include "gl/builders/GrGLProgramBuilder.h"
 #include "gl/GrGLVertexEffect.h"
 #include "gl/GrGpuGL.h"
 
@@ -294,6 +296,16 @@
     uint32_t totalKey = GenTransformKey(drawEffect);
     int numTransforms = drawEffect.effect()->numTransforms();
     transforms.push_back_n(numTransforms);
+
+    SkTArray<PathTransform, true>* pathTransforms = NULL;
+    const GrGLCaps* glCaps = builder->ctxInfo().caps();
+    if (glCaps->pathRenderingSupport() &&
+        builder->gpu()->glPathRendering()->texturingMode() ==
+           GrGLPathRendering::SeparableShaders_TexturingMode) {
+        pathTransforms = &fPathTransforms.push_back();
+        pathTransforms->push_back_n(numTransforms);
+    }
+
     for (int t = 0; t < numTransforms; t++) {
         GrSLType varyingType = kVoid_GrSLType;
         const char* uniName;
@@ -330,7 +342,13 @@
         const char* vsVaryingName;
         const char* fsVaryingName;
         GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
-        builder->addVarying(varyingType, varyingName, &vsVaryingName, &fsVaryingName);
+        if (pathTransforms) {
+            (*pathTransforms)[t].fHandle =
+                builder->addSeparableVarying(varyingType, varyingName, &vsVaryingName, &fsVaryingName);
+            (*pathTransforms)[t].fType = varyingType;
+        } else {
+            builder->addVarying(varyingType, varyingName, &vsVaryingName, &fsVaryingName);
+        }
 
         const GrGLShaderVar& coords = kPosition_GrCoordSet == get_source_coords(totalKey, t) ?
                                           vsBuilder->positionAttribute() :
@@ -350,20 +368,27 @@
 }
 
 void GrGLVertexProgramEffects::setData(GrGpuGL* gpu,
-                                       const GrGLProgramDataManager& programResourceManager,
+                                       GrGpu::DrawType drawType,
+                                       const GrGLProgramDataManager& programDataManager,
                                        const GrEffectStage* effectStages[]) {
     int numEffects = fGLEffects.count();
     SkASSERT(numEffects == fTransforms.count());
     SkASSERT(numEffects == fSamplers.count());
     for (int e = 0; e < numEffects; ++e) {
         GrDrawEffect drawEffect(*effectStages[e], fHasExplicitLocalCoords);
-        fGLEffects[e]->setData(programResourceManager, drawEffect);
-        this->setTransformData(programResourceManager, drawEffect, e);
+        fGLEffects[e]->setData(programDataManager, drawEffect);
+        if (GrGpu::IsPathRenderingDrawType(drawType)) {
+            this->setPathTransformData(gpu, programDataManager, drawEffect, e);
+        } else {
+            this->setTransformData(gpu, programDataManager, drawEffect, e);
+        }
+
         this->bindTextures(gpu, drawEffect.effect(), e);
     }
 }
 
-void GrGLVertexProgramEffects::setTransformData(const GrGLProgramDataManager& programResourceManager,
+void GrGLVertexProgramEffects::setTransformData(GrGpuGL* gpu,
+                                                const GrGLProgramDataManager& pdman,
                                                 const GrDrawEffect& drawEffect,
                                                 int effectIdx) {
     SkTArray<Transform, true>& transforms = fTransforms[effectIdx];
@@ -373,12 +398,39 @@
         SkASSERT(transforms[t].fHandle.isValid());
         const SkMatrix& matrix = get_transform_matrix(drawEffect, t);
         if (!transforms[t].fCurrentValue.cheapEqualTo(matrix)) {
-            programResourceManager.setSkMatrix(transforms[t].fHandle, matrix);
+            pdman.setSkMatrix(transforms[t].fHandle, matrix);
             transforms[t].fCurrentValue = matrix;
         }
     }
 }
 
+void GrGLVertexProgramEffects::setPathTransformData(GrGpuGL* gpu,
+                                                    const GrGLProgramDataManager& pdman,
+                                                    const GrDrawEffect& drawEffect,
+                                                    int effectIdx) {
+    SkTArray<PathTransform, true>& transforms = fPathTransforms[effectIdx];
+    int numTransforms = transforms.count();
+    SkASSERT(numTransforms == drawEffect.effect()->numTransforms());
+    for (int t = 0; t < numTransforms; ++t) {
+        SkASSERT(transforms[t].fHandle.isValid());
+        const SkMatrix& transform = get_transform_matrix(drawEffect, t);
+        if (transforms[t].fCurrentValue.cheapEqualTo(transform)) {
+            continue;
+        }
+        transforms[t].fCurrentValue = transform;
+        switch (transforms[t].fType) {
+            case kVec2f_GrSLType:
+                pdman.setProgramPathFragmentInputTransform(transforms[t].fHandle, 2, transform);
+                break;
+            case kVec3f_GrSLType:
+                pdman.setProgramPathFragmentInputTransform(transforms[t].fHandle, 3, transform);
+                break;
+            default:
+                SkFAIL("Unexpected matrix type.");
+        }
+    }
+}
+
 GrGLVertexProgramEffectsBuilder::GrGLVertexProgramEffectsBuilder(GrGLFullProgramBuilder* builder,
                                                                  int reserveCount)
     : fBuilder(builder)
@@ -445,14 +497,15 @@
 }
 
 void GrGLPathTexGenProgramEffects::setData(GrGpuGL* gpu,
-                                       const GrGLProgramDataManager& programResourceManager,
-                                       const GrEffectStage* effectStages[]) {
+                                           GrGpu::DrawType,
+                                           const GrGLProgramDataManager& pdman,
+                                           const GrEffectStage* effectStages[]) {
     int numEffects = fGLEffects.count();
     SkASSERT(numEffects == fTransforms.count());
     SkASSERT(numEffects == fSamplers.count());
     for (int e = 0; e < numEffects; ++e) {
         GrDrawEffect drawEffect(*effectStages[e], false);
-        fGLEffects[e]->setData(programResourceManager, drawEffect);
+        fGLEffects[e]->setData(pdman, drawEffect);
         this->setPathTexGenState(gpu, drawEffect, e);
         this->bindTextures(gpu, drawEffect.effect(), e);
     }