Major refactor of runtime effects

Adds SkRuntimeEffect, a ref-counted object to hold SkSL,
a Compiler, and compiled Program, along with uniform info.

Removes the old SkSLFP factory and factory cache types.
Caching is done by simply holding on to the effect (or
the shader/color filter factories, which own an effect).

The effect class is simply ref'd by the factories, the
shader and color filter types, and the FP.

NOTE: Changes to public headers only affect private functions.

Change-Id: I0c1401505cb234e83943ad4ef2db6680f4c69fb9
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/259336
Reviewed-by: Brian Salomon <bsalomon@google.com>
Commit-Queue: Brian Osman <brianosman@google.com>
diff --git a/src/gpu/effects/GrSkSLFP.h b/src/gpu/effects/GrSkSLFP.h
index 07d0af1..c9fa9e8 100644
--- a/src/gpu/effects/GrSkSLFP.h
+++ b/src/gpu/effects/GrSkSLFP.h
@@ -24,22 +24,12 @@
 
 class GrContext_Base;
 class GrShaderCaps;
-class GrSkSLFPFactory;
-class GrSkSLFPFactoryCache;
+class SkRuntimeEffect;
 
 class GrSkSLFP : public GrFragmentProcessor {
 public:
     /**
-     * Returns a new unique identifier. Each different SkSL fragment processor should call
-     * NewIndex once, statically, and use this index for all calls to Make.
-     */
-    static int NewIndex() {
-        static std::atomic<int> nextIndex{0};
-        return nextIndex++;
-    }
-
-    /**
-     * Creates a new fragment processor from an SkSL source string and a struct of inputs to the
+     * Creates a new fragment processor from an SkRuntimeEffect and a struct of inputs to the
      * program. The input struct's type is derived from the 'in' and 'uniform' variables in the SkSL
      * source, so e.g. the shader:
      *
@@ -73,35 +63,13 @@
      * values. Other than the (significant) performance implications, the only difference between
      * the two is that 'in' variables can be used in static @if / @switch tests. When in doubt, use
      * 'uniform'.
-     *
-     * As turning SkSL into GLSL / SPIR-V / etc. is fairly expensive, and the output may differ
-     * based on the inputs, internally the process is divided into two steps: we first parse and
-     * semantically analyze the SkSL into an internal representation, and then "specialize" this
-     * internal representation based on the inputs. The unspecialized internal representation of
-     * the program is cached, so further specializations of the same code are much faster than the
-     * first call.
-     *
-     * This caching is based on the 'index' parameter, which should be derived by statically calling
-     * 'NewIndex()'. Each given SkSL string should have a single, statically defined index
-     * associated with it.
      */
-    static std::unique_ptr<GrSkSLFP> Make(
-                   GrContext_Base* context,
-                   int index,
-                   const char* name,
-                   const char* sksl,
-                   const void* inputs,
-                   size_t inputSize,
-                   const SkMatrix* matrix = nullptr);
-
-    static std::unique_ptr<GrSkSLFP> Make(
-                   GrContext_Base* context,
-                   int index,
-                   const char* name,
-                   SkString sksl,
-                   const void* inputs,
-                   size_t inputSize,
-                   const SkMatrix* matrix = nullptr);
+    static std::unique_ptr<GrSkSLFP> Make(GrContext_Base* context,
+                                          sk_sp<SkRuntimeEffect> effect,
+                                          const char* name,
+                                          const void* inputs,
+                                          size_t inputSize,
+                                          const SkMatrix* matrix = nullptr);
 
     const char* name() const override;
 
@@ -110,9 +78,8 @@
     std::unique_ptr<GrFragmentProcessor> clone() const override;
 
 private:
-    GrSkSLFP(sk_sp<GrSkSLFPFactoryCache> factoryCache,
-             int fIndex, const char* name, const char* sksl,
-             SkString skslString, const void* inputs, size_t inputSize, const SkMatrix* matrix);
+    GrSkSLFP(sk_sp<const GrShaderCaps> shaderCaps, sk_sp<SkRuntimeEffect> effect,
+             const char* name, const void* inputs, size_t inputSize, const SkMatrix* matrix);
 
     GrSkSLFP(const GrSkSLFP& other);
 
@@ -122,34 +89,16 @@
 
     bool onIsEqual(const GrFragmentProcessor&) const override;
 
-    void createFactory() const;
+    sk_sp<const GrShaderCaps> fShaderCaps;
 
-    sk_sp<GrSkSLFPFactoryCache> fFactoryCache;
-
-    mutable sk_sp<GrSkSLFPFactory> fFactory;
-
-    int fIndex;
-
-    const char* fName;
-
-    // For object lifetime purposes, we have fields for the SkSL as both a const char* and a
-    // SkString. The const char* is the one we actually use, but it may point to the SkString's
-    // bytes. Since GrSkSLFPs are frequently created from constant strings, this allows us to
-    // generally avoid the overhead of copying the bytes into an SkString (in which case fSkSLString
-    // is the empty string), while still allowing the GrSkSLFP to manage the string's lifetime when
-    // needed.
-    SkString fSkSLString;
-
-    const char* fSkSL;
+    sk_sp<SkRuntimeEffect> fEffect;
+    const char*            fName;
 
     const std::unique_ptr<int8_t[]> fInputs;
-
-    size_t fInputSize;
+    size_t                          fInputSize;
 
     GrCoordTransform fCoordTransform;
 
-    mutable SkSL::String fKey;
-
     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
 
     typedef GrFragmentProcessor INHERITED;
@@ -159,35 +108,4 @@
     friend class GrSkSLFPFactory;
 };
 
-/**
- * Produces GrFragmentProcessors from SkSL code. As the shader code produced from the SkSL depends
- * upon the inputs to the SkSL (static if's, etc.) we first create a factory for a given SkSL
- * string, then use that to create the actual GrFragmentProcessor.
- */
-class GrSkSLFPFactory : public SkNVRefCnt<GrSkSLFPFactory> {
-public:
-    /**
-     * Constructs a GrSkSLFPFactory for a given SkSL source string. Creating a factory will
-     * preprocess the SkSL and determine which of its inputs are declared "key" (meaning they cause
-     * the produced shaders to differ), so it is important to reuse the same factory instance for
-     * the same shader in order to avoid repeatedly re-parsing the SkSL.
-     */
-    GrSkSLFPFactory(const char* name, const GrShaderCaps* shaderCaps, const char* sksl);
-
-    const SkSL::Program* getSpecialization(const SkSL::String& key, const void* inputs,
-                                           size_t inputSize);
-
-    const char* fName;
-
-    SkSL::Compiler fCompiler;
-
-    std::shared_ptr<SkSL::Program> fBaseProgram;
-
-    std::vector<const SkSL::Variable*> fInAndUniformVars;
-
-    std::unordered_map<SkSL::String, std::unique_ptr<const SkSL::Program>> fSpecializations;
-
-    friend class GrSkSLFP;
-};
-
 #endif