1 /*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "src/gpu/GrFragmentProcessor.h"
9
10 #include "src/core/SkRuntimeEffectPriv.h"
11 #include "src/gpu/GrPipeline.h"
12 #include "src/gpu/GrProcessorAnalysis.h"
13 #include "src/gpu/GrShaderCaps.h"
14 #include "src/gpu/effects/GrBlendFragmentProcessor.h"
15 #include "src/gpu/effects/GrSkSLFP.h"
16 #include "src/gpu/effects/GrTextureEffect.h"
17 #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
18 #include "src/gpu/glsl/GrGLSLProgramBuilder.h"
19 #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
20 #include "src/gpu/glsl/GrGLSLUniformHandler.h"
21
22 // Advanced Filter
checkAFRecursively() const23 bool GrFragmentProcessor::checkAFRecursively() const
24 {
25 if (isAFEnabled()) {
26 return true;
27 }
28
29 for (int i = 0; i < numChildProcessors(); ++i) {
30 const GrFragmentProcessor* fChildFp = childProcessor(i);
31 if (fChildFp != nullptr && fChildFp->checkAFRecursively()) {
32 return true;
33 }
34 }
35 return false;
36 }
37
isEqual(const GrFragmentProcessor& that) const38 bool GrFragmentProcessor::isEqual(const GrFragmentProcessor& that) const {
39 if (this->classID() != that.classID()) {
40 return false;
41 }
42 if (this->sampleUsage() != that.sampleUsage()) {
43 return false;
44 }
45 if (!this->onIsEqual(that)) {
46 return false;
47 }
48 if (this->numChildProcessors() != that.numChildProcessors()) {
49 return false;
50 }
51 for (int i = 0; i < this->numChildProcessors(); ++i) {
52 auto thisChild = this->childProcessor(i),
53 thatChild = that .childProcessor(i);
54 if (SkToBool(thisChild) != SkToBool(thatChild)) {
55 return false;
56 }
57 if (thisChild && !thisChild->isEqual(*thatChild)) {
58 return false;
59 }
60 }
61 return true;
62 }
63
visitProxies(const GrVisitProxyFunc& func) const64 void GrFragmentProcessor::visitProxies(const GrVisitProxyFunc& func) const {
65 this->visitTextureEffects([&func](const GrTextureEffect& te) {
66 func(te.view().proxy(), te.samplerState().mipmapped());
67 });
68 }
69
visitTextureEffects( const std::function<void(const GrTextureEffect&)>& func) const70 void GrFragmentProcessor::visitTextureEffects(
71 const std::function<void(const GrTextureEffect&)>& func) const {
72 if (auto* te = this->asTextureEffect()) {
73 func(*te);
74 }
75 for (auto& child : fChildProcessors) {
76 if (child) {
77 child->visitTextureEffects(func);
78 }
79 }
80 }
81
visitWithImpls( const std::function<void(const GrFragmentProcessor&, ProgramImpl&)>& f, ProgramImpl& impl) const82 void GrFragmentProcessor::visitWithImpls(
83 const std::function<void(const GrFragmentProcessor&, ProgramImpl&)>& f,
84 ProgramImpl& impl) const {
85 f(*this, impl);
86 SkASSERT(impl.numChildProcessors() == this->numChildProcessors());
87 for (int i = 0; i < this->numChildProcessors(); ++i) {
88 if (const auto* child = this->childProcessor(i)) {
89 child->visitWithImpls(f, *impl.childProcessor(i));
90 }
91 }
92 }
93
asTextureEffect()94 GrTextureEffect* GrFragmentProcessor::asTextureEffect() {
95 if (this->classID() == kGrTextureEffect_ClassID) {
96 return static_cast<GrTextureEffect*>(this);
97 }
98 return nullptr;
99 }
100
asTextureEffect() const101 const GrTextureEffect* GrFragmentProcessor::asTextureEffect() const {
102 if (this->classID() == kGrTextureEffect_ClassID) {
103 return static_cast<const GrTextureEffect*>(this);
104 }
105 return nullptr;
106 }
107
108 #if GR_TEST_UTILS
recursive_dump_tree_info(const GrFragmentProcessor& fp, SkString indent, SkString* text)109 static void recursive_dump_tree_info(const GrFragmentProcessor& fp,
110 SkString indent,
111 SkString* text) {
112 for (int index = 0; index < fp.numChildProcessors(); ++index) {
113 text->appendf("\n%s(#%d) -> ", indent.c_str(), index);
114 if (const GrFragmentProcessor* childFP = fp.childProcessor(index)) {
115 text->append(childFP->dumpInfo());
116 indent.append("\t");
117 recursive_dump_tree_info(*childFP, indent, text);
118 } else {
119 text->append("null");
120 }
121 }
122 }
123
dumpTreeInfo() const124 SkString GrFragmentProcessor::dumpTreeInfo() const {
125 SkString text = this->dumpInfo();
126 recursive_dump_tree_info(*this, SkString("\t"), &text);
127 text.append("\n");
128 return text;
129 }
130 #endif
131
makeProgramImpl() const132 std::unique_ptr<GrFragmentProcessor::ProgramImpl> GrFragmentProcessor::makeProgramImpl() const {
133 std::unique_ptr<ProgramImpl> impl = this->onMakeProgramImpl();
134 impl->fChildProcessors.push_back_n(fChildProcessors.count());
135 for (int i = 0; i < fChildProcessors.count(); ++i) {
136 impl->fChildProcessors[i] = fChildProcessors[i] ? fChildProcessors[i]->makeProgramImpl()
137 : nullptr;
138 }
139 return impl;
140 }
141
numNonNullChildProcessors() const142 int GrFragmentProcessor::numNonNullChildProcessors() const {
143 return std::count_if(fChildProcessors.begin(), fChildProcessors.end(),
144 [](const auto& c) { return c != nullptr; });
145 }
146
147 #ifdef SK_DEBUG
148 bool GrFragmentProcessor::isInstantiated() const {
149 bool result = true;
150 this->visitTextureEffects([&result](const GrTextureEffect& te) {
151 if (!te.texture()) {
152 result = false;
153 }
154 });
155 return result;
156 }
157 #endif
158
159 void GrFragmentProcessor::registerChild(std::unique_ptr<GrFragmentProcessor> child,
160 SkSL::SampleUsage sampleUsage) {
161 SkASSERT(sampleUsage.isSampled());
162
163 if (!child) {
164 fChildProcessors.push_back(nullptr);
165 return;
166 }
167
168 // The child should not have been attached to another FP already and not had any sampling
169 // strategy set on it.
170 SkASSERT(!child->fParent && !child->sampleUsage().isSampled());
171
172 // Configure child's sampling state first
173 child->fUsage = sampleUsage;
174
175 // Propagate the "will read dest-color" flag up to parent FPs.
176 if (child->willReadDstColor()) {
177 this->setWillReadDstColor();
178 }
179
180 // If this child receives passthrough or matrix transformed coords from its parent then note
181 // that the parent's coords are used indirectly to ensure that they aren't omitted.
182 if ((sampleUsage.isPassThrough() || sampleUsage.isUniformMatrix()) &&
183 child->usesSampleCoords()) {
184 fFlags |= kUsesSampleCoordsIndirectly_Flag;
185 }
186
187 // Record that the child is attached to us; this FP is the source of any uniform data needed
188 // to evaluate the child sample matrix.
189 child->fParent = this;
190 fChildProcessors.push_back(std::move(child));
191
192 // Validate: our sample strategy comes from a parent we shouldn't have yet.
193 SkASSERT(!fUsage.isSampled() && !fParent);
194 }
195
196 void GrFragmentProcessor::cloneAndRegisterAllChildProcessors(const GrFragmentProcessor& src) {
197 for (int i = 0; i < src.numChildProcessors(); ++i) {
198 if (auto fp = src.childProcessor(i)) {
199 this->registerChild(fp->clone(), fp->sampleUsage());
200 } else {
201 this->registerChild(nullptr);
202 }
203 }
204 }
205
206 std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::MakeColor(SkPMColor4f color) {
207 // Use ColorFilter signature/factory to get the constant output for constant input optimization
208 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
209 uniform half4 color;
210 half4 main(half4 inColor) { return color; }
211 )");
212 SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
213 return GrSkSLFP::Make(effect, "color_fp", /*inputFP=*/nullptr,
214 color.isOpaque() ? GrSkSLFP::OptFlags::kPreservesOpaqueInput
215 : GrSkSLFP::OptFlags::kNone,
216 "color", color);
217 }
218
219 std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::MulInputByChildAlpha(
220 std::unique_ptr<GrFragmentProcessor> fp) {
221 if (!fp) {
222 return nullptr;
223 }
224 return GrBlendFragmentProcessor::Make(/*src=*/nullptr, std::move(fp), SkBlendMode::kSrcIn);
225 }
226
227 std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::ApplyPaintAlpha(
228 std::unique_ptr<GrFragmentProcessor> child) {
229 SkASSERT(child);
230 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
231 uniform colorFilter fp;
232 half4 main(half4 inColor) {
233 return fp.eval(inColor.rgb1) * inColor.a;
234 }
235 )");
236 return GrSkSLFP::Make(effect, "ApplyPaintAlpha", /*inputFP=*/nullptr,
237 GrSkSLFP::OptFlags::kPreservesOpaqueInput |
238 GrSkSLFP::OptFlags::kCompatibleWithCoverageAsAlpha,
239 "fp", std::move(child));
240 }
241
242 std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::ModulateRGBA(
243 std::unique_ptr<GrFragmentProcessor> inputFP, const SkPMColor4f& color) {
244 auto colorFP = MakeColor(color);
245 return GrBlendFragmentProcessor::Make(std::move(colorFP),
246 std::move(inputFP),
247 SkBlendMode::kModulate);
248 }
249
250 std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::ClampOutput(
251 std::unique_ptr<GrFragmentProcessor> fp) {
252 SkASSERT(fp);
253 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
254 half4 main(half4 inColor) {
255 return saturate(inColor);
256 }
257 )");
258 SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
259 return GrSkSLFP::Make(
260 effect, "Clamp", std::move(fp), GrSkSLFP::OptFlags::kPreservesOpaqueInput);
261 }
262
263 std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::SwizzleOutput(
264 std::unique_ptr<GrFragmentProcessor> fp, const GrSwizzle& swizzle) {
265 class SwizzleFragmentProcessor : public GrFragmentProcessor {
266 public:
267 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp,
268 const GrSwizzle& swizzle) {
269 return std::unique_ptr<GrFragmentProcessor>(
270 new SwizzleFragmentProcessor(std::move(fp), swizzle));
271 }
272
273 const char* name() const override { return "Swizzle"; }
274
275 SkString getShaderDfxInfo() const override {
276 SkString format;
277 format.printf("ShaderDfx_SwizzleOutput_%d", fSwizzle.asKey());
278 return format;
279 }
280
281 std::unique_ptr<GrFragmentProcessor> clone() const override {
282 return Make(this->childProcessor(0)->clone(), fSwizzle);
283 }
284
285 private:
286 SwizzleFragmentProcessor(std::unique_ptr<GrFragmentProcessor> fp, const GrSwizzle& swizzle)
287 : INHERITED(kSwizzleFragmentProcessor_ClassID, ProcessorOptimizationFlags(fp.get()))
288 , fSwizzle(swizzle) {
289 this->registerChild(std::move(fp));
290 }
291
292 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
293 class Impl : public ProgramImpl {
294 public:
295 void emitCode(EmitArgs& args) override {
296 SkString childColor = this->invokeChild(0, args);
297
298 const SwizzleFragmentProcessor& sfp = args.fFp.cast<SwizzleFragmentProcessor>();
299 const GrSwizzle& swizzle = sfp.fSwizzle;
300 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
301
302 fragBuilder->codeAppendf("return %s.%s;",
303 childColor.c_str(), swizzle.asString().c_str());
304 }
305 };
306 return std::make_unique<Impl>();
307 }
308
309 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
310 b->add32(fSwizzle.asKey());
311 }
312
313 bool onIsEqual(const GrFragmentProcessor& other) const override {
314 const SwizzleFragmentProcessor& sfp = other.cast<SwizzleFragmentProcessor>();
315 return fSwizzle == sfp.fSwizzle;
316 }
317
318 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
319 return fSwizzle.applyTo(ConstantOutputForConstantInput(this->childProcessor(0), input));
320 }
321
322 GrSwizzle fSwizzle;
323
324 using INHERITED = GrFragmentProcessor;
325 };
326
327 if (!fp) {
328 return nullptr;
329 }
330 if (GrSwizzle::RGBA() == swizzle) {
331 return fp;
332 }
333 return SwizzleFragmentProcessor::Make(std::move(fp), swizzle);
334 }
335
336 //////////////////////////////////////////////////////////////////////////////
337
338 std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::OverrideInput(
339 std::unique_ptr<GrFragmentProcessor> fp, const SkPMColor4f& color) {
340 if (!fp) {
341 return nullptr;
342 }
343 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
344 uniform colorFilter fp; // Declared as colorFilter so we can pass a color
345 uniform half4 color;
346 half4 main(half4 inColor) {
347 return fp.eval(color);
348 }
349 )");
350 SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
351 return GrSkSLFP::Make(effect, "OverrideInput", /*inputFP=*/nullptr,
352 color.isOpaque() ? GrSkSLFP::OptFlags::kPreservesOpaqueInput
353 : GrSkSLFP::OptFlags::kNone,
354 "fp", std::move(fp),
355 "color", color);
356 }
357
358 //////////////////////////////////////////////////////////////////////////////
359
360 std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::DisableCoverageAsAlpha(
361 std::unique_ptr<GrFragmentProcessor> fp) {
362 if (!fp || !fp->compatibleWithCoverageAsAlpha()) {
363 return fp;
364 }
365 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
366 half4 main(half4 inColor) { return inColor; }
367 )");
368 SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
369 return GrSkSLFP::Make(effect, "DisableCoverageAsAlpha", std::move(fp),
370 GrSkSLFP::OptFlags::kPreservesOpaqueInput);
371 }
372
373 //////////////////////////////////////////////////////////////////////////////
374
375 std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::UseDestColorAsInput(
376 std::unique_ptr<GrFragmentProcessor> fp) {
377 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForBlender, R"(
378 uniform colorFilter fp; // Declared as colorFilter so we can pass a color
379 half4 main(half4 src, half4 dst) {
380 return fp.eval(dst);
381 }
382 )");
383 return GrSkSLFP::Make(effect, "UseDestColorAsInput", /*inputFP=*/nullptr,
384 GrSkSLFP::OptFlags::kNone, "fp", std::move(fp));
385 }
386
387 //////////////////////////////////////////////////////////////////////////////
388
389 std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::Compose(
390 std::unique_ptr<GrFragmentProcessor> f, std::unique_ptr<GrFragmentProcessor> g) {
391 class ComposeProcessor : public GrFragmentProcessor {
392 public:
393 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> f,
394 std::unique_ptr<GrFragmentProcessor> g) {
395 return std::unique_ptr<GrFragmentProcessor>(new ComposeProcessor(std::move(f),
396 std::move(g)));
397 }
398
399 const char* name() const override { return "Compose"; }
400
401 SkString getShaderDfxInfo() const override { return SkString("ShaderDfx_ComposeProcessor"); }
402
403 std::unique_ptr<GrFragmentProcessor> clone() const override {
404 return std::unique_ptr<GrFragmentProcessor>(new ComposeProcessor(*this));
405 }
406
407 private:
408 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
409 class Impl : public ProgramImpl {
410 public:
411 void emitCode(EmitArgs& args) override {
412 SkString result = this->invokeChild(1, args); // g(x)
413 result = this->invokeChild(0, result.c_str(), args); // f(g(x))
414 args.fFragBuilder->codeAppendf("return %s;", result.c_str());
415 }
416 };
417 return std::make_unique<Impl>();
418 }
419
420 ComposeProcessor(std::unique_ptr<GrFragmentProcessor> f,
421 std::unique_ptr<GrFragmentProcessor> g)
422 : INHERITED(kSeriesFragmentProcessor_ClassID,
423 f->optimizationFlags() & g->optimizationFlags()) {
424 this->registerChild(std::move(f));
425 this->registerChild(std::move(g));
426 }
427
428 ComposeProcessor(const ComposeProcessor& that) : INHERITED(that) {}
429
430 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
431
432 bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
433
434 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override {
435 SkPMColor4f color = inColor;
436 color = ConstantOutputForConstantInput(this->childProcessor(1), color);
437 color = ConstantOutputForConstantInput(this->childProcessor(0), color);
438 return color;
439 }
440
441 using INHERITED = GrFragmentProcessor;
442 };
443
444 // Allow either of the composed functions to be null.
445 if (f == nullptr) {
446 return g;
447 }
448 if (g == nullptr) {
449 return f;
450 }
451
452 // Run an optimization pass on this composition.
453 GrProcessorAnalysisColor inputColor;
454 inputColor.setToUnknown();
455
456 std::unique_ptr<GrFragmentProcessor> series[2] = {std::move(g), std::move(f)};
457 GrColorFragmentProcessorAnalysis info(inputColor, series, SK_ARRAY_COUNT(series));
458
459 SkPMColor4f knownColor;
460 int leadingFPsToEliminate = info.initialProcessorsToEliminate(&knownColor);
461 switch (leadingFPsToEliminate) {
462 default:
463 // We shouldn't eliminate more than we started with.
464 SkASSERT(leadingFPsToEliminate <= 2);
465 [[fallthrough]];
466 case 0:
467 // Compose the two processors as requested.
468 return ComposeProcessor::Make(/*f=*/std::move(series[1]), /*g=*/std::move(series[0]));
469 case 1:
470 // Replace the first processor with a constant color.
471 return ComposeProcessor::Make(/*f=*/std::move(series[1]),
472 /*g=*/MakeColor(knownColor));
473 case 2:
474 // Replace the entire composition with a constant color.
475 return MakeColor(knownColor);
476 }
477 }
478
479 //////////////////////////////////////////////////////////////////////////////
480
481 std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::ColorMatrix(
482 std::unique_ptr<GrFragmentProcessor> child,
483 const float matrix[20],
484 bool unpremulInput,
485 bool clampRGBOutput,
486 bool premulOutput) {
487 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
488 uniform half4x4 m;
489 uniform half4 v;
490 uniform int unpremulInput; // always specialized
491 uniform int clampRGBOutput; // always specialized
492 uniform int premulOutput; // always specialized
493 half4 main(half4 color) {
494 if (bool(unpremulInput)) {
495 color = unpremul(color);
496 }
497 color = m * color + v;
498 if (bool(clampRGBOutput)) {
499 color = saturate(color);
500 } else {
501 color.a = saturate(color.a);
502 }
503 if (bool(premulOutput)) {
504 color.rgb *= color.a;
505 }
506 return color;
507 }
508 )");
509 SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
510
511 SkM44 m44(matrix[ 0], matrix[ 1], matrix[ 2], matrix[ 3],
512 matrix[ 5], matrix[ 6], matrix[ 7], matrix[ 8],
513 matrix[10], matrix[11], matrix[12], matrix[13],
514 matrix[15], matrix[16], matrix[17], matrix[18]);
515 SkV4 v4 = {matrix[4], matrix[9], matrix[14], matrix[19]};
516 return GrSkSLFP::Make(effect, "ColorMatrix", std::move(child), GrSkSLFP::OptFlags::kNone,
517 "m", m44,
518 "v", v4,
519 "unpremulInput", GrSkSLFP::Specialize(unpremulInput ? 1 : 0),
520 "clampRGBOutput", GrSkSLFP::Specialize(clampRGBOutput ? 1 : 0),
521 "premulOutput", GrSkSLFP::Specialize(premulOutput ? 1 : 0));
522 }
523
524 //////////////////////////////////////////////////////////////////////////////
525
526 std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::SurfaceColor() {
527 class SurfaceColorProcessor : public GrFragmentProcessor {
528 public:
529 static std::unique_ptr<GrFragmentProcessor> Make() {
530 return std::unique_ptr<GrFragmentProcessor>(new SurfaceColorProcessor());
531 }
532
533 std::unique_ptr<GrFragmentProcessor> clone() const override { return Make(); }
534
535 const char* name() const override { return "SurfaceColor"; }
536
537 SkString getShaderDfxInfo() const override { return SkString("ShaderDfx_SurfaceColorProcessor"); }
538
539 private:
540 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
541 class Impl : public ProgramImpl {
542 public:
543 void emitCode(EmitArgs& args) override {
544 const char* dstColor = args.fFragBuilder->dstColor();
545 args.fFragBuilder->codeAppendf("return %s;", dstColor);
546 }
547 };
548 return std::make_unique<Impl>();
549 }
550
551 SurfaceColorProcessor()
552 : INHERITED(kSurfaceColorProcessor_ClassID, kNone_OptimizationFlags) {
553 this->setWillReadDstColor();
554 }
555
556 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
557
558 bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
559
560 using INHERITED = GrFragmentProcessor;
561 };
562
563 return SurfaceColorProcessor::Make();
564 }
565
566 //////////////////////////////////////////////////////////////////////////////
567
568 std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::DeviceSpace(
569 std::unique_ptr<GrFragmentProcessor> fp) {
570 if (!fp) {
571 return nullptr;
572 }
573
574 class DeviceSpace : GrFragmentProcessor {
575 public:
576 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp) {
577 return std::unique_ptr<GrFragmentProcessor>(new DeviceSpace(std::move(fp)));
578 }
579
580 SkString getShaderDfxInfo() const override { return SkString("ShaderDfx_DeviceSpace"); }
581
582 private:
583 DeviceSpace(std::unique_ptr<GrFragmentProcessor> fp)
584 : GrFragmentProcessor(kDeviceSpace_ClassID, fp->optimizationFlags()) {
585 // Passing FragCoord here is the reason this is a subclass and not a runtime-FP.
586 this->registerChild(std::move(fp), SkSL::SampleUsage::FragCoord());
587 }
588
589 std::unique_ptr<GrFragmentProcessor> clone() const override {
590 auto child = this->childProcessor(0)->clone();
591 return std::unique_ptr<GrFragmentProcessor>(new DeviceSpace(std::move(child)));
592 }
593
594 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& f) const override {
595 return this->childProcessor(0)->constantOutputForConstantInput(f);
596 }
597
598 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
599 class Impl : public ProgramImpl {
600 public:
601 Impl() = default;
602 void emitCode(ProgramImpl::EmitArgs& args) override {
603 auto child = this->invokeChild(0, args.fInputColor, args, "sk_FragCoord.xy");
604 args.fFragBuilder->codeAppendf("return %s;", child.c_str());
605 }
606 };
607 return std::make_unique<Impl>();
608 }
609
610 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
611
612 bool onIsEqual(const GrFragmentProcessor& processor) const override { return true; }
613
614 const char* name() const override { return "DeviceSpace"; }
615 };
616
617 return DeviceSpace::Make(std::move(fp));
618 }
619
620 //////////////////////////////////////////////////////////////////////////////
621
622 #define CLIP_EDGE_SKSL \
623 "const int kFillBW = 0;" \
624 "const int kFillAA = 1;" \
625 "const int kInverseFillBW = 2;" \
626 "const int kInverseFillAA = 3;"
627
628 static_assert(static_cast<int>(GrClipEdgeType::kFillBW) == 0);
629 static_assert(static_cast<int>(GrClipEdgeType::kFillAA) == 1);
630 static_assert(static_cast<int>(GrClipEdgeType::kInverseFillBW) == 2);
631 static_assert(static_cast<int>(GrClipEdgeType::kInverseFillAA) == 3);
632
633 std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::Rect(
634 std::unique_ptr<GrFragmentProcessor> inputFP, GrClipEdgeType edgeType, SkRect rect) {
635 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, CLIP_EDGE_SKSL R"(
636 uniform int edgeType; // GrClipEdgeType, specialized
637 uniform float4 rectUniform;
638
639 half4 main(float2 xy, half4 inColor) {
640 half coverage;
641 if (edgeType == kFillBW || edgeType == kInverseFillBW) {
642 // non-AA
643 coverage = all(greaterThan(float4(sk_FragCoord.xy, rectUniform.zw),
644 float4(rectUniform.xy, sk_FragCoord.xy))) ? 1 : 0;
645 } else {
646 // compute coverage relative to left and right edges, add, then subtract 1 to
647 // account for double counting. And similar for top/bottom.
648 half4 dists4 = clamp(half4(1, 1, -1, -1) *
649 half4(sk_FragCoord.xyxy - rectUniform), 0, 1);
650 half2 dists2 = dists4.xy + dists4.zw - 1;
651 coverage = dists2.x * dists2.y;
652 }
653
654 if (edgeType == kInverseFillBW || edgeType == kInverseFillAA) {
655 coverage = 1.0 - coverage;
656 }
657
658 return inColor * coverage;
659 }
660 )");
661
662 SkASSERT(rect.isSorted());
663 // The AA math in the shader evaluates to 0 at the uploaded coordinates, so outset by 0.5
664 // to interpolate from 0 at a half pixel inset and 1 at a half pixel outset of rect.
665 SkRect rectUniform = GrClipEdgeTypeIsAA(edgeType) ? rect.makeOutset(.5f, .5f) : rect;
666
667 return GrSkSLFP::Make(effect, "Rect", std::move(inputFP),
668 GrSkSLFP::OptFlags::kCompatibleWithCoverageAsAlpha,
669 "edgeType", GrSkSLFP::Specialize(static_cast<int>(edgeType)),
670 "rectUniform", rectUniform);
671 }
672
673 GrFPResult GrFragmentProcessor::Circle(std::unique_ptr<GrFragmentProcessor> inputFP,
674 GrClipEdgeType edgeType,
675 SkPoint center,
676 float radius) {
677 // A radius below half causes the implicit insetting done by this processor to become
678 // inverted. We could handle this case by making the processor code more complicated.
679 if (radius < .5f && GrClipEdgeTypeIsInverseFill(edgeType)) {
680 return GrFPFailure(std::move(inputFP));
681 }
682
683 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, CLIP_EDGE_SKSL R"(
684 uniform int edgeType; // GrClipEdgeType, specialized
685 // The circle uniform is (center.x, center.y, radius + 0.5, 1 / (radius + 0.5)) for regular
686 // fills and (..., radius - 0.5, 1 / (radius - 0.5)) for inverse fills.
687 uniform float4 circle;
688
689 half4 main(float2 xy, half4 inColor) {
690 // TODO: Right now the distance to circle calculation is performed in a space normalized
691 // to the radius and then denormalized. This is to mitigate overflow on devices that
692 // don't have full float.
693 half d;
694 if (edgeType == kInverseFillBW || edgeType == kInverseFillAA) {
695 d = half((length((circle.xy - sk_FragCoord.xy) * circle.w) - 1.0) * circle.z);
696 } else {
697 d = half((1.0 - length((circle.xy - sk_FragCoord.xy) * circle.w)) * circle.z);
698 }
699 if (edgeType == kFillAA || edgeType == kInverseFillAA) {
700 return inColor * saturate(d);
701 } else {
702 return d > 0.5 ? inColor : half4(0);
703 }
704 }
705 )");
706
707 SkScalar effectiveRadius = radius;
708 if (GrClipEdgeTypeIsInverseFill(edgeType)) {
709 effectiveRadius -= 0.5f;
710 // When the radius is 0.5 effectiveRadius is 0 which causes an inf * 0 in the shader.
711 effectiveRadius = std::max(0.001f, effectiveRadius);
712 } else {
713 effectiveRadius += 0.5f;
714 }
715 SkV4 circle = {center.fX, center.fY, effectiveRadius, SkScalarInvert(effectiveRadius)};
716
717 return GrFPSuccess(GrSkSLFP::Make(effect, "Circle", std::move(inputFP),
718 GrSkSLFP::OptFlags::kCompatibleWithCoverageAsAlpha,
719 "edgeType", GrSkSLFP::Specialize(static_cast<int>(edgeType)),
720 "circle", circle));
721 }
722
723 #ifdef SKIA_OHOS
724 GrFPResult GrFragmentProcessor::CircleSDF(std::unique_ptr<GrFragmentProcessor> inputFP,
725 GrClipEdgeType edgeType, SkPoint center, float radius)
726 {
727 if (radius < .5f && GrClipEdgeTypeIsInverseFill(edgeType)) {
728 return GrFPFailure(std::move(inputFP));
729 }
730
731 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, CLIP_EDGE_SKSL R"(
732 uniform int edgeType;
733 uniform float4 circle;
734
735 half4 main(float2 xy, half4 inColor) {
736 float2 localXY = (sk_FragCoord.xy - circle.xy) / (circle.z - 0.5);
737 float dfLocalD_recip = (circle.z - 0.5) / (2.0 * (abs(localXY.x) + abs(localXY.y)));
738 half d = 0;
739 if (edgeType == kInverseFillBW || edgeType == kInverseFillAA) {
740 d = (dot(localXY, localXY) - 1.0) * dfLocalD_recip - 0.5;
741 } else {
742 d = 0.5 - (dot(localXY, localXY) - 1.0) * dfLocalD_recip;
743 }
744 if (edgeType == kFillAA || edgeType == kInverseFillAA) {
745 return saturate(d) * inColor;
746 } else {
747 return d > 0.5 ? inColor : half4(0);
748 }
749 }
750 )");
751 // Avoid inf * 0 in the shader.
752 SkScalar effectiveRadius = radius;
753 if (GrClipEdgeTypeIsInverseFill(edgeType)) {
754 effectiveRadius -= 0.5f;
755 effectiveRadius = std::max(0.001f, effectiveRadius);
756 } else {
757 effectiveRadius += 0.5f;
758 }
759 SkV4 circle = {center.fX, center.fY, effectiveRadius, SkScalarInvert(effectiveRadius)};
760
761 return GrFPSuccess(GrSkSLFP::Make(effect, "CircleSDF", std::move(inputFP),
762 GrSkSLFP::OptFlags::kCompatibleWithCoverageAsAlpha,
763 "edgeType", GrSkSLFP::Specialize(static_cast<int>(edgeType)),
764 "circle", circle));
765 }
766 #endif
767
768 GrFPResult GrFragmentProcessor::Ellipse(std::unique_ptr<GrFragmentProcessor> inputFP,
769 GrClipEdgeType edgeType,
770 SkPoint center,
771 SkPoint radii,
772 const GrShaderCaps& caps) {
773 const bool medPrecision = !caps.floatIs32Bits();
774
775 // Small radii produce bad results on devices without full float.
776 if (medPrecision && (radii.fX < 0.5f || radii.fY < 0.5f)) {
777 return GrFPFailure(std::move(inputFP));
778 }
779 // Very narrow ellipses produce bad results on devices without full float
780 if (medPrecision && (radii.fX > 255*radii.fY || radii.fY > 255*radii.fX)) {
781 return GrFPFailure(std::move(inputFP));
782 }
783 // Very large ellipses produce bad results on devices without full float
784 if (medPrecision && (radii.fX > 16384 || radii.fY > 16384)) {
785 return GrFPFailure(std::move(inputFP));
786 }
787
788 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, CLIP_EDGE_SKSL R"(
789 uniform int edgeType; // GrClipEdgeType, specialized
790 uniform int medPrecision; // !sk_Caps.floatIs32Bits, specialized
791
792 uniform float4 ellipse;
793 uniform float2 scale; // only for medPrecision
794
795 half4 main(float2 xy, half4 inColor) {
796 // d is the offset to the ellipse center
797 float2 d = sk_FragCoord.xy - ellipse.xy;
798 // If we're on a device with a "real" mediump then we'll do the distance computation in
799 // a space that is normalized by the larger radius or 128, whichever is smaller. The
800 // scale uniform will be scale, 1/scale. The inverse squared radii uniform values are
801 // already in this normalized space. The center is not.
802 if (bool(medPrecision)) {
803 d *= scale.y;
804 }
805 float2 Z = d * ellipse.zw;
806 // implicit is the evaluation of (x/rx)^2 + (y/ry)^2 - 1.
807 float implicit = dot(Z, d) - 1;
808 // grad_dot is the squared length of the gradient of the implicit.
809 float grad_dot = 4 * dot(Z, Z);
810 // Avoid calling inversesqrt on zero.
811 if (bool(medPrecision)) {
812 grad_dot = max(grad_dot, 6.1036e-5);
813 } else {
814 grad_dot = max(grad_dot, 1.1755e-38);
815 }
816 float approx_dist = implicit * inversesqrt(grad_dot);
817 if (bool(medPrecision)) {
818 approx_dist *= scale.x;
819 }
820
821 half alpha;
822 if (edgeType == kFillBW) {
823 alpha = approx_dist > 0.0 ? 0.0 : 1.0;
824 } else if (edgeType == kFillAA) {
825 alpha = saturate(0.5 - half(approx_dist));
826 } else if (edgeType == kInverseFillBW) {
827 alpha = approx_dist > 0.0 ? 1.0 : 0.0;
828 } else { // edgeType == kInverseFillAA
829 alpha = saturate(0.5 + half(approx_dist));
830 }
831 return inColor * alpha;
832 }
833 )");
834
835 float invRXSqd;
836 float invRYSqd;
837 SkV2 scale = {1, 1};
838 // If we're using a scale factor to work around precision issues, choose the larger radius as
839 // the scale factor. The inv radii need to be pre-adjusted by the scale factor.
840 if (medPrecision) {
841 if (radii.fX > radii.fY) {
842 invRXSqd = 1.f;
843 invRYSqd = (radii.fX * radii.fX) / (radii.fY * radii.fY);
844 scale = {radii.fX, 1.f / radii.fX};
845 } else {
846 invRXSqd = (radii.fY * radii.fY) / (radii.fX * radii.fX);
847 invRYSqd = 1.f;
848 scale = {radii.fY, 1.f / radii.fY};
849 }
850 } else {
851 invRXSqd = 1.f / (radii.fX * radii.fX);
852 invRYSqd = 1.f / (radii.fY * radii.fY);
853 }
854 SkV4 ellipse = {center.fX, center.fY, invRXSqd, invRYSqd};
855
856 return GrFPSuccess(GrSkSLFP::Make(effect, "Ellipse", std::move(inputFP),
857 GrSkSLFP::OptFlags::kCompatibleWithCoverageAsAlpha,
858 "edgeType", GrSkSLFP::Specialize(static_cast<int>(edgeType)),
859 "medPrecision", GrSkSLFP::Specialize<int>(medPrecision),
860 "ellipse", ellipse,
861 "scale", scale));
862 }
863
864 //////////////////////////////////////////////////////////////////////////////
865
866 std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::HighPrecision(
867 std::unique_ptr<GrFragmentProcessor> fp) {
868 class HighPrecisionFragmentProcessor : public GrFragmentProcessor {
869 public:
870 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp) {
871 return std::unique_ptr<GrFragmentProcessor>(
872 new HighPrecisionFragmentProcessor(std::move(fp)));
873 }
874
875 const char* name() const override { return "HighPrecision"; }
876
877 SkString getShaderDfxInfo() const override { return SkString("ShaderDfx_HighPrecision"); }
878
879 std::unique_ptr<GrFragmentProcessor> clone() const override {
880 return Make(this->childProcessor(0)->clone());
881 }
882
883 private:
884 HighPrecisionFragmentProcessor(std::unique_ptr<GrFragmentProcessor> fp)
885 : INHERITED(kHighPrecisionFragmentProcessor_ClassID,
886 ProcessorOptimizationFlags(fp.get())) {
887 this->registerChild(std::move(fp));
888 }
889
890 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
891 class Impl : public ProgramImpl {
892 public:
893 void emitCode(EmitArgs& args) override {
894 SkString childColor = this->invokeChild(0, args);
895
896 args.fFragBuilder->forceHighPrecision();
897 args.fFragBuilder->codeAppendf("return %s;", childColor.c_str());
898 }
899 };
900 return std::make_unique<Impl>();
901 }
902
903 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
904 bool onIsEqual(const GrFragmentProcessor& other) const override { return true; }
905
906 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
907 return ConstantOutputForConstantInput(this->childProcessor(0), input);
908 }
909
910 using INHERITED = GrFragmentProcessor;
911 };
912
913 return HighPrecisionFragmentProcessor::Make(std::move(fp));
914 }
915
916 //////////////////////////////////////////////////////////////////////////////
917
918 using ProgramImpl = GrFragmentProcessor::ProgramImpl;
919
920 void ProgramImpl::setData(const GrGLSLProgramDataManager& pdman,
921 const GrFragmentProcessor& processor) {
922 this->onSetData(pdman, processor);
923 }
924
925 SkString ProgramImpl::invokeChild(int childIndex,
926 const char* inputColor,
927 const char* destColor,
928 EmitArgs& args,
929 SkSL::String skslCoords) {
930 SkASSERT(childIndex >= 0);
931
932 if (!inputColor) {
933 inputColor = args.fInputColor;
934 }
935
936 const GrFragmentProcessor* childProc = args.fFp.childProcessor(childIndex);
937 if (!childProc) {
938 // If no child processor is provided, return the input color as-is.
939 return SkString(inputColor);
940 }
941
942 auto invocation = SkStringPrintf("%s(%s", this->childProcessor(childIndex)->functionName(),
943 inputColor);
944
945 if (childProc->isBlendFunction()) {
946 if (!destColor) {
947 destColor = args.fFp.isBlendFunction() ? args.fDestColor : "half4(1)";
948 }
949 invocation.appendf(", %s", destColor);
950 }
951
952 // Assert that the child has no sample matrix. A uniform matrix sample call would go through
953 // invokeChildWithMatrix, not here.
954 SkASSERT(!childProc->sampleUsage().isUniformMatrix());
955
956 if (args.fFragBuilder->getProgramBuilder()->fragmentProcessorHasCoordsParam(childProc)) {
957 SkASSERT(!childProc->sampleUsage().isFragCoord() || skslCoords == "sk_FragCoord.xy");
958 // The child's function takes a half4 color and a float2 coordinate
959 invocation.appendf(", %s", skslCoords.empty() ? args.fSampleCoord : skslCoords.c_str());
960 }
961
962 invocation.append(")");
963 return invocation;
964 }
965
966 SkString ProgramImpl::invokeChildWithMatrix(int childIndex,
967 const char* inputColor,
968 const char* destColor,
969 EmitArgs& args) {
970 SkASSERT(childIndex >= 0);
971
972 if (!inputColor) {
973 inputColor = args.fInputColor;
974 }
975
976 const GrFragmentProcessor* childProc = args.fFp.childProcessor(childIndex);
977 if (!childProc) {
978 // If no child processor is provided, return the input color as-is.
979 return SkString(inputColor);
980 }
981
982 SkASSERT(childProc->sampleUsage().isUniformMatrix());
983
984 // Every uniform matrix has the same (initial) name. Resolve that into the mangled name:
985 GrShaderVar uniform = args.fUniformHandler->getUniformMapping(
986 args.fFp, SkString(SkSL::SampleUsage::MatrixUniformName()));
987 SkASSERT(uniform.getType() == kFloat3x3_GrSLType);
988 const SkString& matrixName(uniform.getName());
989
990 auto invocation = SkStringPrintf("%s(%s", this->childProcessor(childIndex)->functionName(),
991 inputColor);
992
993 if (childProc->isBlendFunction()) {
994 if (!destColor) {
995 destColor = args.fFp.isBlendFunction() ? args.fDestColor : "half4(1)";
996 }
997 invocation.appendf(", %s", destColor);
998 }
999
1000 // Produce a string containing the call to the helper function. We have a uniform variable
1001 // containing our transform (matrixName). If the parent coords were produced by uniform
1002 // transforms, then the entire expression (matrixName * coords) is lifted to a vertex shader
1003 // and is stored in a varying. In that case, childProc will not be sampled explicitly, so its
1004 // function signature will not take in coords.
1005 //
1006 // In all other cases, we need to insert sksl to compute matrix * parent coords and then invoke
1007 // the function.
1008 if (args.fFragBuilder->getProgramBuilder()->fragmentProcessorHasCoordsParam(childProc)) {
1009 // Only check perspective for this specific matrix transform, not the aggregate FP property.
1010 // Any parent perspective will have already been applied when evaluated in the FS.
1011 if (childProc->sampleUsage().hasPerspective()) {
1012 invocation.appendf(", proj((%s) * %s.xy1)", matrixName.c_str(), args.fSampleCoord);
1013 } else if (args.fShaderCaps->nonsquareMatrixSupport()) {
1014 invocation.appendf(", float3x2(%s) * %s.xy1", matrixName.c_str(), args.fSampleCoord);
1015 } else {
1016 invocation.appendf(", ((%s) * %s.xy1).xy", matrixName.c_str(), args.fSampleCoord);
1017 }
1018 }
1019
1020 invocation.append(")");
1021 return invocation;
1022 }
1023