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/core/SkColorFilter.h"
9#include "include/core/SkData.h"
10#include "include/effects/SkRuntimeEffect.h"
11#include "include/private/SkChecksum.h"
12#include "include/private/SkMutex.h"
13#include "src/core/SkRasterPipeline.h"
14#include "src/core/SkReadBuffer.h"
15#include "src/core/SkUtils.h"
16#include "src/core/SkVM.h"
17#include "src/core/SkWriteBuffer.h"
18#include "src/sksl/SkSLByteCode.h"
19#include "src/sksl/SkSLCompiler.h"
20#include "src/sksl/ir/SkSLFunctionDefinition.h"
21#include "src/sksl/ir/SkSLVarDeclarations.h"
22
23#if SK_SUPPORT_GPU
24#include "include/private/GrRecordingContext.h"
25#include "src/gpu/GrColorInfo.h"
26#include "src/gpu/GrFPArgs.h"
27#include "src/gpu/effects/GrSkSLFP.h"
28#endif
29
30namespace SkSL {
31class SharedCompiler {
32public:
33 SharedCompiler() : fLock(compiler_mutex()) {
34 if (!gCompiler) {
35 gCompiler = new SkSL::Compiler{};
36 }
37 }
38
39 SkSL::Compiler* operator->() const { return gCompiler; }
40
41private:
42 SkAutoMutexExclusive fLock;
43
44 static SkMutex& compiler_mutex() {
45 static SkMutex& mutex = *(new SkMutex);
46 return mutex;
47 }
48
49 static SkSL::Compiler* gCompiler;
50};
51SkSL::Compiler* SharedCompiler::gCompiler = nullptr;
52}
53
54SkRuntimeEffect::EffectResult SkRuntimeEffect::Make(SkString sksl) {
55 SkSL::SharedCompiler compiler;
56 auto program = compiler->convertProgram(SkSL::Program::kPipelineStage_Kind,
57 SkSL::String(sksl.c_str(), sksl.size()),
58 SkSL::Program::Settings());
59 // TODO: Many errors aren't caught until we process the generated Program here. Catching those
60 // in the IR generator would provide better errors messages (with locations).
61 #define RETURN_FAILURE(...) return std::make_pair(nullptr, SkStringPrintf(__VA_ARGS__))
62
63 if (!program) {
64 RETURN_FAILURE("%s", compiler->errorText().c_str());
65 }
66 SkASSERT(!compiler->errorCount());
67
68 size_t offset = 0, uniformSize = 0;
69 std::vector<Variable> inAndUniformVars;
70 std::vector<SkString> children;
71 std::vector<Varying> varyings;
72 const SkSL::Context& ctx(compiler->context());
73
74 // Scrape the varyings
75 for (const auto& e : *program) {
76 if (e.fKind == SkSL::ProgramElement::kVar_Kind) {
77 SkSL::VarDeclarations& v = (SkSL::VarDeclarations&) e;
78 for (const auto& varStatement : v.fVars) {
79 const SkSL::Variable& var = *((SkSL::VarDeclaration&) *varStatement).fVar;
80
81 if (var.fModifiers.fFlags & SkSL::Modifiers::kVarying_Flag) {
82 varyings.push_back({var.fName, var.fType.kind() == SkSL::Type::kVector_Kind
83 ? var.fType.columns()
84 : 1});
85 }
86 }
87 }
88 }
89
90 // Gather the inputs in two passes, to de-interleave them in our input layout.
91 // We put the uniforms *first*, so that the CPU backend can alias the combined input block as
92 // the uniform block when calling the interpreter.
93 for (auto flag : { SkSL::Modifiers::kUniform_Flag, SkSL::Modifiers::kIn_Flag }) {
94 if (flag == SkSL::Modifiers::kIn_Flag) {
95 uniformSize = offset;
96 }
97 for (const auto& e : *program) {
98 if (e.fKind == SkSL::ProgramElement::kVar_Kind) {
99 SkSL::VarDeclarations& v = (SkSL::VarDeclarations&) e;
100 for (const auto& varStatement : v.fVars) {
101 const SkSL::Variable& var = *((SkSL::VarDeclaration&) *varStatement).fVar;
102
103 // Sanity check some rules that should be enforced by the IR generator.
104 // These are all layout options that only make sense in .fp files.
105 SkASSERT(!var.fModifiers.fLayout.fKey);
106 SkASSERT((var.fModifiers.fFlags & SkSL::Modifiers::kIn_Flag) == 0 ||
107 (var.fModifiers.fFlags & SkSL::Modifiers::kUniform_Flag) == 0);
108 SkASSERT(var.fModifiers.fLayout.fCType == SkSL::Layout::CType::kDefault);
109 SkASSERT(var.fModifiers.fLayout.fWhen.fLength == 0);
110 SkASSERT((var.fModifiers.fLayout.fFlags & SkSL::Layout::kTracked_Flag) == 0);
111
112 if (var.fModifiers.fFlags & flag) {
113 if (&var.fType == ctx.fFragmentProcessor_Type.get()) {
114 children.push_back(var.fName);
115 continue;
116 }
117
118 Variable v;
119 v.fName = var.fName;
120 v.fQualifier = (var.fModifiers.fFlags & SkSL::Modifiers::kUniform_Flag)
121 ? Variable::Qualifier::kUniform
122 : Variable::Qualifier::kIn;
123 v.fFlags = 0;
124 v.fCount = 1;
125
126 const SkSL::Type* type = &var.fType;
127 if (type->kind() == SkSL::Type::kArray_Kind) {
128 v.fFlags |= Variable::kArray_Flag;
129 v.fCount = type->columns();
130 type = &type->componentType();
131 }
132
133#if SK_SUPPORT_GPU
134#define SET_TYPES(cpuType, gpuType) do { v.fType = cpuType; v.fGPUType = gpuType;} while (false)
135#else
136#define SET_TYPES(cpuType, gpuType) do { v.fType = cpuType; } while (false)
137#endif
138
139 if (type == ctx.fBool_Type.get()) {
140 SET_TYPES(Variable::Type::kBool, kVoid_GrSLType);
141 } else if (type == ctx.fInt_Type.get()) {
142 SET_TYPES(Variable::Type::kInt, kVoid_GrSLType);
143 } else if (type == ctx.fFloat_Type.get()) {
144 SET_TYPES(Variable::Type::kFloat, kFloat_GrSLType);
145 } else if (type == ctx.fHalf_Type.get()) {
146 SET_TYPES(Variable::Type::kFloat, kHalf_GrSLType);
147 } else if (type == ctx.fFloat2_Type.get()) {
148 SET_TYPES(Variable::Type::kFloat2, kFloat2_GrSLType);
149 } else if (type == ctx.fHalf2_Type.get()) {
150 SET_TYPES(Variable::Type::kFloat2, kHalf2_GrSLType);
151 } else if (type == ctx.fFloat3_Type.get()) {
152 SET_TYPES(Variable::Type::kFloat3, kFloat3_GrSLType);
153 } else if (type == ctx.fHalf3_Type.get()) {
154 SET_TYPES(Variable::Type::kFloat3, kHalf3_GrSLType);
155 } else if (type == ctx.fFloat4_Type.get()) {
156 SET_TYPES(Variable::Type::kFloat4, kFloat4_GrSLType);
157 } else if (type == ctx.fHalf4_Type.get()) {
158 SET_TYPES(Variable::Type::kFloat4, kHalf4_GrSLType);
159 } else if (type == ctx.fFloat2x2_Type.get()) {
160 SET_TYPES(Variable::Type::kFloat2x2, kFloat2x2_GrSLType);
161 } else if (type == ctx.fHalf2x2_Type.get()) {
162 SET_TYPES(Variable::Type::kFloat2x2, kHalf2x2_GrSLType);
163 } else if (type == ctx.fFloat3x3_Type.get()) {
164 SET_TYPES(Variable::Type::kFloat3x3, kFloat3x3_GrSLType);
165 } else if (type == ctx.fHalf3x3_Type.get()) {
166 SET_TYPES(Variable::Type::kFloat3x3, kHalf3x3_GrSLType);
167 } else if (type == ctx.fFloat4x4_Type.get()) {
168 SET_TYPES(Variable::Type::kFloat4x4, kFloat4x4_GrSLType);
169 } else if (type == ctx.fHalf4x4_Type.get()) {
170 SET_TYPES(Variable::Type::kFloat4x4, kHalf4x4_GrSLType);
171 } else {
172 RETURN_FAILURE("Invalid input/uniform type: '%s'",
173 type->displayName().c_str());
174 }
175
176#undef SET_TYPES
177
178 switch (v.fType) {
179 case Variable::Type::kBool:
180 case Variable::Type::kInt:
181 if (v.fQualifier == Variable::Qualifier::kUniform) {
182 RETURN_FAILURE("'uniform' variables may not have '%s' type",
183 type->displayName().c_str());
184 }
185 break;
186
187 case Variable::Type::kFloat:
188 // Floats can be 'in' or 'uniform'
189 break;
190
191 case Variable::Type::kFloat2:
192 case Variable::Type::kFloat3:
193 case Variable::Type::kFloat4:
194 case Variable::Type::kFloat2x2:
195 case Variable::Type::kFloat3x3:
196 case Variable::Type::kFloat4x4:
197 if (v.fQualifier == Variable::Qualifier::kIn) {
198 RETURN_FAILURE("'in' variables may not have '%s' type",
199 type->displayName().c_str());
200 }
201 break;
202 }
203
204 if (v.fType != Variable::Type::kBool) {
205 offset = SkAlign4(offset);
206 }
207 v.fOffset = offset;
208 offset += v.sizeInBytes();
209 inAndUniformVars.push_back(v);
210 }
211 }
212 }
213 }
214 }
215
216#undef RETURN_FAILURE
217
218 sk_sp<SkRuntimeEffect> effect(new SkRuntimeEffect(std::move(sksl),
219 std::move(program),
220 std::move(inAndUniformVars),
221 std::move(children),
222 std::move(varyings),
223 uniformSize));
224 return std::make_pair(std::move(effect), SkString());
225}
226
227size_t SkRuntimeEffect::Variable::sizeInBytes() const {
228 auto element_size = [](Type type) -> size_t {
229 switch (type) {
230 case Type::kBool: return 1;
231 case Type::kInt: return sizeof(int32_t);
232 case Type::kFloat: return sizeof(float);
233 case Type::kFloat2: return sizeof(float) * 2;
234 case Type::kFloat3: return sizeof(float) * 3;
235 case Type::kFloat4: return sizeof(float) * 4;
236
237 case Type::kFloat2x2: return sizeof(float) * 4;
238 case Type::kFloat3x3: return sizeof(float) * 9;
239 case Type::kFloat4x4: return sizeof(float) * 16;
240 default: SkUNREACHABLE;
241 }
242 };
243 return element_size(fType) * fCount;
244}
245
246SkRuntimeEffect::SkRuntimeEffect(SkString sksl,
247 std::unique_ptr<SkSL::Program> baseProgram,
248 std::vector<Variable>&& inAndUniformVars,
249 std::vector<SkString>&& children,
250 std::vector<Varying>&& varyings,
251 size_t uniformSize)
252 : fHash(SkGoodHash()(sksl))
253 , fSkSL(std::move(sksl))
254 , fBaseProgram(std::move(baseProgram))
255 , fInAndUniformVars(std::move(inAndUniformVars))
256 , fChildren(std::move(children))
257 , fVaryings(std::move(varyings))
258 , fUniformSize(uniformSize) {
259 SkASSERT(fBaseProgram);
260 SkASSERT(SkIsAlign4(fUniformSize));
261 SkASSERT(fUniformSize <= this->inputSize());
262}
263
264SkRuntimeEffect::~SkRuntimeEffect() = default;
265
266size_t SkRuntimeEffect::inputSize() const {
267 return fInAndUniformVars.empty() ? 0
268 : SkAlign4(fInAndUniformVars.back().fOffset +
269 fInAndUniformVars.back().sizeInBytes());
270}
271
272SkRuntimeEffect::SpecializeResult
273SkRuntimeEffect::specialize(SkSL::Program& baseProgram,
274 const void* inputs,
275 const SkSL::SharedCompiler& compiler) const {
276 std::unordered_map<SkSL::String, SkSL::Program::Settings::Value> inputMap;
277 for (const auto& v : fInAndUniformVars) {
278 if (v.fQualifier != Variable::Qualifier::kIn) {
279 continue;
280 }
281 // 'in' arrays are not supported
282 SkASSERT(!v.isArray());
283 SkSL::String name(v.fName.c_str(), v.fName.size());
284 switch (v.fType) {
285 case Variable::Type::kBool: {
286 bool b = *SkTAddOffset<const bool>(inputs, v.fOffset);
287 inputMap.insert(std::make_pair(name, SkSL::Program::Settings::Value(b)));
288 break;
289 }
290 case Variable::Type::kInt: {
291 int32_t i = *SkTAddOffset<const int32_t>(inputs, v.fOffset);
292 inputMap.insert(std::make_pair(name, SkSL::Program::Settings::Value(i)));
293 break;
294 }
295 case Variable::Type::kFloat: {
296 float f = *SkTAddOffset<const float>(inputs, v.fOffset);
297 inputMap.insert(std::make_pair(name, SkSL::Program::Settings::Value(f)));
298 break;
299 }
300 default:
301 SkDEBUGFAIL("Unsupported input variable type");
302 return SpecializeResult{nullptr, SkString("Unsupported input variable type")};
303 }
304 }
305
306 auto specialized = compiler->specialize(baseProgram, inputMap);
307 bool optimized = compiler->optimize(*specialized);
308 if (!optimized) {
309 return SpecializeResult{nullptr, SkString(compiler->errorText().c_str())};
310 }
311 return SpecializeResult{std::move(specialized), SkString()};
312}
313
314#if SK_SUPPORT_GPU
315bool SkRuntimeEffect::toPipelineStage(const void* inputs, const GrShaderCaps* shaderCaps,
316 GrContextOptions::ShaderErrorHandler* errorHandler,
317 SkSL::PipelineStageArgs* outArgs) {
318 SkSL::SharedCompiler compiler;
319
320 // This function is used by the GPU backend, and can't reuse our previously built fBaseProgram.
321 // If the supplied shaderCaps have any non-default values, we have baked in the wrong settings.
322 SkSL::Program::Settings settings;
323 settings.fCaps = shaderCaps;
324
325 auto baseProgram = compiler->convertProgram(SkSL::Program::kPipelineStage_Kind,
326 SkSL::String(fSkSL.c_str(), fSkSL.size()),
327 settings);
328 if (!baseProgram) {
329 errorHandler->compileError(fSkSL.c_str(), compiler->errorText().c_str());
330 return false;
331 }
332
333 auto [specialized, errorText] = this->specialize(*baseProgram, inputs, compiler);
334 if (!specialized) {
335 errorHandler->compileError(fSkSL.c_str(), errorText.c_str());
336 return false;
337 }
338
339 if (!compiler->toPipelineStage(*specialized, outArgs)) {
340 errorHandler->compileError(fSkSL.c_str(), compiler->errorText().c_str());
341 return false;
342 }
343
344 return true;
345}
346#endif
347
348SkRuntimeEffect::ByteCodeResult SkRuntimeEffect::toByteCode(const void* inputs) const {
349 SkSL::SharedCompiler compiler;
350
351 auto [specialized, errorText] = this->specialize(*fBaseProgram, inputs, compiler);
352 if (!specialized) {
353 return ByteCodeResult{nullptr, errorText};
354 }
355 auto byteCode = compiler->toByteCode(*specialized);
356 return ByteCodeResult(std::move(byteCode), SkString(compiler->errorText().c_str()));
357}
358
359///////////////////////////////////////////////////////////////////////////////////////////////////
360
361static std::vector<skvm::F32> program_fn(skvm::Builder* p,
362 const SkSL::ByteCodeFunction& fn,
363 const std::vector<skvm::F32>& uniform,
364 std::vector<skvm::F32> stack) {
365 auto push = [&](skvm::F32 x) { stack.push_back(x); };
366 auto pop = [&]{ skvm::F32 x = stack.back(); stack.pop_back(); return x; };
367
368 for (int i = 0; i < fn.getLocalCount(); i++) {
369 push(p->splat(0.0f));
370 }
371
372 for (const uint8_t *ip = fn.code(), *end = ip + fn.size(); ip != end; ) {
373 using Inst = SkSL::ByteCodeInstruction;
374
375 auto inst = (Inst)(uintptr_t)sk_unaligned_load<SkSL::instruction>(ip);
376 ip += sizeof(SkSL::instruction);
377
378 auto u8 = [&]{ auto x = sk_unaligned_load<uint8_t >(ip); ip += sizeof(x); return x; };
379 //auto u16 = [&]{ auto x = sk_unaligned_load<uint16_t>(ip); ip += sizeof(x); return x; };
380 auto u32 = [&]{ auto x = sk_unaligned_load<uint32_t>(ip); ip += sizeof(x); return x; };
381
382 switch (inst) {
383 default:
384 #if 0
385 fn.disassemble();
386 SkDebugf("inst %04x unimplemented\n", inst);
387 __builtin_debugtrap();
388 #endif
389 return {};
390
391 case Inst::kLoad: {
392 SkAssertResult(u8() == 1);
393 int ix = u8();
394 push(stack[ix + 0]);
395 } break;
396
397 case Inst::kLoad2: {
398 SkAssertResult(u8() == 2);
399 int ix = u8();
400 push(stack[ix + 0]);
401 push(stack[ix + 1]);
402 } break;
403
404 case Inst::kLoadUniform: {
405 SkAssertResult(u8() == 1);
406 int ix = u8();
407 push(uniform[ix]);
408 } break;
409
410 case Inst::kLoadUniform4: {
411 SkAssertResult(u8() == 4);
412 int ix = u8();
413 push(uniform[ix + 0]);
414 push(uniform[ix + 1]);
415 push(uniform[ix + 2]);
416 push(uniform[ix + 3]);
417 } break;
418
419 case Inst::kStore: {
420 int ix = u8();
421 stack[ix + 0] = pop();
422 } break;
423
424 case Inst::kStore2: {
425 int ix = u8();
426 stack[ix + 1] = pop();
427 stack[ix + 0] = pop();
428 } break;
429
430 case Inst::kStore4: {
431 int ix = u8();
432 stack[ix + 3] = pop();
433 stack[ix + 2] = pop();
434 stack[ix + 1] = pop();
435 stack[ix + 0] = pop();
436 } break;
437
438
439 case Inst::kPushImmediate: {
440 push(bit_cast(p->splat(u32())));
441 } break;
442
443 case Inst::kDup: {
444 int off = u8();
445 push(stack[stack.size() - off]);
446 } break;
447
448 case Inst::kAddF: {
449 SkAssertResult(u8() == 1);
450 skvm::F32 x = pop(),
451 a = pop();
452 push(a+x);
453 } break;
454
455 case Inst::kMultiplyF: {
456 SkAssertResult(u8() == 1);
457 skvm::F32 x = pop(),
458 a = pop();
459 push(a*x);
460 } break;
461
462 case Inst::kMultiplyF2: {
463 SkAssertResult(u8() == 2);
464 skvm::F32 x = pop(), y = pop(),
465 a = pop(), b = pop();
466 push(b*y);
467 push(a*x);
468 } break;
469
470 // Baby steps... just leaving test conditions on the stack for now.
471 case Inst::kMaskPush: break;
472 case Inst::kMaskNegate: break;
473
474 case Inst::kCompareFLT: {
475 SkAssertResult(u8() == 1);
476 skvm::F32 x = pop(),
477 a = pop();
478 push(bit_cast(a<x));
479 } break;
480
481 case Inst::kMaskBlend: {
482 std::vector<skvm::F32> if_true,
483 if_false;
484 int count = u8();
485 for (int i = 0; i < count; i++) { if_false.push_back(pop()); }
486 for (int i = 0; i < count; i++) { if_true .push_back(pop()); }
487
488 skvm::I32 cond = bit_cast(pop());
489 for (int i = count; i --> 0; ) {
490 push(select(cond, if_true[i], if_false[i]));
491 }
492 } break;
493
494 case Inst::kReturn: {
495 SkAssertResult(u8() == 0);
496 SkASSERT(ip == end);
497 } break;
498 }
499 }
500 for (int i = 0; i < fn.getLocalCount(); i++) {
501 pop();
502 }
503 return stack;
504}
505
506
507class SkRuntimeColorFilter : public SkColorFilter {
508public:
509 SkRuntimeColorFilter(sk_sp<SkRuntimeEffect> effect, sk_sp<SkData> inputs,
510 sk_sp<SkColorFilter> children[], size_t childCount)
511 : fEffect(std::move(effect))
512 , fInputs(std::move(inputs))
513 , fChildren(children, children + childCount) {}
514
515#if SK_SUPPORT_GPU
516 std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(
517 GrRecordingContext* context, const GrColorInfo& colorInfo) const override {
518 auto fp = GrSkSLFP::Make(context, fEffect, "Runtime Color Filter", fInputs);
519 for (const auto& child : fChildren) {
520 auto childFP = child ? child->asFragmentProcessor(context, colorInfo) : nullptr;
521 if (!childFP) {
522 // TODO: This is the case that should eventually mean "the original input color"
523 return nullptr;
524 }
525 fp->addChild(std::move(childFP));
526 }
527 return std::move(fp);
528 }
529#endif
530
531 const SkSL::ByteCode* byteCode() const {
532 SkAutoMutexExclusive ama(fByteCodeMutex);
533 if (!fByteCode) {
534 auto [byteCode, errorText] = fEffect->toByteCode(fInputs->data());
535 if (!byteCode) {
536 SkDebugf("%s\n", errorText.c_str());
537 return nullptr;
538 }
539 fByteCode = std::move(byteCode);
540 }
541 return fByteCode.get();
542 }
543
544 bool onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const override {
545 auto ctx = rec.fAlloc->make<SkRasterPipeline_InterpreterCtx>();
546 // don't need to set ctx->paintColor
547 ctx->inputs = fInputs->data();
548 ctx->ninputs = fEffect->uniformSize() / 4;
549 ctx->shaderConvention = false;
550
551 ctx->byteCode = this->byteCode();
552 if (!ctx->byteCode) {
553 return false;
554 }
555
556 ctx->fn = ctx->byteCode->getFunction("main");
557 rec.fPipeline->append(SkRasterPipeline::interpreter, ctx);
558 return true;
559 }
560
561 skvm::Color onProgram(skvm::Builder* p, skvm::Color c,
562 SkColorSpace* /*dstCS*/,
563 skvm::Uniforms* uniforms, SkArenaAlloc*) const override {
564 const SkSL::ByteCode* bc = this->byteCode();
565 if (!bc) {
566 return {};
567 }
568
569 const SkSL::ByteCodeFunction* fn = bc->getFunction("main");
570 if (!fn) {
571 return {};
572 }
573
574 std::vector<skvm::F32> uniform;
575 for (int i = 0; i < (int)fEffect->uniformSize() / 4; i++) {
576 float f;
577 memcpy(&f, (const char*)fInputs->data() + 4*i, 4);
578 uniform.push_back(p->uniformF(uniforms->pushF(f)));
579 }
580
581 std::vector<skvm::F32> stack =
582 program_fn(p, *fn, uniform, {c.r, c.g, c.b, c.a});
583
584 if (stack.size() == 4) {
585 return {stack[0], stack[1], stack[2], stack[3]};
586 }
587 return {};
588 }
589
590 void flatten(SkWriteBuffer& buffer) const override {
591 buffer.writeString(fEffect->source().c_str());
592 if (fInputs) {
593 buffer.writeDataAsByteArray(fInputs.get());
594 } else {
595 buffer.writeByteArray(nullptr, 0);
596 }
597 buffer.write32(fChildren.size());
598 for (const auto& child : fChildren) {
599 buffer.writeFlattenable(child.get());
600 }
601 }
602
603 SK_FLATTENABLE_HOOKS(SkRuntimeColorFilter)
604
605private:
606 sk_sp<SkRuntimeEffect> fEffect;
607 sk_sp<SkData> fInputs;
608 std::vector<sk_sp<SkColorFilter>> fChildren;
609
610 mutable SkMutex fByteCodeMutex;
611 mutable std::unique_ptr<SkSL::ByteCode> fByteCode;
612};
613
614sk_sp<SkFlattenable> SkRuntimeColorFilter::CreateProc(SkReadBuffer& buffer) {
615 SkString sksl;
616 buffer.readString(&sksl);
617 sk_sp<SkData> inputs = buffer.readByteArrayAsData();
618
619 auto effect = std::get<0>(SkRuntimeEffect::Make(std::move(sksl)));
620 if (!effect) {
621 buffer.validate(false);
622 return nullptr;
623 }
624
625 size_t childCount = buffer.read32();
626 if (childCount != effect->children().count()) {
627 buffer.validate(false);
628 return nullptr;
629 }
630
631 std::vector<sk_sp<SkColorFilter>> children;
632 children.resize(childCount);
633 for (size_t i = 0; i < children.size(); ++i) {
634 children[i] = buffer.readColorFilter();
635 }
636
637 return effect->makeColorFilter(std::move(inputs), children.data(), children.size());
638}
639
640///////////////////////////////////////////////////////////////////////////////////////////////////
641
642class SkRTShader : public SkShaderBase {
643public:
644 SkRTShader(sk_sp<SkRuntimeEffect> effect, sk_sp<SkData> inputs, const SkMatrix* localMatrix,
645 sk_sp<SkShader>* children, size_t childCount, bool isOpaque)
646 : SkShaderBase(localMatrix)
647 , fEffect(std::move(effect))
648 , fIsOpaque(isOpaque)
649 , fInputs(std::move(inputs))
650 , fChildren(children, children + childCount) {}
651
652 bool isOpaque() const override { return fIsOpaque; }
653
654#if SK_SUPPORT_GPU
655 std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs& args) const override {
656 SkMatrix matrix;
657 if (!this->totalLocalMatrix(args.fPreLocalMatrix)->invert(&matrix)) {
658 return nullptr;
659 }
660 auto fp = GrSkSLFP::Make(args.fContext, fEffect, "runtime_shader", fInputs, &matrix);
661 for (const auto& child : fChildren) {
662 auto childFP = child ? as_SB(child)->asFragmentProcessor(args) : nullptr;
663 if (!childFP) {
664 // TODO: This is the case that should eventually mean "the original input color"
665 return nullptr;
666 }
667 fp->addChild(std::move(childFP));
668 }
669 if (GrColorTypeClampType(args.fDstColorInfo->colorType()) != GrClampType::kNone) {
670 return GrFragmentProcessor::ClampPremulOutput(std::move(fp));
671 } else {
672 return std::move(fp);
673 }
674 }
675#endif
676
677 const SkSL::ByteCode* byteCode() const {
678 SkAutoMutexExclusive ama(fByteCodeMutex);
679 if (!fByteCode) {
680 auto [byteCode, errorText] = fEffect->toByteCode(fInputs->data());
681 if (!byteCode) {
682 SkDebugf("%s\n", errorText.c_str());
683 return nullptr;
684 }
685 fByteCode = std::move(byteCode);
686 }
687 return fByteCode.get();
688 }
689
690 bool onAppendStages(const SkStageRec& rec) const override {
691 SkMatrix inverse;
692 if (!this->computeTotalInverse(rec.fCTM, rec.fLocalM, &inverse)) {
693 return false;
694 }
695
696 auto ctx = rec.fAlloc->make<SkRasterPipeline_InterpreterCtx>();
697 ctx->paintColor = rec.fPaint.getColor4f();
698 ctx->inputs = fInputs->data();
699 ctx->ninputs = fEffect->uniformSize() / 4;
700 ctx->shaderConvention = true;
701
702 ctx->byteCode = this->byteCode();
703 if (!ctx->byteCode) {
704 return false;
705 }
706 ctx->fn = ctx->byteCode->getFunction("main");
707 rec.fPipeline->append(SkRasterPipeline::seed_shader);
708 rec.fPipeline->append_matrix(rec.fAlloc, inverse);
709 rec.fPipeline->append(SkRasterPipeline::interpreter, ctx);
710 return true;
711 }
712
713 skvm::Color onProgram(skvm::Builder* p, skvm::F32 x, skvm::F32 y, skvm::Color paint,
714 const SkMatrix& ctm, const SkMatrix* localM,
715 SkFilterQuality, const SkColorInfo& /*dst*/,
716 skvm::Uniforms* uniforms, SkArenaAlloc*) const override {
717 const SkSL::ByteCode* bc = this->byteCode();
718 if (!bc) {
719 return {};
720 }
721
722 const SkSL::ByteCodeFunction* fn = bc->getFunction("main");
723 if (!fn) {
724 return {};
725 }
726
727 std::vector<skvm::F32> uniform;
728 for (int i = 0; i < (int)fEffect->uniformSize() / 4; i++) {
729 float f;
730 memcpy(&f, (const char*)fInputs->data() + 4*i, 4);
731 uniform.push_back(p->uniformF(uniforms->pushF(f)));
732 }
733
734 SkMatrix inv;
735 if (!this->computeTotalInverse(ctm, localM, &inv)) {
736 return {};
737 }
738 SkShaderBase::ApplyMatrix(p,inv, &x,&y,uniforms);
739
740 std::vector<skvm::F32> stack =
741 program_fn(p, *fn, uniform, {x,y, paint.r, paint.g, paint.b, paint.a});
742
743 if (stack.size() == 6) {
744 return {stack[2], stack[3], stack[4], stack[5]};
745 }
746 return {};
747 }
748
749 void flatten(SkWriteBuffer& buffer) const override {
750 uint32_t flags = 0;
751 if (fIsOpaque) {
752 flags |= kIsOpaque_Flag;
753 }
754 if (!this->getLocalMatrix().isIdentity()) {
755 flags |= kHasLocalMatrix_Flag;
756 }
757
758 buffer.writeString(fEffect->source().c_str());
759 if (fInputs) {
760 buffer.writeDataAsByteArray(fInputs.get());
761 } else {
762 buffer.writeByteArray(nullptr, 0);
763 }
764 buffer.write32(flags);
765 if (flags & kHasLocalMatrix_Flag) {
766 buffer.writeMatrix(this->getLocalMatrix());
767 }
768 buffer.write32(fChildren.size());
769 for (const auto& child : fChildren) {
770 buffer.writeFlattenable(child.get());
771 }
772 }
773
774 SkRuntimeEffect* asRuntimeEffect() const override { return fEffect.get(); }
775
776 SK_FLATTENABLE_HOOKS(SkRTShader)
777
778private:
779 enum Flags {
780 kIsOpaque_Flag = 1 << 0,
781 kHasLocalMatrix_Flag = 1 << 1,
782 };
783
784 sk_sp<SkRuntimeEffect> fEffect;
785 bool fIsOpaque;
786
787 sk_sp<SkData> fInputs;
788 std::vector<sk_sp<SkShader>> fChildren;
789
790 mutable SkMutex fByteCodeMutex;
791 mutable std::unique_ptr<SkSL::ByteCode> fByteCode;
792};
793
794sk_sp<SkFlattenable> SkRTShader::CreateProc(SkReadBuffer& buffer) {
795 SkString sksl;
796 buffer.readString(&sksl);
797 sk_sp<SkData> inputs = buffer.readByteArrayAsData();
798 uint32_t flags = buffer.read32();
799
800 bool isOpaque = SkToBool(flags & kIsOpaque_Flag);
801 SkMatrix localM, *localMPtr = nullptr;
802 if (flags & kHasLocalMatrix_Flag) {
803 buffer.readMatrix(&localM);
804 localMPtr = &localM;
805 }
806
807 auto effect = std::get<0>(SkRuntimeEffect::Make(std::move(sksl)));
808 if (!effect) {
809 buffer.validate(false);
810 return nullptr;
811 }
812
813 size_t childCount = buffer.read32();
814 if (childCount != effect->children().count()) {
815 buffer.validate(false);
816 return nullptr;
817 }
818
819 std::vector<sk_sp<SkShader>> children;
820 children.resize(childCount);
821 for (size_t i = 0; i < children.size(); ++i) {
822 children[i] = buffer.readShader();
823 }
824
825 return effect->makeShader(std::move(inputs), children.data(), children.size(), localMPtr,
826 isOpaque);
827}
828
829///////////////////////////////////////////////////////////////////////////////////////////////////
830
831sk_sp<SkShader> SkRuntimeEffect::makeShader(sk_sp<SkData> inputs,
832 sk_sp<SkShader> children[], size_t childCount,
833 const SkMatrix* localMatrix, bool isOpaque) {
834 if (!inputs) {
835 inputs = SkData::MakeEmpty();
836 }
837 return inputs->size() == this->inputSize() && childCount == fChildren.size()
838 ? sk_sp<SkShader>(new SkRTShader(sk_ref_sp(this), std::move(inputs), localMatrix,
839 children, childCount, isOpaque))
840 : nullptr;
841}
842
843sk_sp<SkColorFilter> SkRuntimeEffect::makeColorFilter(sk_sp<SkData> inputs,
844 sk_sp<SkColorFilter> children[],
845 size_t childCount) {
846 if (!inputs) {
847 inputs = SkData::MakeEmpty();
848 }
849 return inputs && inputs->size() == this->inputSize() && childCount == fChildren.size()
850 ? sk_sp<SkColorFilter>(new SkRuntimeColorFilter(sk_ref_sp(this), std::move(inputs),
851 children, childCount))
852 : nullptr;
853}
854
855sk_sp<SkColorFilter> SkRuntimeEffect::makeColorFilter(sk_sp<SkData> inputs) {
856 return this->makeColorFilter(std::move(inputs), nullptr, 0);
857}
858
859///////////////////////////////////////////////////////////////////////////////////////////////////
860
861void SkRuntimeEffect::RegisterFlattenables() {
862 SK_REGISTER_FLATTENABLE(SkRuntimeColorFilter);
863 SK_REGISTER_FLATTENABLE(SkRTShader);
864}
865