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