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/SkCanvasPriv.h"
14#include "src/core/SkColorFilterBase.h"
15#include "src/core/SkColorSpacePriv.h"
16#include "src/core/SkColorSpaceXformSteps.h"
17#include "src/core/SkMatrixProvider.h"
18#include "src/core/SkRasterPipeline.h"
19#include "src/core/SkReadBuffer.h"
20#include "src/core/SkUtils.h"
21#include "src/core/SkVM.h"
22#include "src/core/SkWriteBuffer.h"
23#include "src/sksl/SkSLAnalysis.h"
24#include "src/sksl/SkSLByteCode.h"
25#include "src/sksl/SkSLCompiler.h"
26#include "src/sksl/ir/SkSLFunctionDefinition.h"
27#include "src/sksl/ir/SkSLVarDeclarations.h"
28
29#if SK_SUPPORT_GPU
30#include "include/gpu/GrRecordingContext.h"
31#include "src/gpu/GrColorInfo.h"
32#include "src/gpu/GrFPArgs.h"
33#include "src/gpu/effects/GrMatrixEffect.h"
34#include "src/gpu/effects/GrSkSLFP.h"
35#endif
36
37#include <algorithm>
38
39namespace SkSL {
40class SharedCompiler {
41public:
42 SharedCompiler() : fLock(compiler_mutex()) {
43 if (!gCompiler) {
44 gCompiler = new SkSL::Compiler{};
45 gInlineThreshold = SkSL::Program::Settings().fInlineThreshold;
46 }
47 }
48
49 SkSL::Compiler* operator->() const { return gCompiler; }
50
51 int getInlineThreshold() const { return gInlineThreshold; }
52 void setInlineThreshold(int threshold) { gInlineThreshold = threshold; }
53
54private:
55 SkAutoMutexExclusive fLock;
56
57 static SkMutex& compiler_mutex() {
58 static SkMutex& mutex = *(new SkMutex);
59 return mutex;
60 }
61
62 static SkSL::Compiler* gCompiler;
63 static int gInlineThreshold;
64};
65SkSL::Compiler* SharedCompiler::gCompiler = nullptr;
66int SharedCompiler::gInlineThreshold = 0;
67} // namespace SkSL
68
69void SkRuntimeEffect_SetInlineThreshold(int threshold) {
70 SkSL::SharedCompiler compiler;
71 compiler.setInlineThreshold(threshold);
72}
73
74// Accepts a valid marker, or "normals(<marker>)"
75static bool parse_marker(const SkSL::StringFragment& marker, uint32_t* id, uint32_t* flags) {
76 SkString s = marker;
77 if (s.startsWith("normals(") && s.endsWith(')')) {
78 *flags |= SkRuntimeEffect::Uniform::kMarkerNormals_Flag;
79 s.set(marker.fChars + 8, marker.fLength - 9);
80 }
81 if (!SkCanvasPriv::ValidateMarker(s.c_str())) {
82 return false;
83 }
84 *id = SkOpts::hash_fn(s.c_str(), s.size(), 0);
85 return true;
86}
87
88static bool init_uniform_type(const SkSL::Context& ctx,
89 const SkSL::Type* type,
90 SkRuntimeEffect::Uniform* v) {
91#define SET_TYPES(cpuType, gpuType) \
92 do { \
93 v->fType = SkRuntimeEffect::Uniform::Type::cpuType; \
94 v->fGPUType = gpuType; \
95 return true; \
96 } while (false)
97
98 if (type == ctx.fFloat_Type.get()) { SET_TYPES(kFloat, kFloat_GrSLType); }
99 if (type == ctx.fHalf_Type.get()) { SET_TYPES(kFloat, kHalf_GrSLType); }
100 if (type == ctx.fFloat2_Type.get()) { SET_TYPES(kFloat2, kFloat2_GrSLType); }
101 if (type == ctx.fHalf2_Type.get()) { SET_TYPES(kFloat2, kHalf2_GrSLType); }
102 if (type == ctx.fFloat3_Type.get()) { SET_TYPES(kFloat3, kFloat3_GrSLType); }
103 if (type == ctx.fHalf3_Type.get()) { SET_TYPES(kFloat3, kHalf3_GrSLType); }
104 if (type == ctx.fFloat4_Type.get()) { SET_TYPES(kFloat4, kFloat4_GrSLType); }
105 if (type == ctx.fHalf4_Type.get()) { SET_TYPES(kFloat4, kHalf4_GrSLType); }
106 if (type == ctx.fFloat2x2_Type.get()) { SET_TYPES(kFloat2x2, kFloat2x2_GrSLType); }
107 if (type == ctx.fHalf2x2_Type.get()) { SET_TYPES(kFloat2x2, kHalf2x2_GrSLType); }
108 if (type == ctx.fFloat3x3_Type.get()) { SET_TYPES(kFloat3x3, kFloat3x3_GrSLType); }
109 if (type == ctx.fHalf3x3_Type.get()) { SET_TYPES(kFloat3x3, kHalf3x3_GrSLType); }
110 if (type == ctx.fFloat4x4_Type.get()) { SET_TYPES(kFloat4x4, kFloat4x4_GrSLType); }
111 if (type == ctx.fHalf4x4_Type.get()) { SET_TYPES(kFloat4x4, kHalf4x4_GrSLType); }
112
113#undef SET_TYPES
114
115 return false;
116}
117
118SkRuntimeEffect::EffectResult SkRuntimeEffect::Make(SkString sksl) {
119 SkSL::SharedCompiler compiler;
120 SkSL::Program::Settings settings;
121 settings.fInlineThreshold = compiler.getInlineThreshold();
122 auto program = compiler->convertProgram(SkSL::Program::kPipelineStage_Kind,
123 SkSL::String(sksl.c_str(), sksl.size()),
124 settings);
125 // TODO: Many errors aren't caught until we process the generated Program here. Catching those
126 // in the IR generator would provide better errors messages (with locations).
127 #define RETURN_FAILURE(...) return std::make_tuple(nullptr, SkStringPrintf(__VA_ARGS__))
128
129 if (!program) {
130 RETURN_FAILURE("%s", compiler->errorText().c_str());
131 }
132 if (!compiler->optimize(*program)) {
133 RETURN_FAILURE("%s", compiler->errorText().c_str());
134 }
135
136 bool hasMain = false;
137 const bool usesSampleCoords = SkSL::Analysis::ReferencesSampleCoords(*program);
138 const bool usesFragCoords = SkSL::Analysis::ReferencesFragCoords(*program);
139
140 // Color filters are not allowed to depend on position (local or device) in any way, but they
141 // can sample children with matrices or explicit coords. Because the children are color filters,
142 // we know (by induction) that they don't use those coords, so we keep the overall invariant.
143 //
144 // Further down, we also ensure that color filters can't use layout(marker), which would allow
145 // them to change behavior based on the CTM.
146 bool allowColorFilter = !usesSampleCoords && !usesFragCoords;
147
148 size_t offset = 0;
149 std::vector<Uniform> uniforms;
150 std::vector<SkString> children;
151 std::vector<SkSL::SampleUsage> sampleUsages;
152 std::vector<Varying> varyings;
153 const SkSL::Context& ctx(compiler->context());
154
155 // Go through program elements, pulling out information that we need
156 for (const auto& elem : *program) {
157 // Variables (uniform, varying, etc.)
158 if (elem.fKind == SkSL::ProgramElement::kVar_Kind) {
159 const auto& varDecls = static_cast<const SkSL::VarDeclarations&>(elem);
160 for (const auto& varDecl : varDecls.fVars) {
161 const SkSL::Variable& var =
162 *(static_cast<const SkSL::VarDeclaration&>(*varDecl).fVar);
163
164 // Varyings (only used in conjunction with drawVertices)
165 if (var.fModifiers.fFlags & SkSL::Modifiers::kVarying_Flag) {
166 varyings.push_back({var.fName, var.fType.kind() == SkSL::Type::kVector_Kind
167 ? var.fType.columns()
168 : 1});
169 }
170 // Fragment Processors (aka 'shader'): These are child effects
171 else if (&var.fType == ctx.fFragmentProcessor_Type.get()) {
172 children.push_back(var.fName);
173 sampleUsages.push_back(SkSL::Analysis::GetSampleUsage(*program, var));
174 }
175 // 'uniform' variables
176 else if (var.fModifiers.fFlags & SkSL::Modifiers::kUniform_Flag) {
177 Uniform uni;
178 uni.fName = var.fName;
179 uni.fFlags = 0;
180 uni.fCount = 1;
181
182 const SkSL::Type* type = &var.fType;
183 if (type->kind() == SkSL::Type::kArray_Kind) {
184 uni.fFlags |= Uniform::kArray_Flag;
185 uni.fCount = type->columns();
186 type = &type->componentType();
187 }
188
189 if (!init_uniform_type(ctx, type, &uni)) {
190 RETURN_FAILURE("Invalid uniform type: '%s'", type->displayName().c_str());
191 }
192
193 const SkSL::StringFragment& marker(var.fModifiers.fLayout.fMarker);
194 if (marker.fLength) {
195 uni.fFlags |= Uniform::kMarker_Flag;
196 allowColorFilter = false;
197 if (!parse_marker(marker, &uni.fMarker, &uni.fFlags)) {
198 RETURN_FAILURE("Invalid 'marker' string: '%.*s'", (int)marker.fLength,
199 marker.fChars);
200 }
201 }
202
203 if (var.fModifiers.fLayout.fFlags & SkSL::Layout::Flag::kSRGBUnpremul_Flag) {
204 uni.fFlags |= Uniform::kSRGBUnpremul_Flag;
205 }
206
207 uni.fOffset = offset;
208 offset += uni.sizeInBytes();
209 SkASSERT(SkIsAlign4(offset));
210
211 uniforms.push_back(uni);
212 }
213 }
214 }
215 // Functions
216 else if (elem.fKind == SkSL::ProgramElement::kFunction_Kind) {
217 const auto& func = static_cast<const SkSL::FunctionDefinition&>(elem);
218 const SkSL::FunctionDeclaration& decl = func.fDeclaration;
219 if (decl.fName == "main") {
220 hasMain = true;
221 }
222 }
223 }
224
225 if (!hasMain) {
226 RETURN_FAILURE("missing 'main' function");
227 }
228
229#undef RETURN_FAILURE
230
231 sk_sp<SkRuntimeEffect> effect(new SkRuntimeEffect(std::move(sksl),
232 std::move(program),
233 std::move(uniforms),
234 std::move(children),
235 std::move(sampleUsages),
236 std::move(varyings),
237 usesSampleCoords,
238 allowColorFilter));
239 return std::make_tuple(std::move(effect), SkString());
240}
241
242size_t SkRuntimeEffect::Uniform::sizeInBytes() const {
243 auto element_size = [](Type type) -> size_t {
244 switch (type) {
245 case Type::kFloat: return sizeof(float);
246 case Type::kFloat2: return sizeof(float) * 2;
247 case Type::kFloat3: return sizeof(float) * 3;
248 case Type::kFloat4: return sizeof(float) * 4;
249
250 case Type::kFloat2x2: return sizeof(float) * 4;
251 case Type::kFloat3x3: return sizeof(float) * 9;
252 case Type::kFloat4x4: return sizeof(float) * 16;
253 default: SkUNREACHABLE;
254 }
255 };
256 return element_size(fType) * fCount;
257}
258
259SkRuntimeEffect::SkRuntimeEffect(SkString sksl,
260 std::unique_ptr<SkSL::Program> baseProgram,
261 std::vector<Uniform>&& uniforms,
262 std::vector<SkString>&& children,
263 std::vector<SkSL::SampleUsage>&& sampleUsages,
264 std::vector<Varying>&& varyings,
265 bool usesSampleCoords,
266 bool allowColorFilter)
267 : fHash(SkGoodHash()(sksl))
268 , fSkSL(std::move(sksl))
269 , fBaseProgram(std::move(baseProgram))
270 , fUniforms(std::move(uniforms))
271 , fChildren(std::move(children))
272 , fSampleUsages(std::move(sampleUsages))
273 , fVaryings(std::move(varyings))
274 , fUsesSampleCoords(usesSampleCoords)
275 , fAllowColorFilter(allowColorFilter) {
276 SkASSERT(fBaseProgram);
277 SkASSERT(fChildren.size() == fSampleUsages.size());
278}
279
280SkRuntimeEffect::~SkRuntimeEffect() = default;
281
282size_t SkRuntimeEffect::uniformSize() const {
283 return fUniforms.empty() ? 0
284 : SkAlign4(fUniforms.back().fOffset + fUniforms.back().sizeInBytes());
285}
286
287const SkRuntimeEffect::Uniform* SkRuntimeEffect::findUniform(const char* name) const {
288 auto iter = std::find_if(fUniforms.begin(), fUniforms.end(),
289 [name](const Uniform& u) { return u.fName.equals(name); });
290 return iter == fUniforms.end() ? nullptr : &(*iter);
291}
292
293int SkRuntimeEffect::findChild(const char* name) const {
294 auto iter = std::find_if(fChildren.begin(), fChildren.end(),
295 [name](const SkString& s) { return s.equals(name); });
296 return iter == fChildren.end() ? -1 : static_cast<int>(iter - fChildren.begin());
297}
298
299#if SK_SUPPORT_GPU
300bool SkRuntimeEffect::toPipelineStage(const GrShaderCaps* shaderCaps,
301 GrContextOptions::ShaderErrorHandler* errorHandler,
302 SkSL::PipelineStageArgs* outArgs) {
303 SkSL::SharedCompiler compiler;
304
305 // This function is used by the GPU backend, and can't reuse our previously built fBaseProgram.
306 // If the supplied shaderCaps have any non-default values, we have baked in the wrong settings.
307 SkSL::Program::Settings settings;
308 settings.fCaps = shaderCaps;
309 settings.fInlineThreshold = compiler.getInlineThreshold();
310
311 auto program = compiler->convertProgram(SkSL::Program::kPipelineStage_Kind,
312 SkSL::String(fSkSL.c_str(), fSkSL.size()),
313 settings);
314 if (!program) {
315 errorHandler->compileError(fSkSL.c_str(), compiler->errorText().c_str());
316 return false;
317 }
318
319 if (!compiler->toPipelineStage(*program, outArgs)) {
320 errorHandler->compileError(fSkSL.c_str(), compiler->errorText().c_str());
321 return false;
322 }
323
324 return true;
325}
326#endif
327
328SkRuntimeEffect::ByteCodeResult SkRuntimeEffect::toByteCode() const {
329 SkSL::SharedCompiler compiler;
330
331 auto byteCode = compiler->toByteCode(*fBaseProgram);
332 return ByteCodeResult(std::move(byteCode), SkString(compiler->errorText().c_str()));
333}
334
335///////////////////////////////////////////////////////////////////////////////////////////////////
336
337using SampleChildFn = std::function<skvm::Color(int, skvm::Coord)>;
338
339static skvm::Color program_fn(skvm::Builder* p,
340 const SkSL::ByteCodeFunction& fn,
341 const std::vector<skvm::F32>& uniform,
342 skvm::Color inColor,
343 SampleChildFn sampleChild,
344 skvm::Coord device, skvm::Coord local) {
345 std::vector<skvm::F32> stack;
346
347 auto push = [&](skvm::F32 x) { stack.push_back(x); };
348 auto pop = [&]{ skvm::F32 x = stack.back(); stack.pop_back(); return x; };
349
350 // main(inout half4 color) or main(float2 local, inout half4 color)
351 SkASSERT(fn.getParameterCount() == 4 || fn.getParameterCount() == 6);
352 if (fn.getParameterCount() == 6) {
353 push(local.x);
354 push(local.y);
355 }
356 push(inColor.r);
357 push(inColor.g);
358 push(inColor.b);
359 push(inColor.a);
360
361 for (int i = 0; i < fn.getLocalCount(); i++) {
362 push(p->splat(0.0f));
363 }
364
365 for (const uint8_t *ip = fn.code(), *end = ip + fn.size(); ip != end; ) {
366 using Inst = SkSL::ByteCodeInstruction;
367
368 auto inst = sk_unaligned_load<Inst>(ip);
369 ip += sizeof(Inst);
370
371 auto u8 = [&]{ auto x = sk_unaligned_load<uint8_t >(ip); ip += sizeof(x); return x; };
372 //auto u16 = [&]{ auto x = sk_unaligned_load<uint16_t>(ip); ip += sizeof(x); return x; };
373 auto u32 = [&]{ auto x = sk_unaligned_load<uint32_t>(ip); ip += sizeof(x); return x; };
374
375 auto unary = [&](auto&& fn) {
376 int N = u8();
377 std::vector<skvm::F32> a(N);
378 for (int i = N; i --> 0; ) { a[i] = pop(); }
379
380 for (int i = 0; i < N; i++) {
381 push(fn(a[i]));
382 }
383 };
384
385 auto binary = [&](auto&& fn) {
386 int N = u8();
387 std::vector<skvm::F32> a(N), b(N);
388 for (int i = N; i --> 0; ) { b[i] = pop(); }
389 for (int i = N; i --> 0; ) { a[i] = pop(); }
390
391 for (int i = 0; i < N; i++) {
392 push(fn(a[i], b[i]));
393 }
394 };
395
396 auto ternary = [&](auto&& fn) {
397 int N = u8();
398 std::vector<skvm::F32> a(N), b(N), c(N);
399 for (int i = N; i --> 0; ) { c[i] = pop(); }
400 for (int i = N; i --> 0; ) { b[i] = pop(); }
401 for (int i = N; i --> 0; ) { a[i] = pop(); }
402
403 for (int i = 0; i < N; i++) {
404 push(fn(a[i], b[i], c[i]));
405 }
406 };
407
408 auto sample = [&](int ix, skvm::Coord coord) {
409 if (skvm::Color c = sampleChild(ix, coord)) {
410 push(c.r);
411 push(c.g);
412 push(c.b);
413 push(c.a);
414 return true;
415 }
416 return false;
417 };
418
419 switch (inst) {
420 default:
421 #if 0
422 fn.disassemble();
423 SkDebugf("inst %02x unimplemented\n", inst);
424 __builtin_debugtrap();
425 #endif
426 return {};
427
428 case Inst::kSample: {
429 // Child shader to run.
430 int ix = u8();
431 if (!sample(ix, local)) {
432 return {};
433 }
434 } break;
435
436 case Inst::kSampleMatrix: {
437 // Child shader to run.
438 int ix = u8();
439
440 // Stack contains matrix to apply to sample coordinates.
441 skvm::F32 m[9];
442 for (int i = 9; i --> 0; ) { m[i] = pop(); }
443
444 // TODO: Optimize this for simpler matrices
445 skvm::F32 x = m[0]*local.x + m[3]*local.y + m[6],
446 y = m[1]*local.x + m[4]*local.y + m[7],
447 w = m[2]*local.x + m[5]*local.y + m[8];
448 x = x * (1.0f / w);
449 y = y * (1.0f / w);
450
451 if (!sample(ix, {x,y})) {
452 return {};
453 }
454 } break;
455
456 case Inst::kSampleExplicit: {
457 // Child shader to run.
458 int ix = u8();
459
460 // Stack contains x,y to sample at.
461 skvm::F32 y = pop(),
462 x = pop();
463
464 if (!sample(ix, {x,y})) {
465 return {};
466 }
467 } break;
468
469 case Inst::kLoad: {
470 int N = u8(),
471 ix = u8();
472 for (int i = 0; i < N; ++i) {
473 push(stack[ix + i]);
474 }
475 } break;
476
477 case Inst::kLoadUniform: {
478 int N = u8(),
479 ix = u8();
480 for (int i = 0; i < N; ++i) {
481 push(uniform[ix + i]);
482 }
483 } break;
484
485 case Inst::kLoadFragCoord: {
486 // TODO: Actually supply Z and 1/W from the rasterizer?
487 push(device.x);
488 push(device.y);
489 push(p->splat(0.0f)); // Z
490 push(p->splat(1.0f)); // 1/W
491 } break;
492
493 case Inst::kStore: {
494 int N = u8(),
495 ix = u8();
496 for (int i = N; i --> 0; ) {
497 stack[ix + i] = pop();
498 }
499 } break;
500
501 case Inst::kPushImmediate: {
502 push(bit_cast(p->splat(u32())));
503 } break;
504
505 case Inst::kDup: {
506 int N = u8();
507 for (int i = 0; i < N; ++i) {
508 push(stack[stack.size() - N]);
509 }
510 } break;
511
512 case Inst::kSwizzle: {
513 skvm::F32 tmp[4];
514 for (int i = u8(); i --> 0;) {
515 tmp[i] = pop();
516 }
517 for (int i = u8(); i --> 0;) {
518 push(tmp[u8()]);
519 }
520 } break;
521
522 case Inst::kAddF: binary(std::plus<>{}); break;
523 case Inst::kSubtractF: binary(std::minus<>{}); break;
524 case Inst::kMultiplyF: binary(std::multiplies<>{}); break;
525 case Inst::kDivideF: binary(std::divides<>{}); break;
526 case Inst::kNegateF: unary(std::negate<>{}); break;
527
528 case Inst::kMinF:
529 binary([](skvm::F32 x, skvm::F32 y) { return skvm::min(x,y); });
530 break;
531
532 case Inst::kMaxF:
533 binary([](skvm::F32 x, skvm::F32 y) { return skvm::max(x,y); });
534 break;
535
536 case Inst::kPow:
537 binary([](skvm::F32 x, skvm::F32 y) { return skvm::approx_powf(x,y); });
538 break;
539
540 case Inst::kLerp:
541 ternary([](skvm::F32 x, skvm::F32 y, skvm::F32 t) { return skvm::lerp(x, y, t); });
542 break;
543
544 case Inst::kATan: unary(skvm::approx_atan); break;
545 case Inst::kCeil: unary(skvm::ceil); break;
546 case Inst::kFloor: unary(skvm::floor); break;
547 case Inst::kFract: unary(skvm::fract); break;
548 case Inst::kSqrt: unary(skvm::sqrt); break;
549 case Inst::kSin: unary(skvm::approx_sin); break;
550
551 case Inst::kMatrixMultiply: {
552 // Computes M = A*B (all stored column major)
553 int aCols = u8(),
554 aRows = u8(),
555 bCols = u8(),
556 bRows = aCols;
557 std::vector<skvm::F32> A(aCols*aRows),
558 B(bCols*bRows);
559 for (auto i = B.size(); i --> 0;) { B[i] = pop(); }
560 for (auto i = A.size(); i --> 0;) { A[i] = pop(); }
561
562 for (int c = 0; c < bCols; ++c)
563 for (int r = 0; r < aRows; ++r) {
564 skvm::F32 sum = p->splat(0.0f);
565 for (int j = 0; j < aCols; ++j) {
566 sum += A[j*aRows + r] * B[c*bRows + j];
567 }
568 push(sum);
569 }
570 } break;
571
572 // Baby steps... just leaving test conditions on the stack for now.
573 case Inst::kMaskPush: break;
574 case Inst::kMaskNegate: break;
575
576 case Inst::kCompareFLT:
577 binary([](skvm::F32 x, skvm::F32 y) { return bit_cast(x<y); });
578 break;
579
580 case Inst::kMaskBlend: {
581 std::vector<skvm::F32> if_true,
582 if_false;
583 int count = u8();
584 for (int i = 0; i < count; i++) { if_false.push_back(pop()); }
585 for (int i = 0; i < count; i++) { if_true .push_back(pop()); }
586
587 skvm::I32 cond = bit_cast(pop());
588 for (int i = count; i --> 0; ) {
589 push(select(cond, if_true[i], if_false[i]));
590 }
591 } break;
592
593 case Inst::kReturn: {
594 SkAssertResult(u8() == 0);
595 SkASSERT(ip == end);
596 } break;
597 }
598 }
599 for (int i = 0; i < fn.getLocalCount(); i++) {
600 pop();
601 }
602 SkASSERT(stack.size() == (size_t)fn.getParameterCount());
603 skvm::F32 a = pop(),
604 b = pop(),
605 g = pop(),
606 r = pop();
607 return { r, g, b, a };
608}
609
610static sk_sp<SkData> get_xformed_uniforms(const SkRuntimeEffect* effect,
611 sk_sp<SkData> baseUniforms,
612 const SkMatrixProvider* matrixProvider,
613 const SkColorSpace* dstCS) {
614 using Flags = SkRuntimeEffect::Uniform::Flags;
615 using Type = SkRuntimeEffect::Uniform::Type;
616 SkColorSpaceXformSteps steps(sk_srgb_singleton(), kUnpremul_SkAlphaType,
617 dstCS, kUnpremul_SkAlphaType);
618
619 sk_sp<SkData> uniforms = nullptr;
620 auto writableData = [&]() {
621 if (!uniforms) {
622 uniforms = SkData::MakeWithCopy(baseUniforms->data(), baseUniforms->size());
623 }
624 return uniforms->writable_data();
625 };
626
627 for (const auto& v : effect->uniforms()) {
628 if (v.fFlags & Flags::kMarker_Flag) {
629 SkASSERT(v.fType == Type::kFloat4x4);
630 // Color filters don't provide a matrix provider, but shouldn't be allowed to get here
631 SkASSERT(matrixProvider);
632 SkM44* localToMarker = SkTAddOffset<SkM44>(writableData(), v.fOffset);
633 if (!matrixProvider->getLocalToMarker(v.fMarker, localToMarker)) {
634 // We couldn't provide a matrix that was requested by the SkSL
635 return nullptr;
636 }
637 if (v.fFlags & Flags::kMarkerNormals_Flag) {
638 // Normals need to be transformed by the inverse-transpose of the upper-left
639 // 3x3 portion (scale + rotate) of the matrix.
640 localToMarker->setRow(3, {0, 0, 0, 1});
641 localToMarker->setCol(3, {0, 0, 0, 1});
642 if (!localToMarker->invert(localToMarker)) {
643 return nullptr;
644 }
645 *localToMarker = localToMarker->transpose();
646 }
647 } else if (v.fFlags & Flags::kSRGBUnpremul_Flag) {
648 SkASSERT(v.fType == Type::kFloat3 || v.fType == Type::kFloat4);
649 if (steps.flags.mask()) {
650 float* color = SkTAddOffset<float>(writableData(), v.fOffset);
651 if (v.fType == Type::kFloat4) {
652 // RGBA, easy case
653 for (int i = 0; i < v.fCount; ++i) {
654 steps.apply(color);
655 color += 4;
656 }
657 } else {
658 // RGB, need to pad out to include alpha. Technically, this isn't necessary,
659 // because steps shouldn't include unpremul or premul, and thus shouldn't
660 // read or write the fourth element. But let's be safe.
661 float rgba[4];
662 for (int i = 0; i < v.fCount; ++i) {
663 memcpy(rgba, color, 3 * sizeof(float));
664 rgba[3] = 1.0f;
665 steps.apply(rgba);
666 memcpy(color, rgba, 3 * sizeof(float));
667 color += 3;
668 }
669 }
670 }
671 }
672 }
673 return uniforms ? uniforms : baseUniforms;
674}
675
676class SkRuntimeColorFilter : public SkColorFilterBase {
677public:
678 SkRuntimeColorFilter(sk_sp<SkRuntimeEffect> effect,
679 sk_sp<SkData> uniforms,
680 sk_sp<SkColorFilter> children[],
681 size_t childCount)
682 : fEffect(std::move(effect))
683 , fUniforms(std::move(uniforms))
684 , fChildren(children, children + childCount) {}
685
686#if SK_SUPPORT_GPU
687 GrFPResult asFragmentProcessor(std::unique_ptr<GrFragmentProcessor> inputFP,
688 GrRecordingContext* context,
689 const GrColorInfo& colorInfo) const override {
690 sk_sp<SkData> uniforms =
691 get_xformed_uniforms(fEffect.get(), fUniforms, nullptr, colorInfo.colorSpace());
692 if (!uniforms) {
693 return GrFPFailure(nullptr);
694 }
695
696 auto fp = GrSkSLFP::Make(context, fEffect, "Runtime_Color_Filter", std::move(uniforms));
697 for (const auto& child : fChildren) {
698 std::unique_ptr<GrFragmentProcessor> childFP;
699 if (child) {
700 bool success;
701 std::tie(success, childFP) = as_CFB(child)->asFragmentProcessor(
702 /*inputFP=*/nullptr, context, colorInfo);
703 if (!success) {
704 return GrFPFailure(std::move(inputFP));
705 }
706 }
707 fp->addChild(std::move(childFP));
708 }
709
710 // Runtime effect scripts are written to take an input color, not a fragment processor.
711 // We need to pass the input to the runtime filter using Compose. This ensures that it will
712 // be invoked exactly once, and the result will be returned when null children are sampled,
713 // or as the (default) input color for non-null children.
714 return GrFPSuccess(GrFragmentProcessor::Compose(std::move(inputFP), std::move(fp)));
715 }
716#endif
717
718 const SkSL::ByteCode* byteCode() const {
719 SkAutoMutexExclusive ama(fByteCodeMutex);
720 if (!fByteCode) {
721 auto [byteCode, errorText] = fEffect->toByteCode();
722 if (!byteCode) {
723 SkDebugf("%s\n", errorText.c_str());
724 return nullptr;
725 }
726 fByteCode = std::move(byteCode);
727 }
728 return fByteCode.get();
729 }
730
731 bool onAppendStages(const SkStageRec& rec, bool shaderIsOpaque) const override {
732 return false;
733 }
734
735 skvm::Color onProgram(skvm::Builder* p, skvm::Color c,
736 SkColorSpace* dstCS,
737 skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const override {
738 const SkSL::ByteCode* bc = this->byteCode();
739 if (!bc) {
740 return {};
741 }
742
743 const SkSL::ByteCodeFunction* fn = bc->getFunction("main");
744 if (!fn) {
745 return {};
746 }
747
748 sk_sp<SkData> inputs = get_xformed_uniforms(fEffect.get(), fUniforms, nullptr, dstCS);
749 if (!inputs) {
750 return {};
751 }
752
753 std::vector<skvm::F32> uniform;
754 for (int i = 0; i < (int)fEffect->uniformSize() / 4; i++) {
755 float f;
756 memcpy(&f, (const char*)inputs->data() + 4*i, 4);
757 uniform.push_back(p->uniformF(uniforms->pushF(f)));
758 }
759
760 auto sampleChild = [&](int ix, skvm::Coord /*coord*/) {
761 if (fChildren[ix]) {
762 return as_CFB(fChildren[ix])->program(p, c, dstCS, uniforms, alloc);
763 } else {
764 return c;
765 }
766 };
767
768 // The color filter code might use sample-with-matrix (even though the matrix/coords are
769 // ignored by the child). There should be no way for the color filter to use device coords.
770 // Regardless, just to be extra-safe, we pass something valid (0, 0) as both coords, so
771 // the builder isn't trying to do math on invalid values.
772 skvm::Coord zeroCoord = { p->splat(0.0f), p->splat(0.0f) };
773 return program_fn(p, *fn, uniform, c, sampleChild,
774 /*device=*/zeroCoord, /*local=*/zeroCoord);
775 }
776
777 void flatten(SkWriteBuffer& buffer) const override {
778 buffer.writeString(fEffect->source().c_str());
779 if (fUniforms) {
780 buffer.writeDataAsByteArray(fUniforms.get());
781 } else {
782 buffer.writeByteArray(nullptr, 0);
783 }
784 buffer.write32(fChildren.size());
785 for (const auto& child : fChildren) {
786 buffer.writeFlattenable(child.get());
787 }
788 }
789
790 SK_FLATTENABLE_HOOKS(SkRuntimeColorFilter)
791
792private:
793 sk_sp<SkRuntimeEffect> fEffect;
794 sk_sp<SkData> fUniforms;
795 std::vector<sk_sp<SkColorFilter>> fChildren;
796
797 mutable SkMutex fByteCodeMutex;
798 mutable std::unique_ptr<SkSL::ByteCode> fByteCode;
799};
800
801sk_sp<SkFlattenable> SkRuntimeColorFilter::CreateProc(SkReadBuffer& buffer) {
802 SkString sksl;
803 buffer.readString(&sksl);
804 sk_sp<SkData> uniforms = buffer.readByteArrayAsData();
805
806 auto effect = std::get<0>(SkRuntimeEffect::Make(std::move(sksl)));
807 if (!buffer.validate(effect != nullptr)) {
808 return nullptr;
809 }
810
811 size_t childCount = buffer.read32();
812 if (!buffer.validate(childCount == effect->children().count())) {
813 return nullptr;
814 }
815
816 std::vector<sk_sp<SkColorFilter>> children(childCount);
817 for (size_t i = 0; i < children.size(); ++i) {
818 children[i] = buffer.readColorFilter();
819 }
820
821 return effect->makeColorFilter(std::move(uniforms), children.data(), children.size());
822}
823
824///////////////////////////////////////////////////////////////////////////////////////////////////
825
826class SkRTShader : public SkShaderBase {
827public:
828 SkRTShader(sk_sp<SkRuntimeEffect> effect, sk_sp<SkData> uniforms, const SkMatrix* localMatrix,
829 sk_sp<SkShader>* children, size_t childCount, bool isOpaque)
830 : SkShaderBase(localMatrix)
831 , fEffect(std::move(effect))
832 , fIsOpaque(isOpaque)
833 , fUniforms(std::move(uniforms))
834 , fChildren(children, children + childCount) {}
835
836 bool isOpaque() const override { return fIsOpaque; }
837
838#if SK_SUPPORT_GPU
839 std::unique_ptr<GrFragmentProcessor> asFragmentProcessor(const GrFPArgs& args) const override {
840 SkMatrix matrix;
841 if (!this->totalLocalMatrix(args.fPreLocalMatrix)->invert(&matrix)) {
842 return nullptr;
843 }
844
845 sk_sp<SkData> uniforms = get_xformed_uniforms(
846 fEffect.get(), fUniforms, &args.fMatrixProvider, args.fDstColorInfo->colorSpace());
847 if (!uniforms) {
848 return nullptr;
849 }
850
851 auto fp = GrSkSLFP::Make(args.fContext, fEffect, "runtime_shader", std::move(uniforms));
852 for (const auto& child : fChildren) {
853 auto childFP = child ? as_SB(child)->asFragmentProcessor(args) : nullptr;
854 fp->addChild(std::move(childFP));
855 }
856 std::unique_ptr<GrFragmentProcessor> result = std::move(fp);
857 result = GrMatrixEffect::Make(matrix, std::move(result));
858 if (GrColorTypeClampType(args.fDstColorInfo->colorType()) != GrClampType::kNone) {
859 return GrFragmentProcessor::ClampPremulOutput(std::move(result));
860 } else {
861 return result;
862 }
863 }
864#endif
865
866 const SkSL::ByteCode* byteCode() const {
867 SkAutoMutexExclusive ama(fByteCodeMutex);
868 if (!fByteCode) {
869 auto [byteCode, errorText] = fEffect->toByteCode();
870 if (!byteCode) {
871 SkDebugf("%s\n", errorText.c_str());
872 return nullptr;
873 }
874 fByteCode = std::move(byteCode);
875 }
876 return fByteCode.get();
877 }
878
879 bool onAppendStages(const SkStageRec& rec) const override {
880 return false;
881 }
882
883 skvm::Color onProgram(skvm::Builder* p,
884 skvm::Coord device, skvm::Coord local, skvm::Color paint,
885 const SkMatrixProvider& matrices, const SkMatrix* localM,
886 SkFilterQuality quality, const SkColorInfo& dst,
887 skvm::Uniforms* uniforms, SkArenaAlloc* alloc) const override {
888 const SkSL::ByteCode* bc = this->byteCode();
889 if (!bc) {
890 return {};
891 }
892
893 const SkSL::ByteCodeFunction* fn = bc->getFunction("main");
894 if (!fn) {
895 return {};
896 }
897
898 sk_sp<SkData> inputs =
899 get_xformed_uniforms(fEffect.get(), fUniforms, &matrices, dst.colorSpace());
900 if (!inputs) {
901 return {};
902 }
903
904 std::vector<skvm::F32> uniform;
905 for (int i = 0; i < (int)fEffect->uniformSize() / 4; i++) {
906 float f;
907 memcpy(&f, (const char*)inputs->data() + 4*i, 4);
908 uniform.push_back(p->uniformF(uniforms->pushF(f)));
909 }
910
911 SkMatrix inv;
912 if (!this->computeTotalInverse(matrices.localToDevice(), localM, &inv)) {
913 return {};
914 }
915 local = SkShaderBase::ApplyMatrix(p,inv,local,uniforms);
916
917 auto sampleChild = [&](int ix, skvm::Coord coord) {
918 if (fChildren[ix]) {
919 SkOverrideDeviceMatrixProvider mats{matrices, SkMatrix::I()};
920 return as_SB(fChildren[ix])->program(p, device, coord, paint,
921 mats, nullptr,
922 quality, dst,
923 uniforms, alloc);
924 } else {
925 return paint;
926 }
927 };
928
929 return program_fn(p, *fn, uniform, paint, sampleChild, device, local);
930 }
931
932 void flatten(SkWriteBuffer& buffer) const override {
933 uint32_t flags = 0;
934 if (fIsOpaque) {
935 flags |= kIsOpaque_Flag;
936 }
937 if (!this->getLocalMatrix().isIdentity()) {
938 flags |= kHasLocalMatrix_Flag;
939 }
940
941 buffer.writeString(fEffect->source().c_str());
942 if (fUniforms) {
943 buffer.writeDataAsByteArray(fUniforms.get());
944 } else {
945 buffer.writeByteArray(nullptr, 0);
946 }
947 buffer.write32(flags);
948 if (flags & kHasLocalMatrix_Flag) {
949 buffer.writeMatrix(this->getLocalMatrix());
950 }
951 buffer.write32(fChildren.size());
952 for (const auto& child : fChildren) {
953 buffer.writeFlattenable(child.get());
954 }
955 }
956
957 SkRuntimeEffect* asRuntimeEffect() const override { return fEffect.get(); }
958
959 SK_FLATTENABLE_HOOKS(SkRTShader)
960
961private:
962 enum Flags {
963 kIsOpaque_Flag = 1 << 0,
964 kHasLocalMatrix_Flag = 1 << 1,
965 };
966
967 sk_sp<SkRuntimeEffect> fEffect;
968 bool fIsOpaque;
969
970 sk_sp<SkData> fUniforms;
971 std::vector<sk_sp<SkShader>> fChildren;
972
973 mutable SkMutex fByteCodeMutex;
974 mutable std::unique_ptr<SkSL::ByteCode> fByteCode;
975};
976
977sk_sp<SkFlattenable> SkRTShader::CreateProc(SkReadBuffer& buffer) {
978 SkString sksl;
979 buffer.readString(&sksl);
980 sk_sp<SkData> uniforms = buffer.readByteArrayAsData();
981 uint32_t flags = buffer.read32();
982
983 bool isOpaque = SkToBool(flags & kIsOpaque_Flag);
984 SkMatrix localM, *localMPtr = nullptr;
985 if (flags & kHasLocalMatrix_Flag) {
986 buffer.readMatrix(&localM);
987 localMPtr = &localM;
988 }
989
990 auto effect = std::get<0>(SkRuntimeEffect::Make(std::move(sksl)));
991 if (!buffer.validate(effect != nullptr)) {
992 return nullptr;
993 }
994
995 size_t childCount = buffer.read32();
996 if (!buffer.validate(childCount == effect->children().count())) {
997 return nullptr;
998 }
999
1000 std::vector<sk_sp<SkShader>> children(childCount);
1001 for (size_t i = 0; i < children.size(); ++i) {
1002 children[i] = buffer.readShader();
1003 }
1004
1005 return effect->makeShader(std::move(uniforms), children.data(), children.size(), localMPtr,
1006 isOpaque);
1007}
1008
1009///////////////////////////////////////////////////////////////////////////////////////////////////
1010
1011sk_sp<SkShader> SkRuntimeEffect::makeShader(sk_sp<SkData> uniforms,
1012 sk_sp<SkShader> children[], size_t childCount,
1013 const SkMatrix* localMatrix, bool isOpaque) {
1014 if (!uniforms) {
1015 uniforms = SkData::MakeEmpty();
1016 }
1017 return uniforms->size() == this->uniformSize() && childCount == fChildren.size()
1018 ? sk_sp<SkShader>(new SkRTShader(sk_ref_sp(this), std::move(uniforms), localMatrix,
1019 children, childCount, isOpaque))
1020 : nullptr;
1021}
1022
1023sk_sp<SkColorFilter> SkRuntimeEffect::makeColorFilter(sk_sp<SkData> uniforms,
1024 sk_sp<SkColorFilter> children[],
1025 size_t childCount) {
1026 if (!fAllowColorFilter) {
1027 return nullptr;
1028 }
1029 if (!uniforms) {
1030 uniforms = SkData::MakeEmpty();
1031 }
1032 return uniforms->size() == this->uniformSize() && childCount == fChildren.size()
1033 ? sk_sp<SkColorFilter>(new SkRuntimeColorFilter(sk_ref_sp(this), std::move(uniforms),
1034 children, childCount))
1035 : nullptr;
1036}
1037
1038sk_sp<SkColorFilter> SkRuntimeEffect::makeColorFilter(sk_sp<SkData> uniforms) {
1039 return this->makeColorFilter(std::move(uniforms), nullptr, 0);
1040}
1041
1042///////////////////////////////////////////////////////////////////////////////////////////////////
1043
1044void SkRuntimeEffect::RegisterFlattenables() {
1045 SK_REGISTER_FLATTENABLE(SkRuntimeColorFilter);
1046 SK_REGISTER_FLATTENABLE(SkRTShader);
1047}
1048
1049SkRuntimeShaderBuilder::SkRuntimeShaderBuilder(sk_sp<SkRuntimeEffect> effect)
1050 : fEffect(std::move(effect))
1051 , fUniforms(SkData::MakeUninitialized(fEffect->uniformSize()))
1052 , fChildren(fEffect->children().count()) {}
1053
1054SkRuntimeShaderBuilder::~SkRuntimeShaderBuilder() = default;
1055
1056sk_sp<SkShader> SkRuntimeShaderBuilder::makeShader(const SkMatrix* localMatrix, bool isOpaque) {
1057 return fEffect->makeShader(fUniforms, fChildren.data(), fChildren.size(), localMatrix, isOpaque);
1058}
1059
1060SkRuntimeShaderBuilder::BuilderChild&
1061SkRuntimeShaderBuilder::BuilderChild::operator=(const sk_sp<SkShader>& val) {
1062 if (fIndex < 0) {
1063 SkDEBUGFAIL("Assigning to missing child");
1064 } else {
1065 fOwner->fChildren[fIndex] = val;
1066 }
1067 return *this;
1068}
1069