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