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