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