Re-re-land sksl fragment processor support

This reverts commit 5ce397205528f82084fc650c2ce27d246c01da33.

Bug: skia:
Change-Id: I88260c90004610a1cf8ad1a87c2b4b222525bbb6
Reviewed-on: https://skia-review.googlesource.com/21108
Reviewed-by: Ben Wagner <benjaminwagner@google.com>
Commit-Queue: Ethan Nicholas <ethannicholas@google.com>
diff --git a/tests/SkSLFPTest.cpp b/tests/SkSLFPTest.cpp
new file mode 100644
index 0000000..9e635a5
--- /dev/null
+++ b/tests/SkSLFPTest.cpp
@@ -0,0 +1,395 @@
+/*
+ * Copyright 2017 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkSLCompiler.h"
+
+#include "Test.h"
+
+#if SK_SUPPORT_GPU
+
+static void test(skiatest::Reporter* r, const char* src, const GrShaderCaps& caps,
+                 std::vector<const char*> expectedH, std::vector<const char*> expectedCPP) {
+    SkSL::Program::Settings settings;
+    settings.fCaps = &caps;
+    SkSL::Compiler compiler;
+    SkSL::StringStream output;
+    std::unique_ptr<SkSL::Program> program = compiler.convertProgram(
+                                                             SkSL::Program::kFragmentProcessor_Kind,
+                                                             SkString(src),
+                                                             settings);
+    if (!program) {
+        SkDebugf("Unexpected error compiling %s\n%s", src, compiler.errorText().c_str());
+        return;
+    }
+    REPORTER_ASSERT(r, program);
+    bool success = compiler.toH(*program, "Test", output);
+    if (!success) {
+        SkDebugf("Unexpected error compiling %s\n%s", src, compiler.errorText().c_str());
+    }
+    REPORTER_ASSERT(r, success);
+    if (success) {
+        for (const char* expected : expectedH) {
+            bool found = strstr(output.str().c_str(), expected);
+            if (!found) {
+                SkDebugf("HEADER MISMATCH:\nsource:\n%s\n\nexpected:\n'%s'\n\nreceived:\n'%s'", src,
+                         expected, output.str().c_str());
+            }
+            REPORTER_ASSERT(r, found);
+        }
+    }
+    output.reset();
+    success = compiler.toCPP(*program, "Test", output);
+    if (!success) {
+        SkDebugf("Unexpected error compiling %s\n%s", src, compiler.errorText().c_str());
+    }
+    REPORTER_ASSERT(r, success);
+    if (success) {
+        for (const char* expected : expectedCPP) {
+            bool found = strstr(output.str().c_str(), expected);
+            if (!found) {
+                SkDebugf("CPP MISMATCH:\nsource:\n%s\n\nexpected:\n'%s'\n\nreceived:\n'%s'", src,
+                         expected, output.str().c_str());
+            }
+            REPORTER_ASSERT(r, found);
+        }
+    }
+}
+
+DEF_TEST(SkSLFPHelloWorld, r) {
+    test(r,
+         "void main() {"
+         "sk_OutColor = vec4(1);"
+         "}",
+         *SkSL::ShaderCapsFactory::Default(),
+         {
+             "/*\n"
+             " * Copyright 2017 Google Inc.\n"
+             " *\n"
+             " * Use of this source code is governed by a BSD-style license that can be\n"
+             " * found in the LICENSE file.\n"
+             " */\n"
+             "\n"
+             "/*\n"
+             " * This file was autogenerated from GrTest.fp; do not modify.\n"
+             " */\n"
+             "#ifndef GrTest_DEFINED\n"
+             "#define GrTest_DEFINED\n"
+             "#include \"GrFragmentProcessor.h\"\n"
+             "#include \"GrCoordTransform.h\"\n"
+             "#include \"effects/GrProxyMove.h\"\n"
+             "class GrTest : public GrFragmentProcessor {\n"
+             "public:\n"
+             "    static sk_sp<GrFragmentProcessor> Make() {\n"
+             "        return sk_sp<GrFragmentProcessor>(new GrTest());\n"
+             "    }\n"
+             "    const char* name() const override { return \"Test\"; }\n"
+             "private:\n"
+             "    GrTest()\n"
+             "    : INHERITED(kNone_OptimizationFlags) {\n"
+             "        this->initClassID<GrTest>();\n"
+             "    }\n"
+             "    GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;\n"
+             "    void onGetGLSLProcessorKey(const GrShaderCaps&,GrProcessorKeyBuilder*) "
+                    "const override;\n"
+             "    bool onIsEqual(const GrFragmentProcessor&) const override;\n"
+             "    GR_DECLARE_FRAGMENT_PROCESSOR_TEST;\n"
+             "    typedef GrFragmentProcessor INHERITED;\n"
+             "};\n"
+             "#endif\n"
+         },
+         {
+             "/*\n"
+             " * Copyright 2017 Google Inc.\n"
+             " *\n"
+             " * Use of this source code is governed by a BSD-style license that can be\n"
+             " * found in the LICENSE file.\n"
+             " */\n"
+             "\n"
+             "/*\n"
+             " * This file was autogenerated from GrTest.fp; do not modify.\n"
+             " */\n"
+             "#include \"GrTest.h\"\n"
+             "#include \"glsl/GrGLSLColorSpaceXformHelper.h\"\n"
+             "#include \"glsl/GrGLSLFragmentProcessor.h\"\n"
+             "#include \"glsl/GrGLSLFragmentShaderBuilder.h\"\n"
+             "#include \"glsl/GrGLSLProgramBuilder.h\"\n"
+             "#include \"GrResourceProvider.h\"\n"
+             "#include \"SkSLCPP.h\"\n"
+             "#include \"SkSLUtil.h\"\n"
+             "class GrGLSLTest : public GrGLSLFragmentProcessor {\n"
+             "public:\n"
+             "    GrGLSLTest() {}\n"
+             "    void emitCode(EmitArgs& args) override {\n"
+             "        GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;\n"
+             "        const GrTest& _outer = args.fFp.cast<GrTest>();\n"
+             "        (void) _outer;\n"
+             "        fragBuilder->codeAppendf(\"%s = vec4(1.0);\\n\", args.fOutputColor);\n"
+             "    }\n"
+             "private:\n"
+             "    void onSetData(const GrGLSLProgramDataManager& pdman, "
+                                "const GrFragmentProcessor& _proc) override {\n"
+             "    }\n"
+             "};\n"
+             "GrGLSLFragmentProcessor* GrTest::onCreateGLSLInstance() const {\n"
+             "    return new GrGLSLTest();\n"
+             "}\n"
+             "void GrTest::onGetGLSLProcessorKey(const GrShaderCaps& caps, "
+                                                "GrProcessorKeyBuilder* b) const {\n"
+             "}\n"
+             "bool GrTest::onIsEqual(const GrFragmentProcessor& other) const {\n"
+             "    const GrTest& that = other.cast<GrTest>();\n"
+             "    (void) that;\n"
+             "    return true;\n"
+             "}\n"
+         });
+}
+
+DEF_TEST(SkSLFPInput, r) {
+    test(r,
+         "in vec2 point;"
+         "void main() {"
+         "sk_OutColor = vec4(point, point);"
+         "}",
+         *SkSL::ShaderCapsFactory::Default(),
+         {
+             "SkPoint point() const { return fPoint; }",
+             "static sk_sp<GrFragmentProcessor> Make(SkPoint point) {",
+             "return sk_sp<GrFragmentProcessor>(new GrTest(point));",
+             "GrTest(SkPoint point)",
+             ", fPoint(point)"
+         },
+         {
+             "fragBuilder->codeAppendf(\"%s = vec4(vec2(%f, %f), vec2(%f, %f));\\n\", "
+                                      "args.fOutputColor, _outer.point().fX, _outer.point().fY, "
+                                      "_outer.point().fX, _outer.point().fY);",
+             "if (fPoint != that.fPoint) return false;"
+         });
+}
+
+DEF_TEST(SkSLFPUniform, r) {
+    test(r,
+         "uniform vec4 color;"
+         "void main() {"
+         "sk_OutColor = color;"
+         "}",
+         *SkSL::ShaderCapsFactory::Default(),
+         {
+             "static sk_sp<GrFragmentProcessor> Make()"
+         },
+         {
+            "fColorVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kVec4f_GrSLType, "
+                                                         "kDefault_GrSLPrecision, \"color\");",
+         });
+}
+
+DEF_TEST(SkSLFPInUniform, r) {
+    test(r,
+         "in uniform vec4 color;"
+         "void main() {"
+         "sk_OutColor = color;"
+         "}",
+         *SkSL::ShaderCapsFactory::Default(),
+         {
+             "static sk_sp<GrFragmentProcessor> Make(SkRect color) {",
+         },
+         {
+            "fColorVar = args.fUniformHandler->addUniform(kFragment_GrShaderFlag, kVec4f_GrSLType, "
+                                                         "kDefault_GrSLPrecision, \"color\");",
+            "const SkRect colorValue = _outer.color();",
+            "pdman.set4fv(fColorVar, 4, (float*) &colorValue);"
+         });
+}
+
+DEF_TEST(SkSLFPSections, r) {
+    test(r,
+         "@header { header section }"
+         "void main() {"
+         "sk_OutColor = vec4(1);"
+         "}",
+         *SkSL::ShaderCapsFactory::Default(),
+         {
+             "header section class GrTest",
+         },
+         {});
+    test(r,
+         "@class { class section }"
+         "void main() {"
+         "sk_OutColor = vec4(1);"
+         "}",
+         *SkSL::ShaderCapsFactory::Default(),
+         {
+             "class GrTest : public GrFragmentProcessor {\n"
+             "public:\n"
+             " class section"
+         },
+         {});
+    test(r,
+         "@cpp { cpp section }"
+         "void main() {"
+         "sk_OutColor = vec4(1);"
+         "}",
+         *SkSL::ShaderCapsFactory::Default(),
+         {},
+         {"cpp section"});
+    test(r,
+         "@constructorParams { int x, float y, std::vector<float> z }"
+         "in float w;"
+         "void main() {"
+         "sk_OutColor = vec4(1);"
+         "}",
+         *SkSL::ShaderCapsFactory::Default(),
+         {
+             "Make(float w,  int x, float y, std::vector<float> z )",
+             "return sk_sp<GrFragmentProcessor>(new GrTest(w, x, y, z));",
+             "GrTest(float w,  int x, float y, std::vector<float> z )",
+             ", fW(w) {"
+         },
+         {});
+    test(r,
+         "@constructor { constructor section }"
+         "void main() {"
+         "sk_OutColor = vec4(1);"
+         "}",
+         *SkSL::ShaderCapsFactory::Default(),
+         {
+             "private:\n constructor section"
+         },
+         {});
+    test(r,
+         "@initializers { initializers section }"
+         "void main() {"
+         "sk_OutColor = vec4(1);"
+         "}",
+         *SkSL::ShaderCapsFactory::Default(),
+         {
+             ": INHERITED(kNone_OptimizationFlags)\n    ,  initializers section"
+         },
+         {});
+    test(r,
+         "float x = 10;"
+         "@emitCode { fragBuilder->codeAppendf(\"float y = %d\\n\", x * 2); }"
+         "void main() {"
+         "sk_OutColor = vec4(1);"
+         "}",
+         *SkSL::ShaderCapsFactory::Default(),
+         {},
+         {
+            "x = 10.0;\n"
+            " fragBuilder->codeAppendf(\"float y = %d\\n\", x * 2);"
+         });
+    test(r,
+         "@fields { fields section }"
+         "void main() {"
+         "sk_OutColor = vec4(1);"
+         "}",
+         *SkSL::ShaderCapsFactory::Default(),
+         {
+            "GR_DECLARE_FRAGMENT_PROCESSOR_TEST;\n"
+            " fields section     typedef GrFragmentProcessor INHERITED;"
+         },
+         {});
+    test(r,
+         "@make { make section }"
+         "void main() {"
+         "sk_OutColor = vec4(1);"
+         "}",
+         *SkSL::ShaderCapsFactory::Default(),
+         {
+            "public:\n"
+            " make section"
+         },
+         {});
+    test(r,
+         "uniform float calculated;"
+         "in float provided;"
+         "@setData(varName) { varName.set1f(calculated, provided * 2); }"
+         "void main() {"
+         "sk_OutColor = vec4(1);"
+         "}",
+         *SkSL::ShaderCapsFactory::Default(),
+         {},
+         {
+             "void onSetData(const GrGLSLProgramDataManager& varName, "
+                            "const GrFragmentProcessor& _proc) override {\n",
+             "UniformHandle& calculated = fCalculatedVar;",
+             "auto provided = _outer.provided();",
+             "varName.set1f(calculated, provided * 2);"
+         });
+    test(r,
+         "@test(testDataName) { testDataName section }"
+         "void main() {"
+         "sk_OutColor = vec4(1);"
+         "}",
+         *SkSL::ShaderCapsFactory::Default(),
+         {},
+         {
+             "#if GR_TEST_UTILS\n"
+             "sk_sp<GrFragmentProcessor> GrTest::TestCreate(GrProcessorTestData* testDataName) {\n"
+             " testDataName section }\n"
+             "#endif"
+         });
+}
+
+DEF_TEST(SkSLFPColorSpaceXform, r) {
+    test(r,
+         "in uniform sampler2D image;"
+         "in uniform colorSpaceXform colorXform;"
+         "void main() {"
+         "sk_OutColor = sk_InColor * texture(image, vec2(0, 0), colorXform);"
+         "}",
+         *SkSL::ShaderCapsFactory::Default(),
+         {
+            "sk_sp<GrColorSpaceXform> colorXform() const { return fColorXform; }",
+            "GrTest(sk_sp<GrTextureProxy> image, sk_sp<GrColorSpaceXform> colorXform)",
+            "this->addTextureSampler(&fImage);",
+            "sk_sp<GrColorSpaceXform> fColorXform;"
+         },
+         {
+            "fragBuilder->codeAppendf(\"vec4 _tmp0;\\n%s = %s * "
+            "(_tmp0 = texture(%s, vec2(0.0, 0.0)) , %s != mat4(1.0) ? "
+            "vec4(clamp((%s * vec4(_tmp0.xyz, 1.0)).xyz, 0.0, _tmp0.w), _tmp0.w) : "
+            "_tmp0);\\n\", args.fOutputColor, args.fInputColor ? args.fInputColor : "
+            "\"vec4(1)\", fragBuilder->getProgramBuilder()->samplerVariable("
+            "args.fTexSamplers[0]).c_str(), fColorSpaceHelper.isValid() ? "
+            "args.fUniformHandler->getUniformCStr(fColorSpaceHelper.gamutXformUniform()) : "
+            "\"mat4(1.0)\", fColorSpaceHelper.isValid() ? "
+            "args.fUniformHandler->getUniformCStr(fColorSpaceHelper.gamutXformUniform()) : "
+            "\"mat4(1.0)\");"
+         });
+}
+
+DEF_TEST(SkSLFPTransformedCoords, r) {
+    test(r,
+         "void main() {"
+         "sk_OutColor = vec4(sk_TransformedCoords2D[0], sk_TransformedCoords2D[0]);"
+         "}",
+         *SkSL::ShaderCapsFactory::Default(),
+         {},
+         {
+            "SkSL::String sk_TransformedCoords2D_0 = "
+                                         "fragBuilder->ensureCoords2D(args.fTransformedCoords[0]);",
+            "fragBuilder->codeAppendf(\"%s = vec4(%s, %s);\\n\", args.fOutputColor, "
+                              "sk_TransformedCoords2D_0.c_str(), sk_TransformedCoords2D_0.c_str());"
+         });
+
+}
+
+DEF_TEST(SkSLFPLayoutWhen, r) {
+    test(r,
+         "layout(when=someExpression(someOtherExpression())) uniform float sometimes;"
+         "void main() {"
+         "}",
+         *SkSL::ShaderCapsFactory::Default(),
+         {},
+         {
+            "if (someExpression(someOtherExpression())) {\n"
+            "            fSometimesVar = args.fUniformHandler->addUniform"
+         });
+
+}
+
+#endif