• 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 "include/effects/SkRuntimeEffect.h"
13 #include "include/gpu/GrContextOptions.h"
14 #include "include/private/SkVx.h"
15 #include "src/gpu/GrFragmentProcessor.h"
16 
17 #include <atomic>
18 #include <utility>
19 #include <vector>
20 
21 class GrShaderCaps;
22 class SkData;
23 class SkRuntimeEffect;
24 
25 #ifdef SK_DEBUG
26 // UNIFORM_TYPE allows C++ types to be mapped onto SkRuntimeEffect::Uniform::Type
27 template <typename T> struct GrFPUniformType {
28     template <typename U> struct add_a_UNIFORM_TYPE_specialization_for {};
29     static constexpr add_a_UNIFORM_TYPE_specialization_for<T> value = {};
30 };
31 #define UNIFORM_TYPE(E, ...)                                                                       \
32     template <> struct GrFPUniformType<__VA_ARGS__> {                                              \
33         static constexpr SkRuntimeEffect::Uniform::Type value = SkRuntimeEffect::Uniform::Type::E; \
34     };                                                                                             \
35     template <> struct GrFPUniformType<SkSpan<__VA_ARGS__>> {                                      \
36         static constexpr SkRuntimeEffect::Uniform::Type value = SkRuntimeEffect::Uniform::Type::E; \
37     }
38 
39 UNIFORM_TYPE(kFloat,    float);
40 UNIFORM_TYPE(kFloat2,   SkV2);
41 UNIFORM_TYPE(kFloat4,   SkPMColor4f);
42 UNIFORM_TYPE(kFloat4,   SkRect);
43 UNIFORM_TYPE(kFloat4,   SkV4);
44 UNIFORM_TYPE(kFloat4,   skvx::Vec<4, float>);
45 UNIFORM_TYPE(kFloat4x4, SkM44);
46 UNIFORM_TYPE(kInt,      int);
47 
48 #undef UNIFORM_TYPE
49 #endif
50 
51 class GrSkSLFP : public GrFragmentProcessor {
52 public:
53     // Advanced Filter: Overwrite parent's method, check if AF is enabled from fEffect
isAFEnabled()54     virtual bool isAFEnabled() const override
55     {
56         return fEffect != nullptr ? fEffect->getAF() : false;
57     }
58 
59     template <typename T> struct GrSpecializedUniform {
60         bool specialize;
61         T value;
62     };
63     template <typename T>
Specialize(const T & value)64     static GrSpecializedUniform<T> Specialize(const T& value) {
65         return {true, value};
66     }
67     template <typename T>
SpecializeIf(bool condition,const T & value)68     static GrSpecializedUniform<T> SpecializeIf(bool condition, const T& value) {
69         return {condition, value};
70     }
71 
72     template <typename T> struct GrOptionalUniform {
73         bool enabled;
74         T value;
75     };
76     template <typename T>
When(bool condition,const T & value)77     static GrOptionalUniform<T> When(bool condition, const T& value) {
78         return {condition, value};
79     }
80 
81     struct GrIgnoreOptFlags {
82         std::unique_ptr<GrFragmentProcessor> child;
83     };
IgnoreOptFlags(std::unique_ptr<GrFragmentProcessor> child)84     static GrIgnoreOptFlags IgnoreOptFlags(std::unique_ptr<GrFragmentProcessor> child) {
85         return {std::move(child)};
86     }
87 
88     enum class OptFlags : uint32_t {
89         kNone                          = kNone_OptimizationFlags,
90         kCompatibleWithCoverageAsAlpha = kCompatibleWithCoverageAsAlpha_OptimizationFlag,
91         kPreservesOpaqueInput          = kPreservesOpaqueInput_OptimizationFlag,
92         kAll                           = kCompatibleWithCoverageAsAlpha | kPreservesOpaqueInput,
93     };
94 
95     /**
96      * Both factories support a single 'input' FP, as well as a collection of other 'child' FPs.
97      * The 'child' FPs correspond to the children declared in the effect's SkSL. The inputFP is
98      * optional, and intended for instances that have color filter semantics. This is an implicit
99      * child - if present, it's evaluated to produce the input color fed to the SkSL. Otherwise,
100      * the SkSL receives this FP's input color directly.
101      */
102 
103     /**
104      * Creates a new fragment processor from an SkRuntimeEffect and a data blob containing values
105      * for all of the 'uniform' variables in the SkSL source. The layout of the uniforms blob is
106      * dictated by the SkRuntimeEffect.
107      */
108     static std::unique_ptr<GrSkSLFP> MakeWithData(
109             sk_sp<SkRuntimeEffect> effect,
110             const char* name,
111             std::unique_ptr<GrFragmentProcessor> inputFP,
112             std::unique_ptr<GrFragmentProcessor> destColorFP,
113             sk_sp<SkData> uniforms,
114             SkSpan<std::unique_ptr<GrFragmentProcessor>> childFPs);
115 
116     /*
117      * Constructs a GrSkSLFP from a series of name-value pairs, corresponding to the children and
118      * uniform data members of the effect's SkSL.
119      * The variable length args... must contain all of the children and uniforms expected.
120      * Each individual argument must be preceded by a name that matches the SkSL name of the value
121      * being set. For children, the next argument must be a std::unique_ptr<GrFragmentProcessor>.
122      * For uniforms, the next argument must be data of the correct size and type.
123      *
124      * For example, given:
125      *   uniform shader child;
126      *   uniform float scale;
127      *   uniform half2 pt;
128      *   half4 main() { ... }
129      *
130      * A call to GrSkSLFP would be formatted like:
131      *   std::unique_ptr<GrFragmentProcessor> child = ...;
132      *   float scaleVal = ...;
133      *   SkV2 ptVal = ...;
134      *   auto fp = GrSkSLFP::Make(effect, "my_effect", nullptr, GrSkSLFP::OptFlags::...,
135      *                            "child", std::move(child),
136      *                            "scale", scaleVal,
137      *                            "pt", ptVal);
138      *
139      * The uniforms must appear in the correct order, as must the children. Technically, the two
140      * lists can be interleaved. In debug builds, the number, names, and sizes of all arguments are
141      * checked with assertions. In release builds, all checks are elided. In either case, the
142      * uniform data is directly copied into the footer allocated after the FP.
143      */
144     template <typename... Args>
Make(sk_sp<SkRuntimeEffect> effect,const char * name,std::unique_ptr<GrFragmentProcessor> inputFP,OptFlags optFlags,Args &&...args)145     static std::unique_ptr<GrSkSLFP> Make(sk_sp<SkRuntimeEffect> effect,
146                                           const char* name,
147                                           std::unique_ptr<GrFragmentProcessor> inputFP,
148                                           OptFlags optFlags,
149                                           Args&&... args) {
150 #ifdef SK_DEBUG
151         checkArgs(effect->fUniforms.begin(),
152                   effect->fUniforms.end(),
153                   effect->fChildren.begin(),
154                   effect->fChildren.end(),
155                   std::forward<Args>(args)...);
156 #endif
157 
158         size_t uniformPayloadSize = UniformPayloadSize(effect.get());
159         std::unique_ptr<GrSkSLFP> fp(new (uniformPayloadSize)
160                                              GrSkSLFP(std::move(effect), name, optFlags));
161         fp->appendArgs(fp->uniformData(), fp->uniformFlags(), std::forward<Args>(args)...);
162         if (inputFP) {
163             fp->setInput(std::move(inputFP));
164         }
165         return fp;
166     }
167 
name()168     const char* name() const override { return fName; }
169     SkString getShaderDfxInfo() const override;
170     std::unique_ptr<GrFragmentProcessor> clone() const override;
171 
172 private:
173     class Impl;
174 
175     GrSkSLFP(sk_sp<SkRuntimeEffect> effect, const char* name, OptFlags optFlags);
176     GrSkSLFP(const GrSkSLFP& other);
177 
178     void addChild(std::unique_ptr<GrFragmentProcessor> child, bool mergeOptFlags);
179     void setInput(std::unique_ptr<GrFragmentProcessor> input);
180     void setDestColorFP(std::unique_ptr<GrFragmentProcessor> destColorFP);
181 
182     std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override;
183 
184     void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
185 
186     bool onIsEqual(const GrFragmentProcessor&) const override;
187 
188     SkPMColor4f constantOutputForConstantInput(const SkPMColor4f&) const override;
189 
190     // An instance of GrSkSLFP is always allocated with a payload immediately following the FP.
191     // First the values of all the uniforms, and then a set of flags (one per uniform).
UniformPayloadSize(const SkRuntimeEffect * effect)192     static size_t UniformPayloadSize(const SkRuntimeEffect* effect) {
193         return effect->uniformSize() + effect->uniforms().size() * sizeof(UniformFlags);
194     }
195 
uniformData()196     const uint8_t* uniformData() const { return reinterpret_cast<const uint8_t*>(this + 1); }
uniformData()197           uint8_t* uniformData()       { return reinterpret_cast<      uint8_t*>(this + 1); }
198 
199     enum UniformFlags : uint8_t {
200         kSpecialize_Flag = 0x1,
201     };
202 
uniformFlags()203     const UniformFlags* uniformFlags() const {
204         return reinterpret_cast<const UniformFlags*>(this->uniformData() + fUniformSize);
205     }
uniformFlags()206     UniformFlags* uniformFlags() {
207         return reinterpret_cast<UniformFlags*>(this->uniformData() + fUniformSize);
208     }
209 
210     // Helpers to attach variadic template args to a newly constructed FP:
211 
appendArgs(uint8_t * uniformDataPtr,UniformFlags * uniformFlagsPtr)212     void appendArgs(uint8_t* uniformDataPtr, UniformFlags* uniformFlagsPtr) {
213         // Base case -- no more args to append, so we're done
214     }
215     template <typename... Args>
appendArgs(uint8_t * uniformDataPtr,UniformFlags * uniformFlagsPtr,const char * name,std::unique_ptr<GrFragmentProcessor> && child,Args &&...remainder)216     void appendArgs(uint8_t* uniformDataPtr,
217                     UniformFlags* uniformFlagsPtr,
218                     const char* name,
219                     std::unique_ptr<GrFragmentProcessor>&& child,
220                     Args&&... remainder) {
221         // Child FP case -- register the child, then continue processing the remaining arguments.
222         // Children aren't "uniforms" here, so the data & flags pointers don't advance.
223         this->addChild(std::move(child), /*mergeOptFlags=*/true);
224         this->appendArgs(uniformDataPtr, uniformFlagsPtr, std::forward<Args>(remainder)...);
225     }
226     // As above, but we don't merge in the child's optimization flags
227     template <typename... Args>
appendArgs(uint8_t * uniformDataPtr,UniformFlags * uniformFlagsPtr,const char * name,GrIgnoreOptFlags && child,Args &&...remainder)228     void appendArgs(uint8_t* uniformDataPtr,
229                     UniformFlags* uniformFlagsPtr,
230                     const char* name,
231                     GrIgnoreOptFlags&& child,
232                     Args&&... remainder) {
233         // Child FP case -- register the child, then continue processing the remaining arguments.
234         // Children aren't "uniforms" here, so the data & flags pointers don't advance.
235         this->addChild(std::move(child.child), /*mergeOptFlags=*/false);
236         this->appendArgs(uniformDataPtr, uniformFlagsPtr, std::forward<Args>(remainder)...);
237     }
238     template <typename T, typename... Args>
appendArgs(uint8_t * uniformDataPtr,UniformFlags * uniformFlagsPtr,const char * name,const GrSpecializedUniform<T> & val,Args &&...remainder)239     void appendArgs(uint8_t* uniformDataPtr,
240                     UniformFlags* uniformFlagsPtr,
241                     const char* name,
242                     const GrSpecializedUniform<T>& val,
243                     Args&&... remainder) {
244         // Specialized uniform case -- This just handles the specialization logic. If we want to
245         // specialize on this particular value, set the flag. Then, continue processing the actual
246         // value (by just peeling off the wrapper). This lets our generic `const T&` case (below)
247         // handle copying the data into our uniform block, and advancing the per-value uniform
248         // data and flags pointers.
249         if (val.specialize) {
250             *uniformFlagsPtr = static_cast<UniformFlags>(*uniformFlagsPtr | kSpecialize_Flag);
251         }
252         this->appendArgs(
253                 uniformDataPtr, uniformFlagsPtr, name, val.value, std::forward<Args>(remainder)...);
254     }
255     template <typename T, typename... Args>
appendArgs(uint8_t * uniformDataPtr,UniformFlags * uniformFlagsPtr,const char * name,const GrOptionalUniform<T> & val,Args &&...remainder)256     void appendArgs(uint8_t* uniformDataPtr,
257                     UniformFlags* uniformFlagsPtr,
258                     const char* name,
259                     const GrOptionalUniform<T>& val,
260                     Args&&... remainder) {
261         // Optional uniform case. Copy the data and advance pointers, but only if the uniform is
262         // enabled. Then proceed as normal.
263         if (val.enabled) {
264             memcpy(uniformDataPtr, &val.value, sizeof(val.value));
265             uniformDataPtr += sizeof(val.value);
266             uniformFlagsPtr++;
267         }
268 
269         this->appendArgs(uniformDataPtr, uniformFlagsPtr, std::forward<Args>(remainder)...);
270     }
271     template <typename T, typename... Args>
appendArgs(uint8_t * uniformDataPtr,UniformFlags * uniformFlagsPtr,const char * name,SkSpan<T> val,Args &&...remainder)272     void appendArgs(uint8_t* uniformDataPtr,
273                     UniformFlags* uniformFlagsPtr,
274                     const char* name,
275                     SkSpan<T> val,
276                     Args&&... remainder) {
277         // Uniform array case -- We copy the supplied values into our uniform data area,
278         // then advance our uniform data and flags pointers.
279         memcpy(uniformDataPtr, val.data(), val.size_bytes());
280         uniformDataPtr += val.size_bytes();
281         uniformFlagsPtr++;
282         this->appendArgs(uniformDataPtr, uniformFlagsPtr, std::forward<Args>(remainder)...);
283     }
284     template <typename T, typename... Args>
appendArgs(uint8_t * uniformDataPtr,UniformFlags * uniformFlagsPtr,const char * name,const T & val,Args &&...remainder)285     void appendArgs(uint8_t* uniformDataPtr,
286                     UniformFlags* uniformFlagsPtr,
287                     const char* name,
288                     const T& val,
289                     Args&&... remainder) {
290         // Raw uniform value case -- We copy the supplied value into our uniform data area,
291         // then advance our uniform data and flags pointers.
292         memcpy(uniformDataPtr, &val, sizeof(val));
293         uniformDataPtr += sizeof(val);
294         uniformFlagsPtr++;
295         this->appendArgs(uniformDataPtr, uniformFlagsPtr, std::forward<Args>(remainder)...);
296     }
297 
298 #ifdef SK_DEBUG
299     using child_iterator = std::vector<SkRuntimeEffect::Child>::const_iterator;
300     using uniform_iterator = std::vector<SkRuntimeEffect::Uniform>::const_iterator;
301 
302     // Validates that all args passed to the template factory have the right names, sizes, and types
checkArgs(uniform_iterator uIter,uniform_iterator uEnd,child_iterator cIter,child_iterator cEnd)303     static void checkArgs(uniform_iterator uIter,
304                           uniform_iterator uEnd,
305                           child_iterator cIter,
306                           child_iterator cEnd) {
307         SkASSERTF(uIter == uEnd, "Expected more uniforms, starting with '%s'", uIter->name.c_str());
308         SkASSERTF(cIter == cEnd, "Expected more children, starting with '%s'", cIter->name.c_str());
309     }
checkOneChild(child_iterator cIter,child_iterator cEnd,const char * name)310     static void checkOneChild(child_iterator cIter, child_iterator cEnd, const char* name) {
311         SkASSERTF(cIter != cEnd, "Too many children, wasn't expecting '%s'", name);
312         SkASSERTF(cIter->name.equals(name),
313                   "Expected child '%s', got '%s' instead",
314                   cIter->name.c_str(), name);
315     }
316     template <typename... Args>
checkArgs(uniform_iterator uIter,uniform_iterator uEnd,child_iterator cIter,child_iterator cEnd,const char * name,std::unique_ptr<GrFragmentProcessor> && child,Args &&...remainder)317     static void checkArgs(uniform_iterator uIter,
318                           uniform_iterator uEnd,
319                           child_iterator cIter,
320                           child_iterator cEnd,
321                           const char* name,
322                           std::unique_ptr<GrFragmentProcessor>&& child,
323                           Args&&... remainder) {
324         // NOTE: This function (necessarily) gets an rvalue reference to child, but deliberately
325         // does not use it. We leave it intact, and our caller (Make) will pass another rvalue
326         // reference to appendArgs, which will then move it to call addChild.
327         checkOneChild(cIter, cEnd, name);
328         checkArgs(uIter, uEnd, ++cIter, cEnd, std::forward<Args>(remainder)...);
329     }
330     template <typename... Args>
checkArgs(uniform_iterator uIter,uniform_iterator uEnd,child_iterator cIter,child_iterator cEnd,const char * name,GrIgnoreOptFlags && child,Args &&...remainder)331     static void checkArgs(uniform_iterator uIter,
332                           uniform_iterator uEnd,
333                           child_iterator cIter,
334                           child_iterator cEnd,
335                           const char* name,
336                           GrIgnoreOptFlags&& child,
337                           Args&&... remainder) {
338         // NOTE: This function (necessarily) gets an rvalue reference to child, but deliberately
339         // does not use it. We leave it intact, and our caller (Make) will pass another rvalue
340         // reference to appendArgs, which will then move it to call addChild.
341         checkOneChild(cIter, cEnd, name);
342         checkArgs(uIter, uEnd, ++cIter, cEnd, std::forward<Args>(remainder)...);
343     }
344     template <typename T, typename... Args>
checkArgs(uniform_iterator uIter,uniform_iterator uEnd,child_iterator cIter,child_iterator cEnd,const char * name,const GrSpecializedUniform<T> & val,Args &&...remainder)345     static void checkArgs(uniform_iterator uIter,
346                           uniform_iterator uEnd,
347                           child_iterator cIter,
348                           child_iterator cEnd,
349                           const char* name,
350                           const GrSpecializedUniform<T>& val,
351                           Args&&... remainder) {
352         static_assert(!std::is_array<T>::value);  // No specializing arrays
353         checkArgs(uIter, uEnd, cIter, cEnd, name, val.value, std::forward<Args>(remainder)...);
354     }
355     template <typename T, typename... Args>
checkArgs(uniform_iterator uIter,uniform_iterator uEnd,child_iterator cIter,child_iterator cEnd,const char * name,const GrOptionalUniform<T> & val,Args &&...remainder)356     static void checkArgs(uniform_iterator uIter,
357                           uniform_iterator uEnd,
358                           child_iterator cIter,
359                           child_iterator cEnd,
360                           const char* name,
361                           const GrOptionalUniform<T>& val,
362                           Args&&... remainder) {
363         if (val.enabled) {
364             checkArgs(uIter, uEnd, cIter, cEnd, name, val.value, std::forward<Args>(remainder)...);
365         } else {
366             checkArgs(uIter, uEnd, cIter, cEnd, std::forward<Args>(remainder)...);
367         }
368     }
369     template <typename T>
checkOneUniform(uniform_iterator uIter,uniform_iterator uEnd,const char * name,const T *,size_t valSize)370     static void checkOneUniform(uniform_iterator uIter,
371                                 uniform_iterator uEnd,
372                                 const char* name,
373                                 const T* /*val*/,
374                                 size_t valSize) {
375         SkASSERTF(uIter != uEnd, "Too many uniforms, wasn't expecting '%s'", name);
376         SkASSERTF(uIter->name.equals(name),
377                   "Expected uniform '%s', got '%s' instead",
378                   uIter->name.c_str(), name);
379         SkASSERTF(uIter->sizeInBytes() == valSize,
380                   "Expected uniform '%s' to be %zu bytes, got %zu instead",
381                   name, uIter->sizeInBytes(), valSize);
382         SkASSERTF(GrFPUniformType<T>::value == uIter->type,
383                   "Wrong type for uniform '%s'",
384                   name);
385     }
386     template <typename T, typename... Args>
checkArgs(uniform_iterator uIter,uniform_iterator uEnd,child_iterator cIter,child_iterator cEnd,const char * name,SkSpan<T> val,Args &&...remainder)387     static void checkArgs(uniform_iterator uIter,
388                           uniform_iterator uEnd,
389                           child_iterator cIter,
390                           child_iterator cEnd,
391                           const char* name,
392                           SkSpan<T> val,
393                           Args&&... remainder) {
394         checkOneUniform(uIter, uEnd, name, val.data(), val.size_bytes());
395         checkArgs(++uIter, uEnd, cIter, cEnd, std::forward<Args>(remainder)...);
396     }
397     template <typename T, typename... Args>
checkArgs(uniform_iterator uIter,uniform_iterator uEnd,child_iterator cIter,child_iterator cEnd,const char * name,const T & val,Args &&...remainder)398     static void checkArgs(uniform_iterator uIter,
399                           uniform_iterator uEnd,
400                           child_iterator cIter,
401                           child_iterator cEnd,
402                           const char* name,
403                           const T& val,
404                           Args&&... remainder) {
405         checkOneUniform(uIter, uEnd, name, &val, sizeof(val));
406         checkArgs(++uIter, uEnd, cIter, cEnd, std::forward<Args>(remainder)...);
407     }
408 #endif
409 
410     sk_sp<SkRuntimeEffect> fEffect;
411     const char*            fName;
412     uint32_t               fUniformSize;
413     int                    fInputChildIndex = -1;
414     int                    fDestColorChildIndex = -1;
415 
416     GR_DECLARE_FRAGMENT_PROCESSOR_TEST
417 
418     using INHERITED = GrFragmentProcessor;
419 
420     friend class GrSkSLFPFactory;
421 };
422 
423 GR_MAKE_BITFIELD_CLASS_OPS(GrSkSLFP::OptFlags)
424 
425 #endif
426