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