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