• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 Google LLC
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 #include "include/effects/SkRuntimeEffect.h"
9 
10 #include "include/core/SkCapabilities.h"
11 #include "include/core/SkColorFilter.h"
12 #include "include/core/SkData.h"
13 #include "include/core/SkSurface.h"
14 #include "include/private/base/SkMutex.h"
15 #include "include/private/base/SkOnce.h"
16 #include "include/sksl/DSLCore.h"
17 #include "src/base/SkUtils.h"
18 #include "src/core/SkBlenderBase.h"
19 #include "src/core/SkCanvasPriv.h"
20 #include "src/core/SkColorFilterBase.h"
21 #include "src/core/SkColorSpacePriv.h"
22 #include "src/core/SkColorSpaceXformSteps.h"
23 #include "src/core/SkLRUCache.h"
24 #include "src/core/SkMatrixProvider.h"
25 #include "src/core/SkOpts.h"
26 #include "src/core/SkRasterPipeline.h"
27 #include "src/core/SkReadBuffer.h"
28 #include "src/core/SkRuntimeEffectPriv.h"
29 #include "src/core/SkVM.h"
30 #include "src/core/SkWriteBuffer.h"
31 #include "src/shaders/SkLocalMatrixShader.h"
32 #include "src/sksl/SkSLAnalysis.h"
33 #include "src/sksl/SkSLBuiltinTypes.h"
34 #include "src/sksl/SkSLCompiler.h"
35 #include "src/sksl/SkSLProgramSettings.h"
36 #include "src/sksl/SkSLUtil.h"
37 #include "src/sksl/analysis/SkSLProgramUsage.h"
38 #include "src/sksl/codegen/SkSLRasterPipelineBuilder.h"
39 #include "src/sksl/codegen/SkSLVMCodeGenerator.h"
40 #include "src/sksl/ir/SkSLFunctionDefinition.h"
41 #include "src/sksl/ir/SkSLProgram.h"
42 #include "src/sksl/ir/SkSLVarDeclarations.h"
43 #include "src/sksl/tracing/SkVMDebugTrace.h"
44 
45 #if defined(SK_GANESH)
46 #include "include/gpu/GrRecordingContext.h"
47 #include "src/gpu/SkBackingFit.h"
48 #include "src/gpu/ganesh/GrCaps.h"
49 #include "src/gpu/ganesh/GrColorInfo.h"
50 #include "src/gpu/ganesh/GrFPArgs.h"
51 #include "src/gpu/ganesh/GrImageInfo.h"
52 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
53 #include "src/gpu/ganesh/SurfaceFillContext.h"
54 #include "src/gpu/ganesh/effects/GrMatrixEffect.h"
55 #include "src/gpu/ganesh/effects/GrSkSLFP.h"
56 #include "src/image/SkImage_Gpu.h"
57 #endif
58 
59 #if defined(SK_GRAPHITE)
60 #include "src/gpu/graphite/KeyContext.h"
61 #include "src/gpu/graphite/KeyHelpers.h"
62 #include "src/gpu/graphite/PaintParamsKey.h"
63 #endif
64 
65 // This flag can be enabled to use the new Raster Pipeline code generator for SkSL.
66 //#define SK_ENABLE_SKSL_IN_RASTER_PIPELINE
67 
68 #ifdef SK_ENABLE_SKSL_IN_RASTER_PIPELINE
69 #include "src/core/SkStreamPriv.h"
70 #include "src/sksl/codegen/SkSLRasterPipelineCodeGenerator.h"
71 #include "src/sksl/tracing/SkRPDebugTrace.h"
72 constexpr bool kRPEnableLiveTrace = false;
73 #endif
74 
75 #include <algorithm>
76 
77 #if defined(SK_BUILD_FOR_DEBUGGER)
78     #define SK_LENIENT_SKSL_DESERIALIZATION 1
79 #else
80     #define SK_LENIENT_SKSL_DESERIALIZATION 0
81 #endif
82 
83 #ifdef SK_ENABLE_SKSL
84 
85 using ChildType = SkRuntimeEffect::ChildType;
86 
init_uniform_type(const SkSL::Context & ctx,const SkSL::Type * type,SkRuntimeEffect::Uniform * v)87 static bool init_uniform_type(const SkSL::Context& ctx,
88                               const SkSL::Type* type,
89                               SkRuntimeEffect::Uniform* v) {
90     using Type = SkRuntimeEffect::Uniform::Type;
91     if (type->matches(*ctx.fTypes.fFloat))    { v->type = Type::kFloat;    return true; }
92     if (type->matches(*ctx.fTypes.fHalf))     { v->type = Type::kFloat;    return true; }
93     if (type->matches(*ctx.fTypes.fFloat2))   { v->type = Type::kFloat2;   return true; }
94     if (type->matches(*ctx.fTypes.fHalf2))    { v->type = Type::kFloat2;   return true; }
95     if (type->matches(*ctx.fTypes.fFloat3))   { v->type = Type::kFloat3;   return true; }
96     if (type->matches(*ctx.fTypes.fHalf3))    { v->type = Type::kFloat3;   return true; }
97     if (type->matches(*ctx.fTypes.fFloat4))   { v->type = Type::kFloat4;   return true; }
98     if (type->matches(*ctx.fTypes.fHalf4))    { v->type = Type::kFloat4;   return true; }
99     if (type->matches(*ctx.fTypes.fFloat2x2)) { v->type = Type::kFloat2x2; return true; }
100     if (type->matches(*ctx.fTypes.fHalf2x2))  { v->type = Type::kFloat2x2; return true; }
101     if (type->matches(*ctx.fTypes.fFloat3x3)) { v->type = Type::kFloat3x3; return true; }
102     if (type->matches(*ctx.fTypes.fHalf3x3))  { v->type = Type::kFloat3x3; return true; }
103     if (type->matches(*ctx.fTypes.fFloat4x4)) { v->type = Type::kFloat4x4; return true; }
104     if (type->matches(*ctx.fTypes.fHalf4x4))  { v->type = Type::kFloat4x4; return true; }
105 
106     if (type->matches(*ctx.fTypes.fInt))  { v->type = Type::kInt;  return true; }
107     if (type->matches(*ctx.fTypes.fInt2)) { v->type = Type::kInt2; return true; }
108     if (type->matches(*ctx.fTypes.fInt3)) { v->type = Type::kInt3; return true; }
109     if (type->matches(*ctx.fTypes.fInt4)) { v->type = Type::kInt4; return true; }
110 
111     return false;
112 }
113 
VarAsUniform(const SkSL::Variable & var,const SkSL::Context & context,size_t * offset)114 SkRuntimeEffect::Uniform SkRuntimeEffectPriv::VarAsUniform(const SkSL::Variable& var,
115                                                            const SkSL::Context& context,
116                                                            size_t* offset) {
117     using Uniform = SkRuntimeEffect::Uniform;
118     SkASSERT(var.modifiers().fFlags & SkSL::Modifiers::kUniform_Flag);
119     Uniform uni;
120     uni.name = var.name();
121     uni.flags = 0;
122     uni.count = 1;
123 
124     const SkSL::Type* type = &var.type();
125     if (type->isArray()) {
126         uni.flags |= Uniform::kArray_Flag;
127         uni.count = type->columns();
128         type = &type->componentType();
129     }
130 
131     if (type->hasPrecision() && !type->highPrecision()) {
132         uni.flags |= Uniform::kHalfPrecision_Flag;
133     }
134 
135     SkAssertResult(init_uniform_type(context, type, &uni));
136     if (var.modifiers().fLayout.fFlags & SkSL::Layout::Flag::kColor_Flag) {
137         uni.flags |= Uniform::kColor_Flag;
138     }
139 
140     uni.offset = *offset;
141     *offset += uni.sizeInBytes();
142     SkASSERT(SkIsAlign4(*offset));
143     return uni;
144 }
145 
TransformUniforms(SkSpan<const SkRuntimeEffect::Uniform> uniforms,sk_sp<const SkData> originalData,const SkColorSpace * dstCS)146 sk_sp<const SkData> SkRuntimeEffectPriv::TransformUniforms(
147         SkSpan<const SkRuntimeEffect::Uniform> uniforms,
148         sk_sp<const SkData> originalData,
149         const SkColorSpace* dstCS) {
150     SkColorSpaceXformSteps steps(sk_srgb_singleton(), kUnpremul_SkAlphaType,
151                                  dstCS,               kUnpremul_SkAlphaType);
152     return TransformUniforms(uniforms, std::move(originalData), steps);
153 }
154 
TransformUniforms(SkSpan<const SkRuntimeEffect::Uniform> uniforms,sk_sp<const SkData> originalData,const SkColorSpaceXformSteps & steps)155 sk_sp<const SkData> SkRuntimeEffectPriv::TransformUniforms(
156         SkSpan<const SkRuntimeEffect::Uniform> uniforms,
157         sk_sp<const SkData> originalData,
158         const SkColorSpaceXformSteps& steps) {
159     using Flags = SkRuntimeEffect::Uniform::Flags;
160     using Type  = SkRuntimeEffect::Uniform::Type;
161 
162     sk_sp<SkData> data = nullptr;
163     auto writableData = [&]() {
164         if (!data) {
165             data = SkData::MakeWithCopy(originalData->data(), originalData->size());
166         }
167         return data->writable_data();
168     };
169 
170     for (const auto& u : uniforms) {
171         if (u.flags & Flags::kColor_Flag) {
172             SkASSERT(u.type == Type::kFloat3 || u.type == Type::kFloat4);
173             if (steps.flags.mask()) {
174                 float* color = SkTAddOffset<float>(writableData(), u.offset);
175                 if (u.type == Type::kFloat4) {
176                     // RGBA, easy case
177                     for (int i = 0; i < u.count; ++i) {
178                         steps.apply(color);
179                         color += 4;
180                     }
181                 } else {
182                     // RGB, need to pad out to include alpha. Technically, this isn't necessary,
183                     // because steps shouldn't include unpremul or premul, and thus shouldn't
184                     // read or write the fourth element. But let's be safe.
185                     float rgba[4];
186                     for (int i = 0; i < u.count; ++i) {
187                         memcpy(rgba, color, 3 * sizeof(float));
188                         rgba[3] = 1.0f;
189                         steps.apply(rgba);
190                         memcpy(color, rgba, 3 * sizeof(float));
191                         color += 3;
192                     }
193                 }
194             }
195         }
196     }
197     return data ? data : originalData;
198 }
199 
getRPProgram() const200 const SkSL::RP::Program* SkRuntimeEffect::getRPProgram() const {
201     // Lazily compile the program the first time `getRPProgram` is called.
202     // By using an SkOnce, we avoid thread hazards and behave in a conceptually const way, but we
203     // can avoid the cost of invoking the RP code generator until it's actually needed.
204     fCompileRPProgramOnce([&] {
205 #ifdef SK_ENABLE_SKSL_IN_RASTER_PIPELINE
206         SkSL::SkRPDebugTrace debugTrace;
207         const_cast<SkRuntimeEffect*>(this)->fRPProgram =
208                 MakeRasterPipelineProgram(*fBaseProgram,
209                                           fMain,
210                                           kRPEnableLiveTrace ? &debugTrace : nullptr);
211         if (kRPEnableLiveTrace) {
212             if (fRPProgram) {
213                 SkDebugf("-----\n\n");
214                 SkDebugfStream stream;
215                 fRPProgram->dump(&stream);
216                 SkDebugf("\n-----\n\n");
217             } else {
218                 SkDebugf("----- RP unsupported -----\n\n");
219             }
220         }
221 #endif
222     });
223 
224     return fRPProgram.get();
225 }
226 
uniforms_as_span(const SkData * inputs)227 [[maybe_unused]] static SkSpan<const float> uniforms_as_span(const SkData* inputs) {
228     SkASSERT(inputs);
229     return SkSpan<const float>{static_cast<const float*>(inputs->data()),
230                                inputs->size() / sizeof(float)};
231 }
232 
233 class RuntimeEffectRPCallbacks : public SkSL::RP::Callbacks {
234 public:
RuntimeEffectRPCallbacks(const SkStageRec & s,const SkShaderBase::MatrixRec & m,SkSpan<const SkRuntimeEffect::ChildPtr> c,SkSpan<const SkSL::SampleUsage> u)235     RuntimeEffectRPCallbacks(const SkStageRec& s,
236                              const SkShaderBase::MatrixRec& m,
237                              SkSpan<const SkRuntimeEffect::ChildPtr> c,
238                              SkSpan<const SkSL::SampleUsage> u)
239             : fStage(s), fMatrix(m), fChildren(c), fSampleUsages(u) {}
240 
appendShader(int index)241     bool appendShader(int index) override {
242         if (SkShader* shader = fChildren[index].shader()) {
243             if (fSampleUsages[index].isPassThrough()) {
244                 // Given a passthrough sample, the total-matrix is still as valid as before.
245                 return as_SB(shader)->appendStages(fStage, fMatrix);
246             }
247             // For a non-passthrough sample, we need to explicitly mark the total-matrix as invalid.
248             SkShaderBase::MatrixRec nonPassthroughMatrix = fMatrix;
249             nonPassthroughMatrix.markTotalMatrixInvalid();
250             return as_SB(shader)->appendStages(fStage, nonPassthroughMatrix);
251         }
252         // Return the paint color when a null child shader is evaluated.
253         fStage.fPipeline->append_constant_color(fStage.fAlloc, fStage.fPaint.getColor4f());
254         return true;
255     }
appendColorFilter(int index)256     bool appendColorFilter(int index) override {
257         if (SkColorFilter* colorFilter = fChildren[index].colorFilter()) {
258             return as_CFB(colorFilter)->appendStages(fStage, /*shaderIsOpaque=*/false);
259         }
260         // Return the original color as-is when a null child color filter is evaluated.
261         return true;
262     }
appendBlender(int index)263     bool appendBlender(int index) override {
264         // TODO: SkBlender does not yet support appendStages
265         return false;
266     }
toLinearSrgb()267     void toLinearSrgb() override {
268         // TODO: SkColorSpaceXformSteps?
269     }
fromLinearSrgb()270     void fromLinearSrgb() override {
271         // TODO: SkColorSpaceXformSteps?
272     }
273 
274     const SkStageRec& fStage;
275     const SkShaderBase::MatrixRec& fMatrix;
276     SkSpan<const SkRuntimeEffect::ChildPtr> fChildren;
277     SkSpan<const SkSL::SampleUsage> fSampleUsages;
278 };
279 
CanDraw(const SkCapabilities * caps,const SkSL::Program * program)280 bool SkRuntimeEffectPriv::CanDraw(const SkCapabilities* caps, const SkSL::Program* program) {
281     SkASSERT(caps && program);
282     SkASSERT(program->fConfig->enforcesSkSLVersion());
283     return program->fConfig->fRequiredSkSLVersion <= caps->skslVersion();
284 }
285 
CanDraw(const SkCapabilities * caps,const SkRuntimeEffect * effect)286 bool SkRuntimeEffectPriv::CanDraw(const SkCapabilities* caps, const SkRuntimeEffect* effect) {
287     SkASSERT(effect);
288     return CanDraw(caps, effect->fBaseProgram.get());
289 }
290 
291 //////////////////////////////////////////////////////////////////////////////
292 
flattenable_is_valid_as_child(const SkFlattenable * f)293 static bool flattenable_is_valid_as_child(const SkFlattenable* f) {
294     if (!f) { return true; }
295     switch (f->getFlattenableType()) {
296         case SkFlattenable::kSkShader_Type:
297         case SkFlattenable::kSkColorFilter_Type:
298         case SkFlattenable::kSkBlender_Type:
299             return true;
300         default:
301             return false;
302     }
303 }
304 
ChildPtr(sk_sp<SkFlattenable> f)305 SkRuntimeEffect::ChildPtr::ChildPtr(sk_sp<SkFlattenable> f) : fChild(std::move(f)) {
306     SkASSERT(flattenable_is_valid_as_child(fChild.get()));
307 }
308 
make_skvm_debug_trace(SkRuntimeEffect * effect,const SkIPoint & coord)309 static sk_sp<SkSL::SkVMDebugTrace> make_skvm_debug_trace(SkRuntimeEffect* effect,
310                                                          const SkIPoint& coord) {
311     auto debugTrace = sk_make_sp<SkSL::SkVMDebugTrace>();
312     debugTrace->setSource(effect->source());
313     debugTrace->setTraceCoord(coord);
314     return debugTrace;
315 }
316 
child_type(const SkSL::Type & type)317 static ChildType child_type(const SkSL::Type& type) {
318     switch (type.typeKind()) {
319         case SkSL::Type::TypeKind::kBlender:     return ChildType::kBlender;
320         case SkSL::Type::TypeKind::kColorFilter: return ChildType::kColorFilter;
321         case SkSL::Type::TypeKind::kShader:      return ChildType::kShader;
322         default: SkUNREACHABLE;
323     }
324 }
325 
verify_child_effects(const std::vector<SkRuntimeEffect::Child> & reflected,SkSpan<SkRuntimeEffect::ChildPtr> effectPtrs)326 static bool verify_child_effects(const std::vector<SkRuntimeEffect::Child>& reflected,
327                                  SkSpan<SkRuntimeEffect::ChildPtr> effectPtrs) {
328     // Verify that the number of passed-in child-effect pointers matches the SkSL code.
329     if (reflected.size() != effectPtrs.size()) {
330         return false;
331     }
332 
333     // Verify that each child object's type matches its declared type in the SkSL.
334     for (size_t i = 0; i < effectPtrs.size(); ++i) {
335         std::optional<ChildType> effectType = effectPtrs[i].type();
336         if (effectType && effectType != reflected[i].type) {
337             return false;
338         }
339     }
340     return true;
341 }
342 
343 /**
344  * If `effect` is specified, then the number and type of child objects are validated against the
345  * children() of `effect`. If it's nullptr, this is skipped, allowing deserialization of children,
346  * even when the effect could not be constructed (ie, due to malformed SkSL).
347  */
read_child_effects(SkReadBuffer & buffer,const SkRuntimeEffect * effect,SkTArray<SkRuntimeEffect::ChildPtr> * children)348 static bool read_child_effects(SkReadBuffer& buffer,
349                                const SkRuntimeEffect* effect,
350                                SkTArray<SkRuntimeEffect::ChildPtr>* children) {
351     size_t childCount = buffer.read32();
352     if (effect && !buffer.validate(childCount == effect->children().size())) {
353         return false;
354     }
355 
356     children->clear();
357     children->reserve_back(childCount);
358 
359     for (size_t i = 0; i < childCount; i++) {
360         sk_sp<SkFlattenable> obj(buffer.readRawFlattenable());
361         if (!flattenable_is_valid_as_child(obj.get())) {
362             buffer.validate(false);
363             return false;
364         }
365         children->push_back(std::move(obj));
366     }
367 
368     // If we are validating against an effect, make sure any (non-null) children are the right type
369     if (effect) {
370         auto childInfo = effect->children();
371         SkASSERT(childInfo.size() == SkToSizeT(children->size()));
372         for (size_t i = 0; i < childCount; i++) {
373             std::optional<ChildType> ct = (*children)[i].type();
374             if (ct.has_value() && (*ct) != childInfo[i].type) {
375                 buffer.validate(false);
376             }
377         }
378     }
379 
380     return buffer.isValid();
381 }
382 
write_child_effects(SkWriteBuffer & buffer,const std::vector<SkRuntimeEffect::ChildPtr> & children)383 static void write_child_effects(SkWriteBuffer& buffer,
384                                 const std::vector<SkRuntimeEffect::ChildPtr>& children) {
385     buffer.write32(children.size());
386     for (const auto& child : children) {
387         buffer.writeFlattenable(child.flattenable());
388     }
389 }
390 
make_skvm_uniforms(skvm::Builder * p,skvm::Uniforms * uniforms,size_t inputSize,const SkData & inputs)391 static std::vector<skvm::Val> make_skvm_uniforms(skvm::Builder* p,
392                                                  skvm::Uniforms* uniforms,
393                                                  size_t inputSize,
394                                                  const SkData& inputs) {
395     SkASSERTF(!(inputSize & 3), "inputSize was %zu, expected a multiple of 4", inputSize);
396 
397     const int32_t* data = reinterpret_cast<const int32_t*>(inputs.data());
398     const size_t uniformCount = inputSize / sizeof(int32_t);
399     std::vector<skvm::Val> uniform;
400     uniform.reserve(uniformCount);
401     for (size_t index = 0; index < uniformCount; ++index) {
402         int32_t bits;
403         memcpy(&bits, data + index, sizeof(int32_t));
404         uniform.push_back(p->uniform32(uniforms->push(bits)).id);
405     }
406 
407     return uniform;
408 }
409 
MakeSettings(const Options & options)410 SkSL::ProgramSettings SkRuntimeEffect::MakeSettings(const Options& options) {
411     SkSL::ProgramSettings settings;
412     settings.fInlineThreshold = 0;
413     settings.fForceNoInline = options.forceUnoptimized;
414     settings.fOptimize = !options.forceUnoptimized;
415     settings.fMaxVersionAllowed = options.maxVersionAllowed;
416 
417     // SkSL created by the GPU backend is typically parsed, converted to a backend format,
418     // and the IR is immediately discarded. In that situation, it makes sense to use node
419     // pools to accelerate the IR allocations. Here, SkRuntimeEffect instances are often
420     // long-lived (especially those created internally for runtime FPs). In this situation,
421     // we're willing to pay for a slightly longer compile so that we don't waste huge
422     // amounts of memory.
423     settings.fUseMemoryPool = false;
424     return settings;
425 }
426 
427 // TODO: Many errors aren't caught until we process the generated Program here. Catching those
428 // in the IR generator would provide better errors messages (with locations).
429 #define RETURN_FAILURE(...) return Result{nullptr, SkStringPrintf(__VA_ARGS__)}
430 
MakeFromSource(SkString sksl,const Options & options,SkSL::ProgramKind kind)431 SkRuntimeEffect::Result SkRuntimeEffect::MakeFromSource(SkString sksl,
432                                                         const Options& options,
433                                                         SkSL::ProgramKind kind) {
434     SkSL::Compiler compiler(SkSL::ShaderCapsFactory::Standalone());
435     SkSL::ProgramSettings settings = MakeSettings(options);
436     std::unique_ptr<SkSL::Program> program =
437             compiler.convertProgram(kind, std::string(sksl.c_str(), sksl.size()), settings);
438 
439     if (!program) {
440         RETURN_FAILURE("%s", compiler.errorText().c_str());
441     }
442 
443     return MakeInternal(std::move(program), options, kind);
444 }
445 
MakeInternal(std::unique_ptr<SkSL::Program> program,const Options & options,SkSL::ProgramKind kind)446 SkRuntimeEffect::Result SkRuntimeEffect::MakeInternal(std::unique_ptr<SkSL::Program> program,
447                                                       const Options& options,
448                                                       SkSL::ProgramKind kind) {
449     SkSL::Compiler compiler(SkSL::ShaderCapsFactory::Standalone());
450 
451     uint32_t flags = 0;
452     switch (kind) {
453         case SkSL::ProgramKind::kPrivateRuntimeColorFilter:
454         case SkSL::ProgramKind::kRuntimeColorFilter:
455             // TODO(skia:11209): Figure out a way to run ES3+ color filters on the CPU. This doesn't
456             // need to be fast - it could just be direct IR evaluation. But without it, there's no
457             // way for us to fully implement the SkColorFilter API (eg, `filterColor`)
458             if (!SkRuntimeEffectPriv::CanDraw(SkCapabilities::RasterBackend().get(),
459                                               program.get())) {
460                 RETURN_FAILURE("SkSL color filters must target #version 100");
461             }
462             flags |= kAllowColorFilter_Flag;
463             break;
464         case SkSL::ProgramKind::kPrivateRuntimeShader:
465         case SkSL::ProgramKind::kRuntimeShader:
466             flags |= kAllowShader_Flag;
467             break;
468         case SkSL::ProgramKind::kPrivateRuntimeBlender:
469         case SkSL::ProgramKind::kRuntimeBlender:
470             flags |= kAllowBlender_Flag;
471             break;
472         default:
473             SkUNREACHABLE;
474     }
475 
476     // Find 'main', then locate the sample coords parameter. (It might not be present.)
477     const SkSL::FunctionDeclaration* main = program->getFunction("main");
478     if (!main) {
479         RETURN_FAILURE("missing 'main' function");
480     }
481     const auto& mainParams = main->parameters();
482     auto iter = std::find_if(mainParams.begin(), mainParams.end(), [](const SkSL::Variable* p) {
483         return p->modifiers().fLayout.fBuiltin == SK_MAIN_COORDS_BUILTIN;
484     });
485     const SkSL::ProgramUsage::VariableCounts sampleCoordsUsage =
486             iter != mainParams.end() ? program->usage()->get(**iter)
487                                      : SkSL::ProgramUsage::VariableCounts{};
488 
489     if (sampleCoordsUsage.fRead || sampleCoordsUsage.fWrite) {
490         flags |= kUsesSampleCoords_Flag;
491     }
492 
493     // Color filters and blends are not allowed to depend on position (local or device) in any way.
494     // The signature of main, and the declarations in sksl_rt_colorfilter/sksl_rt_blend should
495     // guarantee this.
496     if (flags & (kAllowColorFilter_Flag | kAllowBlender_Flag)) {
497         SkASSERT(!(flags & kUsesSampleCoords_Flag));
498         SkASSERT(!SkSL::Analysis::ReferencesFragCoords(*program));
499     }
500 
501     if (SkSL::Analysis::CallsSampleOutsideMain(*program)) {
502         flags |= kSamplesOutsideMain_Flag;
503     }
504 
505     // Determine if this effect uses of the color transform intrinsics. Effects need to know this
506     // so they can allocate color transform objects, etc.
507     if (SkSL::Analysis::CallsColorTransformIntrinsics(*program)) {
508         flags |= kUsesColorTransform_Flag;
509     }
510 
511     // Shaders are the only thing that cares about this, but it's inexpensive (and safe) to call.
512     if (SkSL::Analysis::ReturnsOpaqueColor(*main->definition())) {
513         flags |= kAlwaysOpaque_Flag;
514     }
515 
516     size_t offset = 0;
517     std::vector<Uniform> uniforms;
518     std::vector<Child> children;
519     std::vector<SkSL::SampleUsage> sampleUsages;
520     int elidedSampleCoords = 0;
521     const SkSL::Context& ctx(compiler.context());
522 
523     // Go through program elements, pulling out information that we need
524     for (const SkSL::ProgramElement* elem : program->elements()) {
525         // Variables (uniform, etc.)
526         if (elem->is<SkSL::GlobalVarDeclaration>()) {
527             const SkSL::GlobalVarDeclaration& global = elem->as<SkSL::GlobalVarDeclaration>();
528             const SkSL::VarDeclaration& varDecl = global.declaration()->as<SkSL::VarDeclaration>();
529 
530             const SkSL::Variable& var = *varDecl.var();
531             const SkSL::Type& varType = var.type();
532 
533             // Child effects that can be sampled ('shader', 'colorFilter', 'blender')
534             if (varType.isEffectChild()) {
535                 Child c;
536                 c.name  = var.name();
537                 c.type  = child_type(varType);
538                 c.index = children.size();
539                 children.push_back(c);
540                 auto usage = SkSL::Analysis::GetSampleUsage(
541                         *program, var, sampleCoordsUsage.fWrite != 0, &elidedSampleCoords);
542                 // If the child is never sampled, we pretend that it's actually in PassThrough mode.
543                 // Otherwise, the GP code for collecting transforms and emitting transform code gets
544                 // very confused, leading to asserts and bad (backend) shaders. There's an implicit
545                 // assumption that every FP is used by its parent. (skbug.com/12429)
546                 sampleUsages.push_back(usage.isSampled() ? usage
547                                                          : SkSL::SampleUsage::PassThrough());
548             }
549             // 'uniform' variables
550             else if (var.modifiers().fFlags & SkSL::Modifiers::kUniform_Flag) {
551                 uniforms.push_back(SkRuntimeEffectPriv::VarAsUniform(var, ctx, &offset));
552             }
553         }
554     }
555 
556     // If the sample coords are never written to, then we will have converted sample calls that use
557     // them unmodified into "passthrough" sampling. If all references to the sample coords were of
558     // that form, then we don't actually "use" sample coords. We unset the flag to prevent creating
559     // an extra (unused) varying holding the coords.
560     if (elidedSampleCoords == sampleCoordsUsage.fRead && sampleCoordsUsage.fWrite == 0) {
561         flags &= ~kUsesSampleCoords_Flag;
562     }
563 
564 #undef RETURN_FAILURE
565 
566     sk_sp<SkRuntimeEffect> effect(new SkRuntimeEffect(std::move(program),
567                                                       options,
568                                                       *main->definition(),
569                                                       std::move(uniforms),
570                                                       std::move(children),
571                                                       std::move(sampleUsages),
572                                                       flags));
573     return Result{std::move(effect), SkString()};
574 }
575 
makeUnoptimizedClone()576 sk_sp<SkRuntimeEffect> SkRuntimeEffect::makeUnoptimizedClone() {
577     // Compile with maximally-permissive options; any restrictions we need to enforce were already
578     // handled when the original SkRuntimeEffect was made. We don't keep around the Options struct
579     // from when it was initially made so we don't know what was originally requested.
580     Options options;
581     options.forceUnoptimized = true;
582     options.maxVersionAllowed = SkSL::Version::k300;
583     options.allowPrivateAccess = true;
584 
585     // We do know the original ProgramKind, so we don't need to re-derive it.
586     SkSL::ProgramKind kind = fBaseProgram->fConfig->fKind;
587 
588     // Attempt to recompile the program's source with optimizations off. This ensures that the
589     // Debugger shows results on every line, even for things that could be optimized away (static
590     // branches, unused variables, etc). If recompilation fails, we fall back to the original code.
591     SkSL::Compiler compiler(SkSL::ShaderCapsFactory::Standalone());
592     SkSL::ProgramSettings settings = MakeSettings(options);
593     std::unique_ptr<SkSL::Program> program =
594             compiler.convertProgram(kind, *fBaseProgram->fSource, settings);
595 
596     if (!program) {
597         // Turning off compiler optimizations can theoretically expose a program error that
598         // had been optimized away (e.g. "all control paths return a value" might be found on a path
599         // that is completely eliminated in the optimized program).
600         // If this happens, the debugger will just have to show the optimized code.
601         return sk_ref_sp(this);
602     }
603 
604     SkRuntimeEffect::Result result = MakeInternal(std::move(program), options, kind);
605     if (!result.effect) {
606         // Nothing in MakeInternal should change as a result of optimizations being toggled.
607         SkDEBUGFAILF("makeUnoptimizedClone: MakeInternal failed\n%s",
608                      result.errorText.c_str());
609         return sk_ref_sp(this);
610     }
611 
612     return result.effect;
613 }
614 
MakeForColorFilter(SkString sksl,const Options & options)615 SkRuntimeEffect::Result SkRuntimeEffect::MakeForColorFilter(SkString sksl, const Options& options) {
616     auto programKind = options.allowPrivateAccess ? SkSL::ProgramKind::kPrivateRuntimeColorFilter
617                                                   : SkSL::ProgramKind::kRuntimeColorFilter;
618     auto result = MakeFromSource(std::move(sksl), options, programKind);
619     SkASSERT(!result.effect || result.effect->allowColorFilter());
620     return result;
621 }
622 
MakeForShader(SkString sksl,const Options & options)623 SkRuntimeEffect::Result SkRuntimeEffect::MakeForShader(SkString sksl, const Options& options) {
624     auto programKind = options.allowPrivateAccess ? SkSL::ProgramKind::kPrivateRuntimeShader
625                                                   : SkSL::ProgramKind::kRuntimeShader;
626     auto result = MakeFromSource(std::move(sksl), options, programKind);
627     SkASSERT(!result.effect || result.effect->allowShader());
628     return result;
629 }
630 
MakeForBlender(SkString sksl,const Options & options)631 SkRuntimeEffect::Result SkRuntimeEffect::MakeForBlender(SkString sksl, const Options& options) {
632     auto programKind = options.allowPrivateAccess ? SkSL::ProgramKind::kPrivateRuntimeBlender
633                                                   : SkSL::ProgramKind::kRuntimeBlender;
634     auto result = MakeFromSource(std::move(sksl), options, programKind);
635     SkASSERT(!result.effect || result.effect->allowBlender());
636     return result;
637 }
638 
SkMakeCachedRuntimeEffect(SkRuntimeEffect::Result (* make)(SkString sksl,const SkRuntimeEffect::Options &),SkString sksl)639 sk_sp<SkRuntimeEffect> SkMakeCachedRuntimeEffect(
640         SkRuntimeEffect::Result (*make)(SkString sksl, const SkRuntimeEffect::Options&),
641         SkString sksl) {
642     SK_BEGIN_REQUIRE_DENSE
643     struct Key {
644         uint32_t skslHashA;
645         uint32_t skslHashB;
646 
647         bool operator==(const Key& that) const {
648             return this->skslHashA == that.skslHashA
649                 && this->skslHashB == that.skslHashB;
650         }
651 
652         explicit Key(const SkString& sksl)
653             : skslHashA(SkOpts::hash(sksl.c_str(), sksl.size(), 0))
654             , skslHashB(SkOpts::hash(sksl.c_str(), sksl.size(), 1)) {}
655     };
656     SK_END_REQUIRE_DENSE
657 
658     static auto* mutex = new SkMutex;
659     static auto* cache = new SkLRUCache<Key, sk_sp<SkRuntimeEffect>>(11/*totally arbitrary*/);
660 
661     Key key(sksl);
662     {
663         SkAutoMutexExclusive _(*mutex);
664         if (sk_sp<SkRuntimeEffect>* found = cache->find(key)) {
665             return *found;
666         }
667     }
668 
669     SkRuntimeEffect::Options options;
670     SkRuntimeEffectPriv::AllowPrivateAccess(&options);
671 
672     auto [effect, err] = make(std::move(sksl), options);
673     if (!effect) {
674         SkDEBUGFAILF("%s", err.c_str());
675         return nullptr;
676     }
677     SkASSERT(err.isEmpty());
678 
679     {
680         SkAutoMutexExclusive _(*mutex);
681         cache->insert_or_update(key, effect);
682     }
683     return effect;
684 }
685 
uniform_element_size(SkRuntimeEffect::Uniform::Type type)686 static size_t uniform_element_size(SkRuntimeEffect::Uniform::Type type) {
687     switch (type) {
688         case SkRuntimeEffect::Uniform::Type::kFloat:  return sizeof(float);
689         case SkRuntimeEffect::Uniform::Type::kFloat2: return sizeof(float) * 2;
690         case SkRuntimeEffect::Uniform::Type::kFloat3: return sizeof(float) * 3;
691         case SkRuntimeEffect::Uniform::Type::kFloat4: return sizeof(float) * 4;
692 
693         case SkRuntimeEffect::Uniform::Type::kFloat2x2: return sizeof(float) * 4;
694         case SkRuntimeEffect::Uniform::Type::kFloat3x3: return sizeof(float) * 9;
695         case SkRuntimeEffect::Uniform::Type::kFloat4x4: return sizeof(float) * 16;
696 
697         case SkRuntimeEffect::Uniform::Type::kInt:  return sizeof(int);
698         case SkRuntimeEffect::Uniform::Type::kInt2: return sizeof(int) * 2;
699         case SkRuntimeEffect::Uniform::Type::kInt3: return sizeof(int) * 3;
700         case SkRuntimeEffect::Uniform::Type::kInt4: return sizeof(int) * 4;
701         default: SkUNREACHABLE;
702     }
703 }
704 
sizeInBytes() const705 size_t SkRuntimeEffect::Uniform::sizeInBytes() const {
706     static_assert(sizeof(int) == sizeof(float));
707     return uniform_element_size(this->type) * this->count;
708 }
709 
SkRuntimeEffect(std::unique_ptr<SkSL::Program> baseProgram,const Options & options,const SkSL::FunctionDefinition & main,std::vector<Uniform> && uniforms,std::vector<Child> && children,std::vector<SkSL::SampleUsage> && sampleUsages,uint32_t flags)710 SkRuntimeEffect::SkRuntimeEffect(std::unique_ptr<SkSL::Program> baseProgram,
711                                  const Options& options,
712                                  const SkSL::FunctionDefinition& main,
713                                  std::vector<Uniform>&& uniforms,
714                                  std::vector<Child>&& children,
715                                  std::vector<SkSL::SampleUsage>&& sampleUsages,
716                                  uint32_t flags)
717         : fHash(SkOpts::hash_fn(baseProgram->fSource->c_str(), baseProgram->fSource->size(), 0))
718         , fBaseProgram(std::move(baseProgram))
719         , fMain(main)
720         , fUniforms(std::move(uniforms))
721         , fChildren(std::move(children))
722         , fSampleUsages(std::move(sampleUsages))
723         , fFlags(flags) {
724     SkASSERT(fBaseProgram);
725     SkASSERT(fChildren.size() == fSampleUsages.size());
726 
727     // Everything from SkRuntimeEffect::Options which could influence the compiled result needs to
728     // be accounted for in `fHash`. If you've added a new field to Options and caused the static-
729     // assert below to trigger, please incorporate your field into `fHash` and update KnownOptions
730     // to match the layout of Options.
731     struct KnownOptions {
732         bool forceUnoptimized, allowPrivateAccess;
733         SkSL::Version maxVersionAllowed;
734     };
735     static_assert(sizeof(Options) == sizeof(KnownOptions));
736     fHash = SkOpts::hash_fn(&options.forceUnoptimized,
737                       sizeof(options.forceUnoptimized), fHash);
738     fHash = SkOpts::hash_fn(&options.allowPrivateAccess,
739                       sizeof(options.allowPrivateAccess), fHash);
740     fHash = SkOpts::hash_fn(&options.maxVersionAllowed,
741                       sizeof(options.maxVersionAllowed), fHash);
742 
743     fFilterColorProgram = SkFilterColorProgram::Make(this);
744 }
745 
746 SkRuntimeEffect::~SkRuntimeEffect() = default;
747 
source() const748 const std::string& SkRuntimeEffect::source() const {
749     return *fBaseProgram->fSource;
750 }
751 
uniformSize() const752 size_t SkRuntimeEffect::uniformSize() const {
753     return fUniforms.empty() ? 0
754                              : SkAlign4(fUniforms.back().offset + fUniforms.back().sizeInBytes());
755 }
756 
findUniform(std::string_view name) const757 const SkRuntimeEffect::Uniform* SkRuntimeEffect::findUniform(std::string_view name) const {
758     auto iter = std::find_if(fUniforms.begin(), fUniforms.end(), [name](const Uniform& u) {
759         return u.name == name;
760     });
761     return iter == fUniforms.end() ? nullptr : &(*iter);
762 }
763 
findChild(std::string_view name) const764 const SkRuntimeEffect::Child* SkRuntimeEffect::findChild(std::string_view name) const {
765     auto iter = std::find_if(fChildren.begin(), fChildren.end(), [name](const Child& c) {
766         return c.name == name;
767     });
768     return iter == fChildren.end() ? nullptr : &(*iter);
769 }
770 
Make(const SkRuntimeEffect * effect)771 std::unique_ptr<SkFilterColorProgram> SkFilterColorProgram::Make(const SkRuntimeEffect* effect) {
772     // Our per-effect program technique is only possible (and necessary) for color filters
773     if (!effect->allowColorFilter()) {
774         return nullptr;
775     }
776 
777     // TODO(skia:10479): Can we support this? When the color filter is invoked like this, there
778     // may not be a real working space? If there is, we'd need to add it as a parameter to eval,
779     // and then coordinate where the relevant uniforms go. For now, just fall back to the slow
780     // path if we see these intrinsics being called.
781     if (effect->usesColorTransform()) {
782         return nullptr;
783     }
784 
785     // We require that any children are color filters (not shaders or blenders). In theory, we could
786     // detect the coords being passed to shader children, and replicate those calls, but that's very
787     // complicated, and has diminishing returns. (eg, for table lookup color filters).
788     if (!std::all_of(effect->fChildren.begin(),
789                      effect->fChildren.end(),
790                      [](const SkRuntimeEffect::Child& c) {
791                          return c.type == ChildType::kColorFilter;
792                      })) {
793         return nullptr;
794     }
795 
796     skvm::Builder p;
797 
798     // For SkSL uniforms, we reserve space and allocate skvm Uniform ids for each one. When we run
799     // the program, these ids will be loads from the *first* arg ptr, the uniform data of the
800     // specific color filter instance.
801     skvm::Uniforms skslUniforms{p.uniform(), 0};
802     const size_t uniformCount = effect->uniformSize() / 4;
803     std::vector<skvm::Val> uniform;
804     uniform.reserve(uniformCount);
805     for (size_t i = 0; i < uniformCount; i++) {
806         uniform.push_back(p.uniform32(skslUniforms.push(/*placeholder*/ 0)).id);
807     }
808 
809     // We reserve a uniform color for each child invocation. While processing the SkSL, we record
810     // the index of the child, and the color being filtered (in a SampleCall struct).
811     // When we run this program later, we use the SampleCall to evaluate the correct child, and
812     // populate these uniform values. These Uniform ids are loads from the *second* arg ptr.
813     // If the color being passed is too complex for us to describe and re-create using SampleCall,
814     // we are unable to use this per-effect program, and callers will need to fall back to another
815     // (slower) implementation.
816     skvm::Uniforms childColorUniforms{p.uniform(), 0};
817     skvm::Color inputColor = p.uniformColor(/*placeholder*/ SkColors::kWhite, &childColorUniforms);
818     std::vector<SkFilterColorProgram::SampleCall> sampleCalls;
819 
820     class Callbacks : public SkSL::SkVMCallbacks {
821     public:
822         Callbacks(skvm::Builder* builder,
823                   const skvm::Uniforms* skslUniforms,
824                   skvm::Uniforms* childColorUniforms,
825                   skvm::Color inputColor,
826                   std::vector<SkFilterColorProgram::SampleCall>* sampleCalls)
827                 : fBuilder(builder)
828                 , fSkslUniforms(skslUniforms)
829                 , fChildColorUniforms(childColorUniforms)
830                 , fInputColor(inputColor)
831                 , fSampleCalls(sampleCalls) {}
832 
833         bool isSimpleUniform(skvm::Color c, int* baseOffset) {
834             skvm::Uniform ur, ug, ub, ua;
835             if (!fBuilder->allUniform(c.r.id, &ur, c.g.id, &ug, c.b.id, &ub, c.a.id, &ua)) {
836                 return false;
837             }
838             skvm::Ptr uniPtr = fSkslUniforms->base;
839             if (ur.ptr != uniPtr || ug.ptr != uniPtr || ub.ptr != uniPtr || ua.ptr != uniPtr) {
840                 return false;
841             }
842             *baseOffset = ur.offset;
843             return ug.offset == ur.offset + 4 &&
844                    ub.offset == ur.offset + 8 &&
845                    ua.offset == ur.offset + 12;
846         }
847 
848         static bool IDsEqual(skvm::Color x, skvm::Color y) {
849             return x.r.id == y.r.id && x.g.id == y.g.id && x.b.id == y.b.id && x.a.id == y.a.id;
850         }
851 
852         skvm::Color sampleColorFilter(int ix, skvm::Color c) override {
853             skvm::Color result =
854                     fBuilder->uniformColor(/*placeholder*/ SkColors::kWhite, fChildColorUniforms);
855             SkFilterColorProgram::SampleCall call;
856             call.fChild = ix;
857             if (IDsEqual(c, fInputColor)) {
858                 call.fKind = SkFilterColorProgram::SampleCall::Kind::kInputColor;
859             } else if (fBuilder->allImm(c.r.id, &call.fImm.fR,
860                                         c.g.id, &call.fImm.fG,
861                                         c.b.id, &call.fImm.fB,
862                                         c.a.id, &call.fImm.fA)) {
863                 call.fKind = SkFilterColorProgram::SampleCall::Kind::kImmediate;
864             } else if (auto it = std::find_if(fChildColors.begin(),
865                                               fChildColors.end(),
866                                               [&](skvm::Color x) { return IDsEqual(x, c); });
867                        it != fChildColors.end()) {
868                 call.fKind = SkFilterColorProgram::SampleCall::Kind::kPrevious;
869                 call.fPrevious = SkTo<int>(it - fChildColors.begin());
870             } else if (isSimpleUniform(c, &call.fOffset)) {
871                 call.fKind = SkFilterColorProgram::SampleCall::Kind::kUniform;
872             } else {
873                 fAllSampleCallsSupported = false;
874             }
875             fSampleCalls->push_back(call);
876             fChildColors.push_back(result);
877             return result;
878         }
879 
880         // We did an early return from this function if we saw any child that wasn't a shader, so
881         // it should be impossible for either of these callbacks to occur:
882         skvm::Color sampleShader(int, skvm::Coord) override {
883             SkDEBUGFAIL("Unexpected child type");
884             return {};
885         }
886         skvm::Color sampleBlender(int, skvm::Color, skvm::Color) override {
887             SkDEBUGFAIL("Unexpected child type");
888             return {};
889         }
890 
891         // We did an early return from this function if we saw any call to these intrinsics, so it
892         // should be impossible for either of these callbacks to occur:
893         skvm::Color toLinearSrgb(skvm::Color color) override {
894             SkDEBUGFAIL("Unexpected color transform intrinsic");
895             return {};
896         }
897         skvm::Color fromLinearSrgb(skvm::Color color) override {
898             SkDEBUGFAIL("Unexpected color transform intrinsic");
899             return {};
900         }
901 
902         skvm::Builder* fBuilder;
903         const skvm::Uniforms* fSkslUniforms;
904         skvm::Uniforms* fChildColorUniforms;
905         skvm::Color fInputColor;
906         std::vector<SkFilterColorProgram::SampleCall>* fSampleCalls;
907 
908         std::vector<skvm::Color> fChildColors;
909         bool fAllSampleCallsSupported = true;
910     };
911     Callbacks callbacks(&p, &skslUniforms, &childColorUniforms, inputColor, &sampleCalls);
912 
913     // Emit the skvm instructions for the SkSL
914     skvm::Coord zeroCoord = {p.splat(0.0f), p.splat(0.0f)};
915     skvm::Color result = SkSL::ProgramToSkVM(*effect->fBaseProgram,
916                                              effect->fMain,
917                                              &p,
918                                              /*debugTrace=*/nullptr,
919                                              SkSpan(uniform),
920                                              /*device=*/zeroCoord,
921                                              /*local=*/zeroCoord,
922                                              inputColor,
923                                              inputColor,
924                                              &callbacks);
925 
926     // Then store the result to the *third* arg ptr
927     p.store({skvm::PixelFormat::FLOAT, 32, 32, 32, 32, 0, 32, 64, 96},
928             p.varying<skvm::F32>(), result);
929 
930     if (!callbacks.fAllSampleCallsSupported) {
931         return nullptr;
932     }
933 
934     // This is conservative. If a filter gets the input color by sampling a null child, we'll
935     // return an (acceptable) false negative. All internal runtime color filters should work.
936     bool alphaUnchanged = (inputColor.a.id == result.a.id);
937 
938     // We'll use this program to filter one color at a time, don't bother with jit
939     return std::unique_ptr<SkFilterColorProgram>(
940             new SkFilterColorProgram(p.done(/*debug_name=*/nullptr, /*allow_jit=*/false),
941                                      std::move(sampleCalls),
942                                      alphaUnchanged));
943 }
944 
SkFilterColorProgram(skvm::Program program,std::vector<SampleCall> sampleCalls,bool alphaUnchanged)945 SkFilterColorProgram::SkFilterColorProgram(skvm::Program program,
946                                            std::vector<SampleCall> sampleCalls,
947                                            bool alphaUnchanged)
948         : fProgram(std::move(program))
949         , fSampleCalls(std::move(sampleCalls))
950         , fAlphaUnchanged(alphaUnchanged) {}
951 
eval(const SkPMColor4f & inColor,const void * uniformData,std::function<SkPMColor4f (int,SkPMColor4f)> evalChild) const952 SkPMColor4f SkFilterColorProgram::eval(
953         const SkPMColor4f& inColor,
954         const void* uniformData,
955         std::function<SkPMColor4f(int, SkPMColor4f)> evalChild) const {
956     // Our program defines sampling any child as returning a uniform color. Assemble a buffer
957     // containing those colors. The first entry is always the input color. Subsequent entries
958     // are for each sample call, based on the information in fSampleCalls. For any null children,
959     // the sample result is just the passed-in color.
960     SkSTArray<4, SkPMColor4f, true> childColors;
961     childColors.push_back(inColor);
962     for (const auto& s : fSampleCalls) {
963         SkPMColor4f passedColor = inColor;
964         switch (s.fKind) {
965             case SampleCall::Kind::kInputColor:                                             break;
966             case SampleCall::Kind::kImmediate:  passedColor = s.fImm;                       break;
967             case SampleCall::Kind::kPrevious:   passedColor = childColors[s.fPrevious + 1]; break;
968             case SampleCall::Kind::kUniform:
969                 passedColor = *SkTAddOffset<const SkPMColor4f>(uniformData, s.fOffset);
970                 break;
971         }
972         childColors.push_back(evalChild(s.fChild, passedColor));
973     }
974 
975     SkPMColor4f result;
976     fProgram.eval(1, uniformData, childColors.begin(), result.vec());
977     return result;
978 }
979 
getFilterColorProgram() const980 const SkFilterColorProgram* SkRuntimeEffect::getFilterColorProgram() const {
981     return fFilterColorProgram.get();
982 }
983 
984 ///////////////////////////////////////////////////////////////////////////////////////////////////
985 
986 #if defined(SK_GANESH)
make_effect_fp(sk_sp<SkRuntimeEffect> effect,const char * name,sk_sp<const SkData> uniforms,std::unique_ptr<GrFragmentProcessor> inputFP,std::unique_ptr<GrFragmentProcessor> destColorFP,SkSpan<const SkRuntimeEffect::ChildPtr> children,const GrFPArgs & childArgs)987 static GrFPResult make_effect_fp(sk_sp<SkRuntimeEffect> effect,
988                                  const char* name,
989                                  sk_sp<const SkData> uniforms,
990                                  std::unique_ptr<GrFragmentProcessor> inputFP,
991                                  std::unique_ptr<GrFragmentProcessor> destColorFP,
992                                  SkSpan<const SkRuntimeEffect::ChildPtr> children,
993                                  const GrFPArgs& childArgs) {
994     SkSTArray<8, std::unique_ptr<GrFragmentProcessor>> childFPs;
995     for (const auto& child : children) {
996         std::optional<ChildType> type = child.type();
997         if (type == ChildType::kShader) {
998             // Convert a SkShader into a child FP.
999             SkShaderBase::MatrixRec mRec(SkMatrix::I());
1000             mRec.markTotalMatrixInvalid();
1001             auto childFP = as_SB(child.shader())->asFragmentProcessor(childArgs, mRec);
1002             if (!childFP) {
1003                 return GrFPFailure(std::move(inputFP));
1004             }
1005             childFPs.push_back(std::move(childFP));
1006         } else if (type == ChildType::kColorFilter) {
1007             // Convert a SkColorFilter into a child FP.
1008             auto [success, childFP] = as_CFB(child.colorFilter())
1009                                               ->asFragmentProcessor(/*inputFP=*/nullptr,
1010                                                                     childArgs.fContext,
1011                                                                     *childArgs.fDstColorInfo,
1012                                                                     childArgs.fSurfaceProps);
1013             if (!success) {
1014                 return GrFPFailure(std::move(inputFP));
1015             }
1016             childFPs.push_back(std::move(childFP));
1017         } else if (type == ChildType::kBlender) {
1018             // Convert a SkBlender into a child FP.
1019             auto childFP = as_BB(child.blender())->asFragmentProcessor(
1020                     /*srcFP=*/nullptr,
1021                     GrFragmentProcessor::DestColor(),
1022                     childArgs);
1023             if (!childFP) {
1024                 return GrFPFailure(std::move(inputFP));
1025             }
1026             childFPs.push_back(std::move(childFP));
1027         } else {
1028             // We have a null child effect.
1029             childFPs.push_back(nullptr);
1030         }
1031     }
1032     auto fp = GrSkSLFP::MakeWithData(std::move(effect),
1033                                      name,
1034                                      childArgs.fDstColorInfo->refColorSpace(),
1035                                      std::move(inputFP),
1036                                      std::move(destColorFP),
1037                                      std::move(uniforms),
1038                                      SkSpan(childFPs));
1039     SkASSERT(fp);
1040     return GrFPSuccess(std::move(fp));
1041 }
1042 #endif
1043 
1044 #if defined(SK_GRAPHITE)
add_children_to_key(SkSpan<const SkRuntimeEffect::ChildPtr> children,SkSpan<const SkRuntimeEffect::Child> childInfo,const skgpu::graphite::KeyContext & keyContext,skgpu::graphite::PaintParamsKeyBuilder * builder,skgpu::graphite::PipelineDataGatherer * gatherer)1045 static void add_children_to_key(SkSpan<const SkRuntimeEffect::ChildPtr> children,
1046                                 SkSpan<const SkRuntimeEffect::Child> childInfo,
1047                                 const skgpu::graphite::KeyContext& keyContext,
1048                                 skgpu::graphite::PaintParamsKeyBuilder* builder,
1049                                 skgpu::graphite::PipelineDataGatherer* gatherer) {
1050     using namespace skgpu::graphite;
1051 
1052     SkASSERT(children.size() == childInfo.size());
1053 
1054     for (size_t index = 0; index < children.size(); ++index) {
1055         const SkRuntimeEffect::ChildPtr& child = children[index];
1056         std::optional<ChildType> type = child.type();
1057         if (type == ChildType::kShader) {
1058             as_SB(child.shader())->addToKey(keyContext, builder, gatherer);
1059         } else if (type == ChildType::kColorFilter) {
1060             as_CFB(child.colorFilter())->addToKey(keyContext, builder, gatherer);
1061         } else if (type == ChildType::kBlender) {
1062             as_BB(child.blender())->addToKey(keyContext, builder, gatherer,
1063                                              /*primitiveColorBlender=*/false);
1064         } else {
1065             // We don't have a child effect. Substitute in a no-op effect.
1066             switch (childInfo[index].type) {
1067                 case ChildType::kShader:
1068                 case ChildType::kColorFilter:
1069                     // A "passthrough" shader returns the input color as-is.
1070                     PassthroughShaderBlock::BeginBlock(keyContext, builder, gatherer);
1071                     builder->endBlock();
1072                     break;
1073 
1074                 case ChildType::kBlender:
1075                     // A "passthrough" blender performs `blend_src_over(src, dest)`.
1076                     PassthroughBlenderBlock::BeginBlock(keyContext, builder, gatherer);
1077                     builder->endBlock();
1078                     break;
1079             }
1080         }
1081     }
1082 }
1083 #endif
1084 
1085 class RuntimeEffectVMCallbacks : public SkSL::SkVMCallbacks {
1086 public:
RuntimeEffectVMCallbacks(skvm::Builder * builder,skvm::Uniforms * uniforms,SkArenaAlloc * alloc,const std::vector<SkRuntimeEffect::ChildPtr> & children,const SkShaderBase::MatrixRec & mRec,skvm::Color inColor,const SkColorInfo & colorInfo)1087     RuntimeEffectVMCallbacks(skvm::Builder* builder,
1088                              skvm::Uniforms* uniforms,
1089                              SkArenaAlloc* alloc,
1090                              const std::vector<SkRuntimeEffect::ChildPtr>& children,
1091                              const SkShaderBase::MatrixRec& mRec,
1092                              skvm::Color inColor,
1093                              const SkColorInfo& colorInfo)
1094             : fBuilder(builder)
1095             , fUniforms(uniforms)
1096             , fAlloc(alloc)
1097             , fChildren(children)
1098             , fMRec(mRec)
1099             , fInColor(inColor)
1100             , fColorInfo(colorInfo) {}
1101 
sampleShader(int ix,skvm::Coord coord)1102     skvm::Color sampleShader(int ix, skvm::Coord coord) override {
1103         // We haven't tracked device coords and the runtime effect could have arbitrarily
1104         // manipulated the passed coords. We should be in a state where any pending matrix was
1105         // already applied before the runtime effect's code could have manipulated the coords
1106         // and the total matrix from child shader to device space is flagged as unknown.
1107         SkASSERT(!fMRec.hasPendingMatrix());
1108         SkASSERT(!fMRec.totalMatrixIsValid());
1109         if (SkShader* shader = fChildren[ix].shader()) {
1110             return as_SB(shader)->program(fBuilder,
1111                                           coord,
1112                                           coord,
1113                                           fInColor,
1114                                           fMRec,
1115                                           fColorInfo,
1116                                           fUniforms,
1117                                           fAlloc);
1118         }
1119         return fInColor;
1120     }
1121 
sampleColorFilter(int ix,skvm::Color color)1122     skvm::Color sampleColorFilter(int ix, skvm::Color color) override {
1123         if (SkColorFilter* colorFilter = fChildren[ix].colorFilter()) {
1124             return as_CFB(colorFilter)->program(fBuilder, color, fColorInfo, fUniforms, fAlloc);
1125         }
1126         return color;
1127     }
1128 
sampleBlender(int ix,skvm::Color src,skvm::Color dst)1129     skvm::Color sampleBlender(int ix, skvm::Color src, skvm::Color dst) override {
1130         if (SkBlender* blender = fChildren[ix].blender()) {
1131             return as_BB(blender)->program(fBuilder, src, dst, fColorInfo, fUniforms, fAlloc);
1132         }
1133         return blend(SkBlendMode::kSrcOver, src, dst);
1134     }
1135 
toLinearSrgb(skvm::Color color)1136     skvm::Color toLinearSrgb(skvm::Color color) override {
1137         if (!fColorInfo.colorSpace()) {
1138             // These intrinsics do nothing when color management is disabled
1139             return color;
1140         }
1141         return SkColorSpaceXformSteps{fColorInfo.colorSpace(),    kUnpremul_SkAlphaType,
1142                                       sk_srgb_linear_singleton(), kUnpremul_SkAlphaType}
1143                 .program(fBuilder, fUniforms, color);
1144     }
1145 
fromLinearSrgb(skvm::Color color)1146     skvm::Color fromLinearSrgb(skvm::Color color) override {
1147         if (!fColorInfo.colorSpace()) {
1148             // These intrinsics do nothing when color management is disabled
1149             return color;
1150         }
1151         return SkColorSpaceXformSteps{sk_srgb_linear_singleton(), kUnpremul_SkAlphaType,
1152                                       fColorInfo.colorSpace(),    kUnpremul_SkAlphaType}
1153                 .program(fBuilder, fUniforms, color);
1154     }
1155 
1156     skvm::Builder* fBuilder;
1157     skvm::Uniforms* fUniforms;
1158     SkArenaAlloc* fAlloc;
1159     const std::vector<SkRuntimeEffect::ChildPtr>& fChildren;
1160     const SkShaderBase::MatrixRec& fMRec;
1161     const skvm::Color fInColor;
1162     const SkColorInfo& fColorInfo;
1163 };
1164 
1165 class SkRuntimeColorFilter : public SkColorFilterBase {
1166 public:
SkRuntimeColorFilter(sk_sp<SkRuntimeEffect> effect,sk_sp<const SkData> uniforms,SkSpan<SkRuntimeEffect::ChildPtr> children)1167     SkRuntimeColorFilter(sk_sp<SkRuntimeEffect> effect,
1168                          sk_sp<const SkData> uniforms,
1169                          SkSpan<SkRuntimeEffect::ChildPtr> children)
1170             : fEffect(std::move(effect))
1171             , fUniforms(std::move(uniforms))
1172             , fChildren(children.begin(), children.end()) {}
1173 
1174 #if defined(SK_GANESH)
asFragmentProcessor(std::unique_ptr<GrFragmentProcessor> inputFP,GrRecordingContext * context,const GrColorInfo & colorInfo,const SkSurfaceProps & props) const1175     GrFPResult asFragmentProcessor(std::unique_ptr<GrFragmentProcessor> inputFP,
1176                                    GrRecordingContext* context,
1177                                    const GrColorInfo& colorInfo,
1178                                    const SkSurfaceProps& props) const override {
1179         sk_sp<const SkData> uniforms = SkRuntimeEffectPriv::TransformUniforms(
1180                 fEffect->uniforms(),
1181                 fUniforms,
1182                 colorInfo.colorSpace());
1183         SkASSERT(uniforms);
1184 
1185         GrFPArgs childArgs(context, &colorInfo, props);
1186         return make_effect_fp(fEffect,
1187                               "runtime_color_filter",
1188                               std::move(uniforms),
1189                               std::move(inputFP),
1190                               /*destColorFP=*/nullptr,
1191                               SkSpan(fChildren),
1192                               childArgs);
1193     }
1194 #endif
1195 
1196 #if defined(SK_GRAPHITE)
addToKey(const skgpu::graphite::KeyContext & keyContext,skgpu::graphite::PaintParamsKeyBuilder * builder,skgpu::graphite::PipelineDataGatherer * gatherer) const1197     void addToKey(const skgpu::graphite::KeyContext& keyContext,
1198                   skgpu::graphite::PaintParamsKeyBuilder* builder,
1199                   skgpu::graphite::PipelineDataGatherer* gatherer) const override {
1200         using namespace skgpu::graphite;
1201 
1202         sk_sp<const SkData> uniforms = SkRuntimeEffectPriv::TransformUniforms(
1203                 fEffect->uniforms(),
1204                 fUniforms,
1205                 keyContext.dstColorInfo().colorSpace());
1206         SkASSERT(uniforms);
1207 
1208         RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
1209                                        { fEffect, std::move(uniforms) });
1210 
1211         add_children_to_key(fChildren, fEffect->children(), keyContext, builder, gatherer);
1212 
1213         builder->endBlock();
1214     }
1215 #endif
1216 
appendStages(const SkStageRec & rec,bool) const1217     bool appendStages(const SkStageRec& rec, bool) const override {
1218 #ifdef SK_ENABLE_SKSL_IN_RASTER_PIPELINE
1219         if (!SkRuntimeEffectPriv::CanDraw(SkCapabilities::RasterBackend().get(), fEffect.get())) {
1220             // SkRP has support for many parts of #version 300 already, but for now, we restrict its
1221             // usage in runtime effects to just #version 100.
1222             return false;
1223         }
1224         if (const SkSL::RP::Program* program = fEffect->getRPProgram()) {
1225             sk_sp<const SkData> inputs = SkRuntimeEffectPriv::TransformUniforms(fEffect->uniforms(),
1226                                                                                 fUniforms,
1227                                                                                 rec.fDstCS);
1228             SkShaderBase::MatrixRec matrix(SkMatrix::I());
1229             matrix.markCTMApplied();
1230             RuntimeEffectRPCallbacks callbacks(rec, matrix, fChildren, fEffect->fSampleUsages);
1231             bool success = program->appendStages(rec.fPipeline, rec.fAlloc, &callbacks,
1232                                                  uniforms_as_span(inputs.get()));
1233             return success;
1234         }
1235 #endif
1236         return false;
1237     }
1238 
onProgram(skvm::Builder * p,skvm::Color c,const SkColorInfo & colorInfo,skvm::Uniforms * uniforms,SkArenaAlloc * alloc) const1239     skvm::Color onProgram(skvm::Builder* p, skvm::Color c,
1240                           const SkColorInfo& colorInfo,
1241                           skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const override {
1242         SkASSERT(SkRuntimeEffectPriv::CanDraw(SkCapabilities::RasterBackend().get(),
1243                                               fEffect.get()));
1244 
1245         sk_sp<const SkData> inputs = SkRuntimeEffectPriv::TransformUniforms(
1246                 fEffect->uniforms(),
1247                 fUniforms,
1248                 colorInfo.colorSpace());
1249         SkASSERT(inputs);
1250 
1251         SkShaderBase::MatrixRec mRec(SkMatrix::I());
1252         mRec.markTotalMatrixInvalid();
1253         RuntimeEffectVMCallbacks callbacks(p, uniforms, alloc, fChildren, mRec, c, colorInfo);
1254         std::vector<skvm::Val> uniform = make_skvm_uniforms(p, uniforms, fEffect->uniformSize(),
1255                                                             *inputs);
1256 
1257         // There should be no way for the color filter to use device coords, but we need to supply
1258         // something. (Uninitialized values can trigger asserts in skvm::Builder).
1259         skvm::Coord zeroCoord = { p->splat(0.0f), p->splat(0.0f) };
1260         return SkSL::ProgramToSkVM(*fEffect->fBaseProgram, fEffect->fMain, p,/*debugTrace=*/nullptr,
1261                                    SkSpan(uniform), /*device=*/zeroCoord, /*local=*/zeroCoord,
1262                                    c, c, &callbacks);
1263     }
1264 
onFilterColor4f(const SkPMColor4f & color,SkColorSpace * dstCS) const1265     SkPMColor4f onFilterColor4f(const SkPMColor4f& color, SkColorSpace* dstCS) const override {
1266         // Get the generic program for filtering a single color
1267         const SkFilterColorProgram* program = fEffect->getFilterColorProgram();
1268         if (!program) {
1269             // We were unable to build a cached (per-effect) program. Use the base-class fallback,
1270             // which builds a program for the specific filter instance.
1271             return SkColorFilterBase::onFilterColor4f(color, dstCS);
1272         }
1273 
1274         // Get our specific uniform values
1275         sk_sp<const SkData> inputs = SkRuntimeEffectPriv::TransformUniforms(
1276                 fEffect->uniforms(),
1277                 fUniforms,
1278                 dstCS);
1279         SkASSERT(inputs);
1280 
1281         auto evalChild = [&](int index, SkPMColor4f inColor) {
1282             const auto& child = fChildren[index];
1283 
1284             // SkFilterColorProgram::Make has guaranteed that any children will be color filters.
1285             SkASSERT(!child.shader());
1286             SkASSERT(!child.blender());
1287             if (SkColorFilter* colorFilter = child.colorFilter()) {
1288                 return as_CFB(colorFilter)->onFilterColor4f(inColor, dstCS);
1289             }
1290             return inColor;
1291         };
1292 
1293         return program->eval(color, inputs->data(), evalChild);
1294     }
1295 
onIsAlphaUnchanged() const1296     bool onIsAlphaUnchanged() const override {
1297         return fEffect->getFilterColorProgram() &&
1298                fEffect->getFilterColorProgram()->isAlphaUnchanged();
1299     }
1300 
flatten(SkWriteBuffer & buffer) const1301     void flatten(SkWriteBuffer& buffer) const override {
1302         buffer.writeString(fEffect->source().c_str());
1303         buffer.writeDataAsByteArray(fUniforms.get());
1304         write_child_effects(buffer, fChildren);
1305     }
1306 
asRuntimeEffect() const1307     SkRuntimeEffect* asRuntimeEffect() const override { return fEffect.get(); }
1308 
1309     SK_FLATTENABLE_HOOKS(SkRuntimeColorFilter)
1310 
1311 private:
1312     sk_sp<SkRuntimeEffect> fEffect;
1313     sk_sp<const SkData> fUniforms;
1314     std::vector<SkRuntimeEffect::ChildPtr> fChildren;
1315 };
1316 
CreateProc(SkReadBuffer & buffer)1317 sk_sp<SkFlattenable> SkRuntimeColorFilter::CreateProc(SkReadBuffer& buffer) {
1318     SkString sksl;
1319     buffer.readString(&sksl);
1320     sk_sp<SkData> uniforms = buffer.readByteArrayAsData();
1321 
1322     auto effect = SkMakeCachedRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, std::move(sksl));
1323 #if !SK_LENIENT_SKSL_DESERIALIZATION
1324     if (!buffer.validate(effect != nullptr)) {
1325         return nullptr;
1326     }
1327 #endif
1328 
1329     SkSTArray<4, SkRuntimeEffect::ChildPtr> children;
1330     if (!read_child_effects(buffer, effect.get(), &children)) {
1331         return nullptr;
1332     }
1333 
1334 #if SK_LENIENT_SKSL_DESERIALIZATION
1335     if (!effect) {
1336         SkDebugf("Serialized SkSL failed to compile. Ignoring/dropping SkSL color filter.\n");
1337         return nullptr;
1338     }
1339 #endif
1340 
1341     return effect->makeColorFilter(std::move(uniforms), SkSpan(children));
1342 }
1343 
1344 ///////////////////////////////////////////////////////////////////////////////////////////////////
1345 
1346 using UniformsCallback = SkRuntimeEffectPriv::UniformsCallback;
1347 
1348 class SkRTShader : public SkShaderBase {
1349 public:
SkRTShader(sk_sp<SkRuntimeEffect> effect,sk_sp<SkSL::SkVMDebugTrace> debugTrace,sk_sp<const SkData> uniforms,SkSpan<SkRuntimeEffect::ChildPtr> children)1350     SkRTShader(sk_sp<SkRuntimeEffect> effect,
1351                sk_sp<SkSL::SkVMDebugTrace> debugTrace,
1352                sk_sp<const SkData> uniforms,
1353                SkSpan<SkRuntimeEffect::ChildPtr> children)
1354             : fEffect(std::move(effect))
1355             , fDebugTrace(std::move(debugTrace))
1356             , fUniformData(std::move(uniforms))
1357             , fChildren(children.begin(), children.end()) {}
1358 
SkRTShader(sk_sp<SkRuntimeEffect> effect,sk_sp<SkSL::SkVMDebugTrace> debugTrace,UniformsCallback uniformsCallback,SkSpan<SkRuntimeEffect::ChildPtr> children)1359     SkRTShader(sk_sp<SkRuntimeEffect> effect,
1360                sk_sp<SkSL::SkVMDebugTrace> debugTrace,
1361                UniformsCallback uniformsCallback,
1362                SkSpan<SkRuntimeEffect::ChildPtr> children)
1363             : fEffect(std::move(effect))
1364             , fDebugTrace(std::move(debugTrace))
1365             , fUniformsCallback(std::move(uniformsCallback))
1366             , fChildren(children.begin(), children.end()) {}
1367 
makeTracedClone(const SkIPoint & coord)1368     SkRuntimeEffect::TracedShader makeTracedClone(const SkIPoint& coord) {
1369         sk_sp<SkRuntimeEffect> unoptimized = fEffect->makeUnoptimizedClone();
1370         sk_sp<SkSL::SkVMDebugTrace> debugTrace = make_skvm_debug_trace(unoptimized.get(), coord);
1371         auto debugShader = sk_make_sp<SkRTShader>(
1372                 unoptimized, debugTrace, this->uniformData(nullptr), SkSpan(fChildren));
1373 
1374         return SkRuntimeEffect::TracedShader{std::move(debugShader), std::move(debugTrace)};
1375     }
1376 
isOpaque() const1377     bool isOpaque() const override { return fEffect->alwaysOpaque(); }
1378 
1379 #if defined(SK_GANESH)
asFragmentProcessor(const GrFPArgs & args,const MatrixRec & mRec) const1380     std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs& args,
1381                                                              const MatrixRec& mRec) const override {
1382         if (!SkRuntimeEffectPriv::CanDraw(args.fContext->priv().caps(), fEffect.get())) {
1383             return nullptr;
1384         }
1385 
1386         sk_sp<const SkData> uniforms = SkRuntimeEffectPriv::TransformUniforms(
1387                 fEffect->uniforms(),
1388                 this->uniformData(args.fDstColorInfo->colorSpace()),
1389                 args.fDstColorInfo->colorSpace());
1390         SkASSERT(uniforms);
1391 
1392         bool success;
1393         std::unique_ptr<GrFragmentProcessor> fp;
1394         std::tie(success, fp) = make_effect_fp(fEffect,
1395                                                "runtime_shader",
1396                                                std::move(uniforms),
1397                                                /*inputFP=*/nullptr,
1398                                                /*destColorFP=*/nullptr,
1399                                                SkSpan(fChildren),
1400                                                args);
1401         if (!success) {
1402             return nullptr;
1403         }
1404 
1405         std::tie(success, fp) = mRec.apply(std::move(fp));
1406         if (!success) {
1407             return nullptr;
1408         }
1409         return fp;
1410     }
1411 #endif
1412 
1413 #if defined(SK_GRAPHITE)
addToKey(const skgpu::graphite::KeyContext & keyContext,skgpu::graphite::PaintParamsKeyBuilder * builder,skgpu::graphite::PipelineDataGatherer * gatherer) const1414     void addToKey(const skgpu::graphite::KeyContext& keyContext,
1415                   skgpu::graphite::PaintParamsKeyBuilder* builder,
1416                   skgpu::graphite::PipelineDataGatherer* gatherer) const override {
1417         using namespace skgpu::graphite;
1418 
1419         sk_sp<const SkData> uniforms = SkRuntimeEffectPriv::TransformUniforms(
1420                 fEffect->uniforms(),
1421                 this->uniformData(keyContext.dstColorInfo().colorSpace()),
1422                 keyContext.dstColorInfo().colorSpace());
1423         SkASSERT(uniforms);
1424 
1425         RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
1426                                        { fEffect, std::move(uniforms) });
1427 
1428         add_children_to_key(fChildren, fEffect->children(), keyContext, builder, gatherer);
1429 
1430         builder->endBlock();
1431     }
1432 #endif
1433 
appendStages(const SkStageRec & rec,const MatrixRec & mRec) const1434     bool appendStages(const SkStageRec& rec, const MatrixRec& mRec) const override {
1435 #ifdef SK_ENABLE_SKSL_IN_RASTER_PIPELINE
1436         if (!SkRuntimeEffectPriv::CanDraw(SkCapabilities::RasterBackend().get(), fEffect.get())) {
1437             // SkRP has support for many parts of #version 300 already, but for now, we restrict its
1438             // usage in runtime effects to just #version 100.
1439             return false;
1440         }
1441         if (fDebugTrace) {
1442             // SkRP doesn't support debug traces yet; fall back to SkVM until this is implemented.
1443             return false;
1444         }
1445         if (const SkSL::RP::Program* program = fEffect->getRPProgram()) {
1446             std::optional<MatrixRec> newMRec = mRec.apply(rec);
1447             if (!newMRec.has_value()) {
1448                 return false;
1449             }
1450 
1451             sk_sp<const SkData> inputs = SkRuntimeEffectPriv::TransformUniforms(fEffect->uniforms(),
1452                                                                                 this->uniformData(rec.fDstCS),
1453                                                                                 rec.fDstCS);
1454 
1455             RuntimeEffectRPCallbacks callbacks(rec, *newMRec, fChildren, fEffect->fSampleUsages);
1456             bool success = program->appendStages(rec.fPipeline, rec.fAlloc, &callbacks,
1457                                                  uniforms_as_span(inputs.get()));
1458             return success;
1459         }
1460 #endif
1461         return false;
1462     }
1463 
program(skvm::Builder * p,skvm::Coord device,skvm::Coord local,skvm::Color paint,const MatrixRec & mRec,const SkColorInfo & colorInfo,skvm::Uniforms * uniforms,SkArenaAlloc * alloc) const1464     skvm::Color program(skvm::Builder* p,
1465                         skvm::Coord device,
1466                         skvm::Coord local,
1467                         skvm::Color paint,
1468                         const MatrixRec& mRec,
1469                         const SkColorInfo& colorInfo,
1470                         skvm::Uniforms* uniforms,
1471                         SkArenaAlloc* alloc) const override {
1472         if (!SkRuntimeEffectPriv::CanDraw(SkCapabilities::RasterBackend().get(), fEffect.get())) {
1473             return {};
1474         }
1475 
1476         sk_sp<const SkData> inputs =
1477                 SkRuntimeEffectPriv::TransformUniforms(fEffect->uniforms(),
1478                                                        this->uniformData(colorInfo.colorSpace()),
1479                                                        colorInfo.colorSpace());
1480         SkASSERT(inputs);
1481 
1482         // Ensure any pending transform is applied before running the runtime shader's code, which
1483         // gets to use and manipulate the coordinates.
1484         std::optional<MatrixRec> newMRec = mRec.apply(p, &local, uniforms);
1485         if (!newMRec.has_value()) {
1486             return {};
1487         }
1488         // We could omit this for children that are only sampled with passthrough coords.
1489         newMRec->markTotalMatrixInvalid();
1490 
1491         RuntimeEffectVMCallbacks callbacks(p,
1492                                            uniforms,
1493                                            alloc,
1494                                            fChildren,
1495                                            *newMRec,
1496                                            paint,
1497                                            colorInfo);
1498         std::vector<skvm::Val> uniform = make_skvm_uniforms(p, uniforms, fEffect->uniformSize(),
1499                                                             *inputs);
1500 
1501         return SkSL::ProgramToSkVM(*fEffect->fBaseProgram, fEffect->fMain, p, fDebugTrace.get(),
1502                                    SkSpan(uniform), device, local, paint, paint, &callbacks);
1503     }
1504 
flatten(SkWriteBuffer & buffer) const1505     void flatten(SkWriteBuffer& buffer) const override {
1506         buffer.writeString(fEffect->source().c_str());
1507         buffer.writeDataAsByteArray(this->uniformData(nullptr).get());
1508         write_child_effects(buffer, fChildren);
1509     }
1510 
asRuntimeEffect() const1511     SkRuntimeEffect* asRuntimeEffect() const override { return fEffect.get(); }
1512 
1513     SK_FLATTENABLE_HOOKS(SkRTShader)
1514 
1515 private:
1516     enum Flags {
1517         kHasLegacyLocalMatrix_Flag = 1 << 1,
1518     };
1519 
uniformData(const SkColorSpace * dstCS) const1520     sk_sp<const SkData> uniformData(const SkColorSpace* dstCS) const {
1521         if (fUniformData) {
1522             return fUniformData;
1523         }
1524 
1525         SkASSERT(fUniformsCallback);
1526         sk_sp<const SkData> uniforms = fUniformsCallback({dstCS});
1527         SkASSERT(uniforms && uniforms->size() == fEffect->uniformSize());
1528         return uniforms;
1529     }
1530 
1531     sk_sp<SkRuntimeEffect> fEffect;
1532     sk_sp<SkSL::SkVMDebugTrace> fDebugTrace;
1533     sk_sp<const SkData> fUniformData;
1534     UniformsCallback fUniformsCallback;
1535     std::vector<SkRuntimeEffect::ChildPtr> fChildren;
1536 };
1537 
CreateProc(SkReadBuffer & buffer)1538 sk_sp<SkFlattenable> SkRTShader::CreateProc(SkReadBuffer& buffer) {
1539     SkString sksl;
1540     buffer.readString(&sksl);
1541     sk_sp<SkData> uniforms = buffer.readByteArrayAsData();
1542 
1543     SkTLazy<SkMatrix> localM;
1544     if (buffer.isVersionLT(SkPicturePriv::kNoShaderLocalMatrix)) {
1545         uint32_t flags = buffer.read32();
1546         if (flags & kHasLegacyLocalMatrix_Flag) {
1547             buffer.readMatrix(localM.init());
1548         }
1549     }
1550 
1551     auto effect = SkMakeCachedRuntimeEffect(SkRuntimeEffect::MakeForShader, std::move(sksl));
1552 #if !SK_LENIENT_SKSL_DESERIALIZATION
1553     if (!buffer.validate(effect != nullptr)) {
1554         return nullptr;
1555     }
1556 #endif
1557 
1558     SkSTArray<4, SkRuntimeEffect::ChildPtr> children;
1559     if (!read_child_effects(buffer, effect.get(), &children)) {
1560         return nullptr;
1561     }
1562 
1563 #if SK_LENIENT_SKSL_DESERIALIZATION
1564     if (!effect) {
1565         // If any children were SkShaders, return the first one. This is a reasonable fallback.
1566         for (int i = 0; i < children.size(); i++) {
1567             if (children[i].shader()) {
1568                 SkDebugf("Serialized SkSL failed to compile. Replacing shader with child %d.\n", i);
1569                 return sk_ref_sp(children[i].shader());
1570             }
1571         }
1572 
1573         // We don't know what to do, so just return nullptr (but *don't* poison the buffer).
1574         SkDebugf("Serialized SkSL failed to compile. Ignoring/dropping SkSL shader.\n");
1575         return nullptr;
1576     }
1577 #endif
1578 
1579     return effect->makeShader(std::move(uniforms), SkSpan(children), localM.getMaybeNull());
1580 }
1581 
1582 ///////////////////////////////////////////////////////////////////////////////////////////////////
1583 
1584 class SkRuntimeBlender : public SkBlenderBase {
1585 public:
SkRuntimeBlender(sk_sp<SkRuntimeEffect> effect,sk_sp<const SkData> uniforms,SkSpan<SkRuntimeEffect::ChildPtr> children)1586     SkRuntimeBlender(sk_sp<SkRuntimeEffect> effect,
1587                      sk_sp<const SkData> uniforms,
1588                      SkSpan<SkRuntimeEffect::ChildPtr> children)
1589             : fEffect(std::move(effect))
1590             , fUniforms(std::move(uniforms))
1591             , fChildren(children.begin(), children.end()) {}
1592 
asRuntimeEffect() const1593     SkRuntimeEffect* asRuntimeEffect() const override { return fEffect.get(); }
1594 
onProgram(skvm::Builder * p,skvm::Color src,skvm::Color dst,const SkColorInfo & colorInfo,skvm::Uniforms * uniforms,SkArenaAlloc * alloc) const1595     skvm::Color onProgram(skvm::Builder* p, skvm::Color src, skvm::Color dst,
1596                           const SkColorInfo& colorInfo, skvm::Uniforms* uniforms,
1597                           SkArenaAlloc* alloc) const override {
1598         if (!SkRuntimeEffectPriv::CanDraw(SkCapabilities::RasterBackend().get(), fEffect.get())) {
1599             return {};
1600         }
1601 
1602         sk_sp<const SkData> inputs = SkRuntimeEffectPriv::TransformUniforms(fEffect->uniforms(),
1603                                                                             fUniforms,
1604                                                                             colorInfo.colorSpace());
1605         SkASSERT(inputs);
1606 
1607         SkShaderBase::MatrixRec mRec(SkMatrix::I());
1608         mRec.markTotalMatrixInvalid();
1609         RuntimeEffectVMCallbacks callbacks(p, uniforms, alloc, fChildren, mRec, src, colorInfo);
1610         std::vector<skvm::Val> uniform = make_skvm_uniforms(p, uniforms, fEffect->uniformSize(),
1611                                                             *inputs);
1612 
1613         // Emit the blend function as an SkVM program.
1614         skvm::Coord zeroCoord = {p->splat(0.0f), p->splat(0.0f)};
1615         return SkSL::ProgramToSkVM(*fEffect->fBaseProgram, fEffect->fMain, p,/*debugTrace=*/nullptr,
1616                                    SkSpan(uniform), /*device=*/zeroCoord, /*local=*/zeroCoord,
1617                                    src, dst, &callbacks);
1618     }
1619 
1620 #if defined(SK_GANESH)
asFragmentProcessor(std::unique_ptr<GrFragmentProcessor> srcFP,std::unique_ptr<GrFragmentProcessor> dstFP,const GrFPArgs & args) const1621     std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(
1622             std::unique_ptr<GrFragmentProcessor> srcFP,
1623             std::unique_ptr<GrFragmentProcessor> dstFP,
1624             const GrFPArgs& args) const override {
1625         if (!SkRuntimeEffectPriv::CanDraw(args.fContext->priv().caps(), fEffect.get())) {
1626             return nullptr;
1627         }
1628 
1629         sk_sp<const SkData> uniforms = SkRuntimeEffectPriv::TransformUniforms(
1630                 fEffect->uniforms(),
1631                 fUniforms,
1632                 args.fDstColorInfo->colorSpace());
1633         SkASSERT(uniforms);
1634         auto [success, fp] = make_effect_fp(fEffect,
1635                                             "runtime_blender",
1636                                             std::move(uniforms),
1637                                             std::move(srcFP),
1638                                             std::move(dstFP),
1639                                             SkSpan(fChildren),
1640                                             args);
1641 
1642         return success ? std::move(fp) : nullptr;
1643     }
1644 #endif
1645 
1646 #if defined(SK_GRAPHITE)
addToKey(const skgpu::graphite::KeyContext & keyContext,skgpu::graphite::PaintParamsKeyBuilder * builder,skgpu::graphite::PipelineDataGatherer * gatherer,bool primitiveColorBlender) const1647     void addToKey(const skgpu::graphite::KeyContext& keyContext,
1648                   skgpu::graphite::PaintParamsKeyBuilder* builder,
1649                   skgpu::graphite::PipelineDataGatherer* gatherer,
1650                   bool primitiveColorBlender) const override {
1651         using namespace skgpu::graphite;
1652 
1653         sk_sp<const SkData> uniforms = SkRuntimeEffectPriv::TransformUniforms(
1654                 fEffect->uniforms(),
1655                 fUniforms,
1656                 keyContext.dstColorInfo().colorSpace());
1657         SkASSERT(uniforms);
1658 
1659         RuntimeEffectBlock::BeginBlock(keyContext, builder, gatherer,
1660                                        { fEffect, std::move(uniforms) });
1661 
1662         add_children_to_key(fChildren, fEffect->children(), keyContext, builder, gatherer);
1663 
1664         builder->endBlock();
1665     }
1666 #endif
1667 
flatten(SkWriteBuffer & buffer) const1668     void flatten(SkWriteBuffer& buffer) const override {
1669         buffer.writeString(fEffect->source().c_str());
1670         buffer.writeDataAsByteArray(fUniforms.get());
1671         write_child_effects(buffer, fChildren);
1672     }
1673 
1674     SK_FLATTENABLE_HOOKS(SkRuntimeBlender)
1675 
1676 private:
1677     using INHERITED = SkBlenderBase;
1678 
1679     sk_sp<SkRuntimeEffect> fEffect;
1680     sk_sp<const SkData> fUniforms;
1681     std::vector<SkRuntimeEffect::ChildPtr> fChildren;
1682 };
1683 
CreateProc(SkReadBuffer & buffer)1684 sk_sp<SkFlattenable> SkRuntimeBlender::CreateProc(SkReadBuffer& buffer) {
1685     SkString sksl;
1686     buffer.readString(&sksl);
1687     sk_sp<SkData> uniforms = buffer.readByteArrayAsData();
1688 
1689     auto effect = SkMakeCachedRuntimeEffect(SkRuntimeEffect::MakeForBlender, std::move(sksl));
1690 #if !SK_LENIENT_SKSL_DESERIALIZATION
1691     if (!buffer.validate(effect != nullptr)) {
1692         return nullptr;
1693     }
1694 #endif
1695 
1696     SkSTArray<4, SkRuntimeEffect::ChildPtr> children;
1697     if (!read_child_effects(buffer, effect.get(), &children)) {
1698         return nullptr;
1699     }
1700 
1701 #if SK_LENIENT_SKSL_DESERIALIZATION
1702     if (!effect) {
1703         SkDebugf("Serialized SkSL failed to compile. Ignoring/dropping SkSL blender.\n");
1704         return nullptr;
1705     }
1706 #endif
1707 
1708     return effect->makeBlender(std::move(uniforms), SkSpan(children));
1709 }
1710 
1711 ///////////////////////////////////////////////////////////////////////////////////////////////////
1712 
MakeDeferredShader(const SkRuntimeEffect * effect,UniformsCallback uniformsCallback,SkSpan<SkRuntimeEffect::ChildPtr> children,const SkMatrix * localMatrix)1713 sk_sp<SkShader> SkRuntimeEffectPriv::MakeDeferredShader(const SkRuntimeEffect* effect,
1714                                                         UniformsCallback uniformsCallback,
1715                                                         SkSpan<SkRuntimeEffect::ChildPtr> children,
1716                                                         const SkMatrix* localMatrix) {
1717     if (!effect->allowShader()) {
1718         return nullptr;
1719     }
1720     if (!verify_child_effects(effect->fChildren, children)) {
1721         return nullptr;
1722     }
1723     if (!uniformsCallback) {
1724         return nullptr;
1725     }
1726     return SkLocalMatrixShader::MakeWrapped<SkRTShader>(localMatrix,
1727                                                         sk_ref_sp(effect),
1728                                                         /*debugTrace=*/nullptr,
1729                                                         std::move(uniformsCallback),
1730                                                         children);
1731 }
1732 
makeShader(sk_sp<const SkData> uniforms,sk_sp<SkShader> childShaders[],size_t childCount,const SkMatrix * localMatrix) const1733 sk_sp<SkShader> SkRuntimeEffect::makeShader(sk_sp<const SkData> uniforms,
1734                                             sk_sp<SkShader> childShaders[],
1735                                             size_t childCount,
1736                                             const SkMatrix* localMatrix) const {
1737     SkSTArray<4, ChildPtr> children(childCount);
1738     for (size_t i = 0; i < childCount; ++i) {
1739         children.emplace_back(childShaders[i]);
1740     }
1741     return this->makeShader(std::move(uniforms), SkSpan(children), localMatrix);
1742 }
1743 
makeShader(sk_sp<const SkData> uniforms,SkSpan<ChildPtr> children,const SkMatrix * localMatrix) const1744 sk_sp<SkShader> SkRuntimeEffect::makeShader(sk_sp<const SkData> uniforms,
1745                                             SkSpan<ChildPtr> children,
1746                                             const SkMatrix* localMatrix) const {
1747     if (!this->allowShader()) {
1748         return nullptr;
1749     }
1750     if (!verify_child_effects(fChildren, children)) {
1751         return nullptr;
1752     }
1753     if (!uniforms) {
1754         uniforms = SkData::MakeEmpty();
1755     }
1756     if (uniforms->size() != this->uniformSize()) {
1757         return nullptr;
1758     }
1759     return SkLocalMatrixShader::MakeWrapped<SkRTShader>(localMatrix,
1760                                                         sk_ref_sp(this),
1761                                                         /*debugTrace=*/nullptr,
1762                                                         std::move(uniforms),
1763                                                         children);
1764 }
1765 
makeImage(GrRecordingContext * rContext,sk_sp<const SkData> uniforms,SkSpan<ChildPtr> children,const SkMatrix * localMatrix,SkImageInfo resultInfo,bool mipmapped) const1766 sk_sp<SkImage> SkRuntimeEffect::makeImage(GrRecordingContext* rContext,
1767                                           sk_sp<const SkData> uniforms,
1768                                           SkSpan<ChildPtr> children,
1769                                           const SkMatrix* localMatrix,
1770                                           SkImageInfo resultInfo,
1771                                           bool mipmapped) const {
1772     if (resultInfo.alphaType() == kUnpremul_SkAlphaType ||
1773         resultInfo.alphaType() == kUnknown_SkAlphaType) {
1774         return nullptr;
1775     }
1776     sk_sp<SkSurface> surface;
1777     if (rContext) {
1778 #if defined(SK_GANESH)
1779         if (!rContext->priv().caps()->mipmapSupport()) {
1780             mipmapped = false;
1781         }
1782         surface = SkSurface::MakeRenderTarget(rContext,
1783                                               skgpu::Budgeted::kYes,
1784                                               resultInfo,
1785                                               1,
1786                                               kTopLeft_GrSurfaceOrigin,
1787                                               nullptr,
1788                                               mipmapped);
1789 #endif
1790     } else {
1791         surface = SkSurface::MakeRaster(resultInfo);
1792     }
1793     if (!surface) {
1794         return nullptr;
1795     }
1796     SkCanvas* canvas = surface->getCanvas();
1797     auto shader = this->makeShader(std::move(uniforms), children, localMatrix);
1798     if (!shader) {
1799         return nullptr;
1800     }
1801     SkPaint paint;
1802     paint.setShader(std::move(shader));
1803     paint.setBlendMode(SkBlendMode::kSrc);
1804     canvas->drawPaint(paint);
1805     return surface->makeImageSnapshot();
1806 }
1807 
makeColorFilter(sk_sp<const SkData> uniforms,sk_sp<SkColorFilter> childColorFilters[],size_t childCount) const1808 sk_sp<SkColorFilter> SkRuntimeEffect::makeColorFilter(sk_sp<const SkData> uniforms,
1809                                                       sk_sp<SkColorFilter> childColorFilters[],
1810                                                       size_t childCount) const {
1811     SkSTArray<4, ChildPtr> children(childCount);
1812     for (size_t i = 0; i < childCount; ++i) {
1813         children.emplace_back(childColorFilters[i]);
1814     }
1815     return this->makeColorFilter(std::move(uniforms), SkSpan(children));
1816 }
1817 
makeColorFilter(sk_sp<const SkData> uniforms,SkSpan<ChildPtr> children) const1818 sk_sp<SkColorFilter> SkRuntimeEffect::makeColorFilter(sk_sp<const SkData> uniforms,
1819                                                       SkSpan<ChildPtr> children) const {
1820     if (!this->allowColorFilter()) {
1821         return nullptr;
1822     }
1823     if (!verify_child_effects(fChildren, children)) {
1824         return nullptr;
1825     }
1826     if (!uniforms) {
1827         uniforms = SkData::MakeEmpty();
1828     }
1829     if (uniforms->size() != this->uniformSize()) {
1830         return nullptr;
1831     }
1832     return sk_make_sp<SkRuntimeColorFilter>(sk_ref_sp(this), std::move(uniforms), children);
1833 }
1834 
makeColorFilter(sk_sp<const SkData> uniforms) const1835 sk_sp<SkColorFilter> SkRuntimeEffect::makeColorFilter(sk_sp<const SkData> uniforms) const {
1836     return this->makeColorFilter(std::move(uniforms), /*children=*/{});
1837 }
1838 
makeBlender(sk_sp<const SkData> uniforms,SkSpan<ChildPtr> children) const1839 sk_sp<SkBlender> SkRuntimeEffect::makeBlender(sk_sp<const SkData> uniforms,
1840                                               SkSpan<ChildPtr> children) const {
1841     if (!this->allowBlender()) {
1842         return nullptr;
1843     }
1844     if (!verify_child_effects(fChildren, children)) {
1845         return nullptr;
1846     }
1847     if (!uniforms) {
1848         uniforms = SkData::MakeEmpty();
1849     }
1850     if (uniforms->size() != this->uniformSize()) {
1851         return nullptr;
1852     }
1853     return sk_make_sp<SkRuntimeBlender>(sk_ref_sp(this), std::move(uniforms), children);
1854 }
1855 
1856 ///////////////////////////////////////////////////////////////////////////////////////////////////
1857 
MakeTraced(sk_sp<SkShader> shader,const SkIPoint & traceCoord)1858 SkRuntimeEffect::TracedShader SkRuntimeEffect::MakeTraced(sk_sp<SkShader> shader,
1859                                                           const SkIPoint& traceCoord) {
1860     SkRuntimeEffect* effect = as_SB(shader)->asRuntimeEffect();
1861     if (!effect) {
1862         return TracedShader{nullptr, nullptr};
1863     }
1864     // An SkShader with an attached SkRuntimeEffect must be an SkRTShader.
1865     SkRTShader* rtShader = static_cast<SkRTShader*>(shader.get());
1866     return rtShader->makeTracedClone(traceCoord);
1867 }
1868 
1869 ///////////////////////////////////////////////////////////////////////////////////////////////////
1870 
type() const1871 std::optional<ChildType> SkRuntimeEffect::ChildPtr::type() const {
1872     if (fChild) {
1873         switch (fChild->getFlattenableType()) {
1874             case SkFlattenable::kSkShader_Type:
1875                 return ChildType::kShader;
1876             case SkFlattenable::kSkColorFilter_Type:
1877                 return ChildType::kColorFilter;
1878             case SkFlattenable::kSkBlender_Type:
1879                 return ChildType::kBlender;
1880             default:
1881                 break;
1882         }
1883     }
1884     return std::nullopt;
1885 }
1886 
shader() const1887 SkShader* SkRuntimeEffect::ChildPtr::shader() const {
1888     return (fChild && fChild->getFlattenableType() == SkFlattenable::kSkShader_Type)
1889                    ? static_cast<SkShader*>(fChild.get())
1890                    : nullptr;
1891 }
1892 
colorFilter() const1893 SkColorFilter* SkRuntimeEffect::ChildPtr::colorFilter() const {
1894     return (fChild && fChild->getFlattenableType() == SkFlattenable::kSkColorFilter_Type)
1895                    ? static_cast<SkColorFilter*>(fChild.get())
1896                    : nullptr;
1897 }
1898 
blender() const1899 SkBlender* SkRuntimeEffect::ChildPtr::blender() const {
1900     return (fChild && fChild->getFlattenableType() == SkFlattenable::kSkBlender_Type)
1901                    ? static_cast<SkBlender*>(fChild.get())
1902                    : nullptr;
1903 }
1904 
1905 ///////////////////////////////////////////////////////////////////////////////////////////////////
1906 
RegisterFlattenables()1907 void SkRuntimeEffect::RegisterFlattenables() {
1908     SK_REGISTER_FLATTENABLE(SkRuntimeColorFilter);
1909     SK_REGISTER_FLATTENABLE(SkRTShader);
1910     SK_REGISTER_FLATTENABLE(SkRuntimeBlender);
1911 }
1912 
SkRuntimeShaderBuilder(sk_sp<SkRuntimeEffect> effect)1913 SkRuntimeShaderBuilder::SkRuntimeShaderBuilder(sk_sp<SkRuntimeEffect> effect)
1914         : INHERITED(std::move(effect)) {}
1915 
1916 SkRuntimeShaderBuilder::~SkRuntimeShaderBuilder() = default;
1917 
makeImage(GrRecordingContext * recordingContext,const SkMatrix * localMatrix,SkImageInfo resultInfo,bool mipmapped)1918 sk_sp<SkImage> SkRuntimeShaderBuilder::makeImage(GrRecordingContext* recordingContext,
1919                                                  const SkMatrix* localMatrix,
1920                                                  SkImageInfo resultInfo,
1921                                                  bool mipmapped) {
1922     return this->effect()->makeImage(recordingContext,
1923                                      this->uniforms(),
1924                                      this->children(),
1925                                      localMatrix,
1926                                      resultInfo,
1927                                      mipmapped);
1928 }
1929 
makeShader(const SkMatrix * localMatrix)1930 sk_sp<SkShader> SkRuntimeShaderBuilder::makeShader(const SkMatrix* localMatrix) {
1931     return this->effect()->makeShader(this->uniforms(), this->children(), localMatrix);
1932 }
1933 
SkRuntimeBlendBuilder(sk_sp<SkRuntimeEffect> effect)1934 SkRuntimeBlendBuilder::SkRuntimeBlendBuilder(sk_sp<SkRuntimeEffect> effect)
1935         : INHERITED(std::move(effect)) {}
1936 
1937 SkRuntimeBlendBuilder::~SkRuntimeBlendBuilder() = default;
1938 
makeBlender()1939 sk_sp<SkBlender> SkRuntimeBlendBuilder::makeBlender() {
1940     return this->effect()->makeBlender(this->uniforms(), this->children());
1941 }
1942 
SkRuntimeColorFilterBuilder(sk_sp<SkRuntimeEffect> effect)1943 SkRuntimeColorFilterBuilder::SkRuntimeColorFilterBuilder(sk_sp<SkRuntimeEffect> effect)
1944         : INHERITED(std::move(effect)) {}
1945 
1946 SkRuntimeColorFilterBuilder::~SkRuntimeColorFilterBuilder() = default;
1947 
makeColorFilter()1948 sk_sp<SkColorFilter> SkRuntimeColorFilterBuilder::makeColorFilter() {
1949     return this->effect()->makeColorFilter(this->uniforms(), this->children());
1950 }
1951 
1952 #endif  // SK_ENABLE_SKSL
1953