Add back door support for GLSL tessellation shaders

Implements tessellation support at the Ganesh level, and adds back
door methods for supplying raw GLSL strings directly to the OpenGL
driver. Adds a new gm to verify tessellation is works in GL.

Change-Id: Idfc285b955cbe5e8e6bf0475be8b518b0cc6ed2c
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/261196
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Chris Dalton <csmartdalton@google.com>
diff --git a/src/gpu/gl/builders/GrGLProgramBuilder.cpp b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
index 3ce3267..0fb915d 100644
--- a/src/gpu/gl/builders/GrGLProgramBuilder.cpp
+++ b/src/gpu/gl/builders/GrGLProgramBuilder.cpp
@@ -362,6 +362,38 @@
         }
 
         /*
+           Tessellation Shaders
+        */
+        if (fProgramInfo.primProc().willUseTessellationShaders()) {
+            // Tessellation shaders are not currently supported by SkSL. So here, we temporarily
+            // generate GLSL strings directly using back door methods on GrPrimitiveProcessor, and
+            // pass those raw strings on to the driver.
+            SkString versionAndExtensionDecls;
+            versionAndExtensionDecls.appendf("%s\n", this->shaderCaps()->versionDeclString());
+            if (const char* extensionString = this->shaderCaps()->tessellationExtensionString()) {
+                versionAndExtensionDecls.appendf("#extension %s : require\n", extensionString);
+            }
+
+            SkString tessControlShader = primProc.getTessControlShaderGLSL(
+                    versionAndExtensionDecls.c_str(), *this->shaderCaps());
+            if (!this->compileAndAttachShaders(tessControlShader.c_str(), programID,
+                                               GR_GL_TESS_CONTROL_SHADER, &shadersToDelete,
+                                               errorHandler)) {
+                cleanup_program(fGpu, programID, shadersToDelete);
+                return nullptr;
+            }
+
+            SkString tessEvaluationShader = primProc.getTessEvaluationShaderGLSL(
+                    versionAndExtensionDecls.c_str(), *this->shaderCaps());
+            if (!this->compileAndAttachShaders(tessEvaluationShader.c_str(), programID,
+                                               GR_GL_TESS_EVALUATION_SHADER, &shadersToDelete,
+                                               errorHandler)) {
+                cleanup_program(fGpu, programID, shadersToDelete);
+                return nullptr;
+            }
+        }
+
+        /*
            Geometry Shader
         */
         if (primProc.willUseGeoShader()) {
@@ -404,9 +436,16 @@
     // and ANGLE's deserialized program state doesn't restore enough state to handle that.
     // The native NVIDIA drivers do, but this is such an edge case that it's easier to just
     // black-list caching these programs in all cases. See: anglebug.com/3619
+    //
+    // We temporarily can't cache tessellation shaders while using back door GLSL.
+    //
     // We also can't cache SkSL or GLSL if we were given a precompiled program, but there's not
     // much point in doing so.
-    if (!cached && !primProc.isPathRendering() && !precompiledProgram) {
+    if (!cached && !primProc.isPathRendering() && !primProc.willUseTessellationShaders() &&
+        !precompiledProgram) {
+        static_assert(&GrPrimitiveProcessor::getTessControlShaderGLSL,
+                      "FIXME: Remove the check for tessellation shaders in the above 'if' once the "
+                      "back door GLSL mechanism is removed.");
         bool isSkSL = false;
         if (fGpu->getContext()->priv().options().fShaderCacheStrategy ==
                 GrContextOptions::ShaderCacheStrategy::kSkSL) {