• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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' variables in the SkSL source, so
44      * e.g. the shader:
45      *
46      *    in bool dither;
47      *    in float x;
48      *    in 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      * As turning SkSL into GLSL / SPIR-V / etc. is fairly expensive, and the output may differ
60      * based on the inputs, internally the process is divided into two steps: we first parse and
61      * semantically analyze the SkSL into an internal representation, and then "specialize" this
62      * internal representation based on the inputs. The unspecialized internal representation of
63      * the program is cached, so further specializations of the same code are much faster than the
64      * first call.
65      *
66      * This caching is based on the 'index' parameter, which should be derived by statically calling
67      * 'NewIndex()'. Each given SkSL string should have a single, statically defined index
68      * associated with it.
69      */
70     static std::unique_ptr<GrSkSLFP> Make(
71                    GrContext_Base* context,
72                    int index,
73                    const char* name,
74                    const char* sksl,
75                    const void* inputs,
76                    size_t inputSize,
77                    SkSL::Program::Kind kind = SkSL::Program::kPipelineStage_Kind,
78                    const SkMatrix* matrix = nullptr);
79 
80     static std::unique_ptr<GrSkSLFP> Make(
81                    GrContext_Base* context,
82                    int index,
83                    const char* name,
84                    SkString sksl,
85                    const void* inputs,
86                    size_t inputSize,
87                    SkSL::Program::Kind kind = SkSL::Program::kPipelineStage_Kind,
88                    const SkMatrix* matrix = nullptr);
89 
90     const char* name() const override;
91 
92     void addChild(std::unique_ptr<GrFragmentProcessor> child);
93 
94     std::unique_ptr<GrFragmentProcessor> clone() const override;
95 
96 private:
97     GrSkSLFP(sk_sp<GrSkSLFPFactoryCache> factoryCache, const GrShaderCaps* shaderCaps,
98              SkSL::Program::Kind kind, int fIndex, const char* name, const char* sksl,
99              SkString skslString, const void* inputs, size_t inputSize, const SkMatrix* matrix);
100 
101     GrSkSLFP(const GrSkSLFP& other);
102 
103     GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
104 
105     void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
106 
107     bool onIsEqual(const GrFragmentProcessor&) const override;
108 
109     void createFactory() const;
110 
111     sk_sp<GrSkSLFPFactoryCache> fFactoryCache;
112 
113     const sk_sp<GrShaderCaps> fShaderCaps;
114 
115     mutable sk_sp<GrSkSLFPFactory> fFactory;
116 
117     SkSL::Program::Kind fKind;
118 
119     int fIndex;
120 
121     const char* fName;
122 
123     // For object lifetime purposes, we have fields for the SkSL as both a const char* and a
124     // SkString. The const char* is the one we actually use, but it may point to the SkString's
125     // bytes. Since GrSkSLFPs are frequently created from constant strings, this allows us to
126     // generally avoid the overhead of copying the bytes into an SkString (in which case fSkSLString
127     // is the empty string), while still allowing the GrSkSLFP to manage the string's lifetime when
128     // needed.
129     SkString fSkSLString;
130 
131     const char* fSkSL;
132 
133     const std::unique_ptr<int8_t[]> fInputs;
134 
135     size_t fInputSize;
136 
137     GrCoordTransform fCoordTransform;
138 
139     mutable SkSL::String fKey;
140 
141     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
142 
143     typedef GrFragmentProcessor INHERITED;
144 
145     friend class GrGLSLSkSLFP;
146 
147     friend class GrSkSLFPFactory;
148 };
149 
150 /**
151  * Produces GrFragmentProcessors from SkSL code. As the shader code produced from the SkSL depends
152  * upon the inputs to the SkSL (static if's, etc.) we first create a factory for a given SkSL
153  * string, then use that to create the actual GrFragmentProcessor.
154  */
155 class GrSkSLFPFactory : public SkNVRefCnt<GrSkSLFPFactory> {
156 public:
157     /**
158      * Constructs a GrSkSLFPFactory for a given SkSL source string. Creating a factory will
159      * preprocess the SkSL and determine which of its inputs are declared "key" (meaning they cause
160      * the produced shaders to differ), so it is important to reuse the same factory instance for
161      * the same shader in order to avoid repeatedly re-parsing the SkSL.
162      */
163     GrSkSLFPFactory(const char* name, const GrShaderCaps* shaderCaps, const char* sksl,
164                     SkSL::Program::Kind kind = SkSL::Program::kPipelineStage_Kind);
165 
166     const SkSL::Program* getSpecialization(const SkSL::String& key, const void* inputs,
167                                            size_t inputSize);
168 
169     SkSL::Program::Kind fKind;
170 
171     const char* fName;
172 
173     SkSL::Compiler fCompiler;
174 
175     std::shared_ptr<SkSL::Program> fBaseProgram;
176 
177     std::vector<const SkSL::Variable*> fInputVars;
178 
179     std::vector<const SkSL::Variable*> fKeyVars;
180 
181     std::unordered_map<SkSL::String, std::unique_ptr<const SkSL::Program>> fSpecializations;
182 
183     friend class GrSkSLFP;
184 };
185 
186 #endif
187