1 /*
2  * Copyright 2018 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef GrSkSLFP_DEFINED
9 #define GrSkSLFP_DEFINED
10 
11 #include "include/core/SkRefCnt.h"
12 #include "src/gpu/GrCaps.h"
13 #include "src/gpu/GrCoordTransform.h"
14 #include "src/gpu/GrFragmentProcessor.h"
15 #include "src/gpu/GrShaderCaps.h"
16 #include "src/gpu/GrSkSLFPFactoryCache.h"
17 #include "src/sksl/SkSLCompiler.h"
18 #include "src/sksl/SkSLPipelineStageCodeGenerator.h"
19 #include <atomic>
20 
21 #if GR_TEST_UTILS
22 #define GR_FP_SRC_STRING const char*
23 #else
24 #define GR_FP_SRC_STRING static const char*
25 #endif
26 
27 class GrContext_Base;
28 class GrSkSLFPFactory;
29 
30 class GrSkSLFP : public GrFragmentProcessor {
31 public:
32     /**
33      * Returns a new unique identifier. Each different SkSL fragment processor should call
34      * NewIndex once, statically, and use this index for all calls to Make.
35      */
NewIndex()36     static int NewIndex() {
37         static std::atomic<int> nextIndex{0};
38         return nextIndex++;
39     }
40 
41     /**
42      * Creates a new fragment processor from an SkSL source string and a struct of inputs to the
43      * program. The input struct's type is derived from the 'in' and 'uniform' variables in the SkSL
44      * source, so e.g. the shader:
45      *
46      *    in bool dither;
47      *    uniform float x;
48      *    uniform float y;
49      *    ....
50      *
51      * would expect a pointer to a struct set up like:
52      *
53      * struct {
54      *     bool dither;
55      *     float x;
56      *     float y;
57      * };
58      *
59      * While both 'in' and 'uniform' variables go into this struct, the difference between them is
60      * that 'in' variables are statically "baked in" to the generated code, becoming literals,
61      * whereas uniform variables may be changed from invocation to invocation without having to
62      * recompile the shader.
63      *
64      * As the decision of whether to create a new shader or just upload new uniforms all happens
65      * behind the scenes, the difference between the two from an end-user perspective is primarily
66      * in performance: on the one hand, changing the value of an 'in' variable is very expensive
67      * (requiring the compiler to regenerate the code, upload a new shader to the GPU, and so
68      * forth), but on the other hand the compiler can optimize around its value because it is known
69      * at compile time. 'in' variables are therefore suitable for things like flags, where there are
70      * only a few possible values and a known-in-advance value can cause entire chunks of code to
71      * become dead (think static @ifs), while 'uniform's are used for continuous values like colors
72      * and coordinates, where it would be silly to create a separate shader for each possible set of
73      * values. Other than the (significant) performance implications, the only difference between
74      * the two is that 'in' variables can be used in static @if / @switch tests. When in doubt, use
75      * 'uniform'.
76      *
77      * As turning SkSL into GLSL / SPIR-V / etc. is fairly expensive, and the output may differ
78      * based on the inputs, internally the process is divided into two steps: we first parse and
79      * semantically analyze the SkSL into an internal representation, and then "specialize" this
80      * internal representation based on the inputs. The unspecialized internal representation of
81      * the program is cached, so further specializations of the same code are much faster than the
82      * first call.
83      *
84      * This caching is based on the 'index' parameter, which should be derived by statically calling
85      * 'NewIndex()'. Each given SkSL string should have a single, statically defined index
86      * associated with it.
87      */
88     static std::unique_ptr<GrSkSLFP> Make(
89                    GrContext_Base* context,
90                    int index,
91                    const char* name,
92                    const char* sksl,
93                    const void* inputs,
94                    size_t inputSize,
95                    SkSL::Program::Kind kind = SkSL::Program::kPipelineStage_Kind,
96                    const SkMatrix* matrix = nullptr);
97 
98     static std::unique_ptr<GrSkSLFP> Make(
99                    GrContext_Base* context,
100                    int index,
101                    const char* name,
102                    SkString sksl,
103                    const void* inputs,
104                    size_t inputSize,
105                    SkSL::Program::Kind kind = SkSL::Program::kPipelineStage_Kind,
106                    const SkMatrix* matrix = nullptr);
107 
108     const char* name() const override;
109 
110     void addChild(std::unique_ptr<GrFragmentProcessor> child);
111 
112     std::unique_ptr<GrFragmentProcessor> clone() const override;
113 
114 private:
115     GrSkSLFP(sk_sp<GrSkSLFPFactoryCache> factoryCache, const GrShaderCaps* shaderCaps,
116              SkSL::Program::Kind kind, int fIndex, const char* name, const char* sksl,
117              SkString skslString, const void* inputs, size_t inputSize, const SkMatrix* matrix);
118 
119     GrSkSLFP(const GrSkSLFP& other);
120 
121     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
122 
123     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
124 
125     bool onIsEqual(const GrFragmentProcessor&) const override;
126 
127     void createFactory() const;
128 
129     sk_sp<GrSkSLFPFactoryCache> fFactoryCache;
130 
131     const sk_sp<GrShaderCaps> fShaderCaps;
132 
133     mutable sk_sp<GrSkSLFPFactory> fFactory;
134 
135     SkSL::Program::Kind fKind;
136 
137     int fIndex;
138 
139     const char* fName;
140 
141     // For object lifetime purposes, we have fields for the SkSL as both a const char* and a
142     // SkString. The const char* is the one we actually use, but it may point to the SkString's
143     // bytes. Since GrSkSLFPs are frequently created from constant strings, this allows us to
144     // generally avoid the overhead of copying the bytes into an SkString (in which case fSkSLString
145     // is the empty string), while still allowing the GrSkSLFP to manage the string's lifetime when
146     // needed.
147     SkString fSkSLString;
148 
149     const char* fSkSL;
150 
151     const std::unique_ptr<int8_t[]> fInputs;
152 
153     size_t fInputSize;
154 
155     GrCoordTransform fCoordTransform;
156 
157     mutable SkSL::String fKey;
158 
159     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
160 
161     typedef GrFragmentProcessor INHERITED;
162 
163     friend class GrGLSLSkSLFP;
164 
165     friend class GrSkSLFPFactory;
166 };
167 
168 /**
169  * Produces GrFragmentProcessors from SkSL code. As the shader code produced from the SkSL depends
170  * upon the inputs to the SkSL (static if's, etc.) we first create a factory for a given SkSL
171  * string, then use that to create the actual GrFragmentProcessor.
172  */
173 class GrSkSLFPFactory : public SkNVRefCnt<GrSkSLFPFactory> {
174 public:
175     /**
176      * Constructs a GrSkSLFPFactory for a given SkSL source string. Creating a factory will
177      * preprocess the SkSL and determine which of its inputs are declared "key" (meaning they cause
178      * the produced shaders to differ), so it is important to reuse the same factory instance for
179      * the same shader in order to avoid repeatedly re-parsing the SkSL.
180      */
181     GrSkSLFPFactory(const char* name, const GrShaderCaps* shaderCaps, const char* sksl,
182                     SkSL::Program::Kind kind = SkSL::Program::kPipelineStage_Kind);
183 
184     const SkSL::Program* getSpecialization(const SkSL::String& key, const void* inputs,
185                                            size_t inputSize);
186 
187     SkSL::Program::Kind fKind;
188 
189     const char* fName;
190 
191     SkSL::Compiler fCompiler;
192 
193     std::shared_ptr<SkSL::Program> fBaseProgram;
194 
195     std::vector<const SkSL::Variable*> fInAndUniformVars;
196 
197     std::unordered_map<SkSL::String, std::unique_ptr<const SkSL::Program>> fSpecializations;
198 
199     friend class GrSkSLFP;
200 };
201 
202 #endif
203