blob: edc585026a06834368c696271765cc13193011f4 [file] [log] [blame]
bsalomonbf877302015-09-22 09:06:13 -07001/*
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
Brian Osmand1b530a2021-05-25 16:09:16 -04008#include "src/core/SkRuntimeEffectPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -05009#include "src/gpu/GrFragmentProcessor.h"
10#include "src/gpu/GrPipeline.h"
11#include "src/gpu/GrProcessorAnalysis.h"
John Stilesf743d4e2020-07-23 11:35:08 -040012#include "src/gpu/effects/GrBlendFragmentProcessor.h"
Brian Salomon354147a2021-04-14 11:15:05 -040013#include "src/gpu/effects/GrSkSLFP.h"
Robert Phillips550de7f2021-07-06 16:28:52 -040014#include "src/gpu/effects/GrTextureEffect.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "src/gpu/glsl/GrGLSLFragmentProcessor.h"
16#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
17#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
18#include "src/gpu/glsl/GrGLSLUniformHandler.h"
bsalomonbf877302015-09-22 09:06:13 -070019
bsalomon7312ff82016-09-12 08:55:38 -070020bool GrFragmentProcessor::isEqual(const GrFragmentProcessor& that) const {
Brian Salomone782f842018-07-31 13:53:11 -040021 if (this->classID() != that.classID()) {
bsalomonbf877302015-09-22 09:06:13 -070022 return false;
23 }
Brian Salomon66b500a2021-08-02 12:37:14 -040024 if (this->sampleUsage() != that.sampleUsage()) {
bsalomonbf877302015-09-22 09:06:13 -070025 return false;
26 }
27 if (!this->onIsEqual(that)) {
28 return false;
29 }
30 if (this->numChildProcessors() != that.numChildProcessors()) {
31 return false;
32 }
33 for (int i = 0; i < this->numChildProcessors(); ++i) {
Brian Osman12c5d292020-07-13 16:11:35 -040034 auto thisChild = this->childProcessor(i),
35 thatChild = that .childProcessor(i);
36 if (SkToBool(thisChild) != SkToBool(thatChild)) {
37 return false;
38 }
39 if (thisChild && !thisChild->isEqual(*thatChild)) {
bsalomonbf877302015-09-22 09:06:13 -070040 return false;
41 }
42 }
43 return true;
44}
45
Robert Phillips294723d2021-06-17 09:23:58 -040046void GrFragmentProcessor::visitProxies(const GrVisitProxyFunc& func) const {
Brian Salomond90b3d32020-07-09 12:04:31 -040047 this->visitTextureEffects([&func](const GrTextureEffect& te) {
Brian Salomone69b9ef2020-07-22 11:18:06 -040048 func(te.view().proxy(), te.samplerState().mipmapped());
Brian Salomond90b3d32020-07-09 12:04:31 -040049 });
50}
51
52void GrFragmentProcessor::visitTextureEffects(
53 const std::function<void(const GrTextureEffect&)>& func) const {
54 if (auto* te = this->asTextureEffect()) {
55 func(*te);
Brian Salomone782f842018-07-31 13:53:11 -040056 }
Brian Salomond90b3d32020-07-09 12:04:31 -040057 for (auto& child : fChildProcessors) {
Brian Osman12c5d292020-07-13 16:11:35 -040058 if (child) {
59 child->visitTextureEffects(func);
60 }
Brian Salomond90b3d32020-07-09 12:04:31 -040061 }
62}
63
Brian Salomon91398032021-08-05 10:02:08 -040064void GrFragmentProcessor::visitWithImpls(
Brian Salomon3176e862021-08-09 11:23:04 -040065 const std::function<void(const GrFragmentProcessor&, ProgramImpl&)>& f,
66 ProgramImpl& impl) const {
Brian Salomon91398032021-08-05 10:02:08 -040067 f(*this, impl);
68 SkASSERT(impl.numChildProcessors() == this->numChildProcessors());
69 for (int i = 0; i < this->numChildProcessors(); ++i) {
70 if (const auto* child = this->childProcessor(i)) {
71 child->visitWithImpls(f, *impl.childProcessor(i));
72 }
73 }
74}
75
Brian Salomond90b3d32020-07-09 12:04:31 -040076GrTextureEffect* GrFragmentProcessor::asTextureEffect() {
77 if (this->classID() == kGrTextureEffect_ClassID) {
78 return static_cast<GrTextureEffect*>(this);
79 }
80 return nullptr;
81}
82
83const GrTextureEffect* GrFragmentProcessor::asTextureEffect() const {
84 if (this->classID() == kGrTextureEffect_ClassID) {
85 return static_cast<const GrTextureEffect*>(this);
86 }
87 return nullptr;
Brian Salomone782f842018-07-31 13:53:11 -040088}
89
John Stiles8d9bf642020-08-12 15:07:45 -040090#if GR_TEST_UTILS
John Stilesba1879d2020-08-11 13:58:32 -040091static void recursive_dump_tree_info(const GrFragmentProcessor& fp,
92 SkString indent,
93 SkString* text) {
94 for (int index = 0; index < fp.numChildProcessors(); ++index) {
95 text->appendf("\n%s(#%d) -> ", indent.c_str(), index);
96 if (const GrFragmentProcessor* childFP = fp.childProcessor(index)) {
97 text->append(childFP->dumpInfo());
98 indent.append("\t");
99 recursive_dump_tree_info(*childFP, indent, text);
100 } else {
101 text->append("null");
102 }
103 }
104}
105
106SkString GrFragmentProcessor::dumpTreeInfo() const {
107 SkString text = this->dumpInfo();
108 recursive_dump_tree_info(*this, SkString("\t"), &text);
109 text.append("\n");
110 return text;
111}
112#endif
113
Brian Salomon3176e862021-08-09 11:23:04 -0400114std::unique_ptr<GrFragmentProcessor::ProgramImpl> GrFragmentProcessor::makeProgramImpl() const {
115 std::unique_ptr<ProgramImpl> impl = this->onMakeProgramImpl();
116 impl->fChildProcessors.push_back_n(fChildProcessors.count());
bsalomonbf877302015-09-22 09:06:13 -0700117 for (int i = 0; i < fChildProcessors.count(); ++i) {
Brian Salomon3176e862021-08-09 11:23:04 -0400118 impl->fChildProcessors[i] = fChildProcessors[i] ? fChildProcessors[i]->makeProgramImpl()
119 : nullptr;
bsalomonbf877302015-09-22 09:06:13 -0700120 }
Brian Salomon3176e862021-08-09 11:23:04 -0400121 return impl;
bsalomonbf877302015-09-22 09:06:13 -0700122}
123
Brian Osman12c5d292020-07-13 16:11:35 -0400124int GrFragmentProcessor::numNonNullChildProcessors() const {
125 return std::count_if(fChildProcessors.begin(), fChildProcessors.end(),
126 [](const auto& c) { return c != nullptr; });
127}
128
Robert Phillips82774f82019-06-20 14:38:27 -0400129#ifdef SK_DEBUG
130bool GrFragmentProcessor::isInstantiated() const {
Brian Salomond90b3d32020-07-09 12:04:31 -0400131 bool result = true;
132 this->visitTextureEffects([&result](const GrTextureEffect& te) {
133 if (!te.texture()) {
134 result = false;
Brian Salomone782f842018-07-31 13:53:11 -0400135 }
Brian Salomond90b3d32020-07-09 12:04:31 -0400136 });
137 return result;
Robert Phillips9bee2e52017-05-29 12:37:20 -0400138}
Robert Phillips82774f82019-06-20 14:38:27 -0400139#endif
Robert Phillips9bee2e52017-05-29 12:37:20 -0400140
Brian Osman12c5d292020-07-13 16:11:35 -0400141void GrFragmentProcessor::registerChild(std::unique_ptr<GrFragmentProcessor> child,
142 SkSL::SampleUsage sampleUsage) {
Brian Osman54867de2020-07-10 14:22:57 -0400143 if (!child) {
Brian Osman12c5d292020-07-13 16:11:35 -0400144 fChildProcessors.push_back(nullptr);
145 return;
Brian Osman54867de2020-07-10 14:22:57 -0400146 }
147
Michael Ludwige88320b2020-06-24 09:04:56 -0400148 // The child should not have been attached to another FP already and not had any sampling
149 // strategy set on it.
Brian Salomon66b500a2021-08-02 12:37:14 -0400150 SkASSERT(!child->fParent && !child->sampleUsage().isSampled());
Michael Ludwige88320b2020-06-24 09:04:56 -0400151
Michael Ludwig9aba6252020-06-22 14:46:36 -0400152 // Configure child's sampling state first
Brian Osman1298bc42020-06-30 13:39:35 -0400153 child->fUsage = sampleUsage;
154
John Stilese69f25f2021-06-03 12:23:33 -0400155 // Propagate the "will read dest-color" flag up to parent FPs.
John Stilesbc4bc5f2021-06-11 16:43:15 -0400156 if (child->willReadDstColor()) {
157 this->setWillReadDstColor();
John Stilese69f25f2021-06-03 12:23:33 -0400158 }
159
Brian Salomon66b500a2021-08-02 12:37:14 -0400160 // If this child receives passthrough or matrix transformed coords from its parent then note
161 // that the parent's coords are used indirectly to ensure that they aren't omitted.
162 if ((sampleUsage.isPassThrough() || sampleUsage.isUniformMatrix()) &&
163 child->usesSampleCoords()) {
164 fFlags |= kUsesSampleCoordsIndirectly_Flag;
Michael Ludwige88320b2020-06-24 09:04:56 -0400165 }
166
Chris Daltond7291ba2019-03-07 14:17:03 -0700167 fRequestedFeatures |= child->fRequestedFeatures;
bsalomonbf877302015-09-22 09:06:13 -0700168
Michael Ludwige88320b2020-06-24 09:04:56 -0400169 // Record that the child is attached to us; this FP is the source of any uniform data needed
170 // to evaluate the child sample matrix.
171 child->fParent = this;
Brian Salomonaff329b2017-08-11 09:40:37 -0400172 fChildProcessors.push_back(std::move(child));
Michael Ludwige88320b2020-06-24 09:04:56 -0400173
Leon Scroggins III982fff22020-07-31 14:09:06 -0400174 // Validate: our sample strategy comes from a parent we shouldn't have yet.
Brian Salomon66b500a2021-08-02 12:37:14 -0400175 SkASSERT(!fUsage.isSampled() && !fParent);
John Stiles3779f442020-06-15 10:48:49 -0400176}
177
John Stiles9ec6b052020-06-15 12:06:10 -0400178void GrFragmentProcessor::cloneAndRegisterAllChildProcessors(const GrFragmentProcessor& src) {
179 for (int i = 0; i < src.numChildProcessors(); ++i) {
Brian Osman12c5d292020-07-13 16:11:35 -0400180 if (auto fp = src.childProcessor(i)) {
181 this->registerChild(fp->clone(), fp->sampleUsage());
182 } else {
183 this->registerChild(nullptr);
184 }
John Stiles9ec6b052020-06-15 12:06:10 -0400185 }
186}
187
Brian Salomon354147a2021-04-14 11:15:05 -0400188std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::MakeColor(SkPMColor4f color) {
Brian Osman4cd134c2021-04-28 17:25:31 -0400189 // Use ColorFilter signature/factory to get the constant output for constant input optimization
Brian Osmand1b530a2021-05-25 16:09:16 -0400190 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
Brian Salomon354147a2021-04-14 11:15:05 -0400191 uniform half4 color;
Brian Osman4cd134c2021-04-28 17:25:31 -0400192 half4 main(half4 inColor) { return color; }
Brian Osmand1b530a2021-05-25 16:09:16 -0400193 )");
Brian Osmanbe545c92021-06-18 09:41:15 -0400194 SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
Brian Osman171fba72021-06-16 17:10:21 -0400195 return GrSkSLFP::Make(effect, "color_fp", /*inputFP=*/nullptr,
196 color.isOpaque() ? GrSkSLFP::OptFlags::kPreservesOpaqueInput
197 : GrSkSLFP::OptFlags::kNone,
198 "color", color);
Brian Salomon354147a2021-04-14 11:15:05 -0400199}
200
Mike Reed28eaed22018-02-01 11:24:53 -0500201std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::MulChildByInputAlpha(
Brian Salomonaff329b2017-08-11 09:40:37 -0400202 std::unique_ptr<GrFragmentProcessor> fp) {
bsalomonf1b7a1d2015-09-28 06:26:28 -0700203 if (!fp) {
204 return nullptr;
205 }
Brian Salomon4b6e2f02021-07-08 14:04:21 -0400206 return GrBlendFragmentProcessor::Make(/*src=*/nullptr,
207 OverrideInput(std::move(fp), SK_PMColor4fWHITE),
208 SkBlendMode::kDstIn);
bsalomonbf877302015-09-22 09:06:13 -0700209}
210
Mike Reed28eaed22018-02-01 11:24:53 -0500211std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::MulInputByChildAlpha(
212 std::unique_ptr<GrFragmentProcessor> fp) {
213 if (!fp) {
214 return nullptr;
215 }
Brian Salomon4b6e2f02021-07-08 14:04:21 -0400216 return GrBlendFragmentProcessor::Make(/*src=*/nullptr,
217 OverrideInput(std::move(fp), SK_PMColor4fWHITE),
218 SkBlendMode::kSrcIn);
Mike Reed28eaed22018-02-01 11:24:53 -0500219}
220
John Stiles7bf26002020-07-13 11:30:12 -0400221std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::ModulateAlpha(
222 std::unique_ptr<GrFragmentProcessor> inputFP, const SkPMColor4f& color) {
Brian Salomon354147a2021-04-14 11:15:05 -0400223 auto colorFP = MakeColor(color);
Brian Salomon4b6e2f02021-07-08 14:04:21 -0400224 return GrBlendFragmentProcessor::Make(std::move(colorFP),
225 std::move(inputFP),
226 SkBlendMode::kSrcIn);
John Stiles7bf26002020-07-13 11:30:12 -0400227}
228
John Stiles85894302020-07-13 11:39:52 -0400229std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::ModulateRGBA(
230 std::unique_ptr<GrFragmentProcessor> inputFP, const SkPMColor4f& color) {
Brian Salomon354147a2021-04-14 11:15:05 -0400231 auto colorFP = MakeColor(color);
Brian Salomon4b6e2f02021-07-08 14:04:21 -0400232 return GrBlendFragmentProcessor::Make(std::move(colorFP),
233 std::move(inputFP),
234 SkBlendMode::kModulate);
John Stiles85894302020-07-13 11:39:52 -0400235}
236
Brian Osman8e814b32021-06-17 14:14:26 -0400237std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::ClampOutput(
238 std::unique_ptr<GrFragmentProcessor> fp) {
239 SkASSERT(fp);
240 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
241 half4 main(half4 inColor) {
242 return saturate(inColor);
243 }
244 )");
Brian Osmanbe545c92021-06-18 09:41:15 -0400245 SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
Brian Osman8e814b32021-06-17 14:14:26 -0400246 return GrSkSLFP::Make(
247 effect, "Clamp", std::move(fp), GrSkSLFP::OptFlags::kPreservesOpaqueInput);
248}
249
Brian Osman6f5e9402020-01-22 10:39:31 -0500250std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::ClampPremulOutput(
251 std::unique_ptr<GrFragmentProcessor> fp) {
Brian Osman8e814b32021-06-17 14:14:26 -0400252 SkASSERT(fp);
253 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
254 half4 main(half4 inColor) {
255 half alpha = saturate(inColor.a);
256 return half4(clamp(inColor.rgb, 0, alpha), alpha);
257 }
258 )");
Brian Osmanbe545c92021-06-18 09:41:15 -0400259 SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
Brian Osman8e814b32021-06-17 14:14:26 -0400260 return GrSkSLFP::Make(
261 effect, "ClampPremul", std::move(fp), GrSkSLFP::OptFlags::kPreservesOpaqueInput);
Brian Osman6f5e9402020-01-22 10:39:31 -0500262}
263
Brian Salomonaff329b2017-08-11 09:40:37 -0400264std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::SwizzleOutput(
265 std::unique_ptr<GrFragmentProcessor> fp, const GrSwizzle& swizzle) {
Brian Osmance425512017-03-22 14:37:50 -0400266 class SwizzleFragmentProcessor : public GrFragmentProcessor {
267 public:
John Stileseed56f02020-06-04 13:30:51 -0400268 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp,
269 const GrSwizzle& swizzle) {
270 return std::unique_ptr<GrFragmentProcessor>(
John Stiles4bdc1212020-12-14 18:04:13 -0500271 new SwizzleFragmentProcessor(std::move(fp), swizzle));
Brian Osmance425512017-03-22 14:37:50 -0400272 }
273
274 const char* name() const override { return "Swizzle"; }
Brian Osmance425512017-03-22 14:37:50 -0400275
John Stileseed56f02020-06-04 13:30:51 -0400276 std::unique_ptr<GrFragmentProcessor> clone() const override {
Brian Osman12c5d292020-07-13 16:11:35 -0400277 return Make(this->childProcessor(0)->clone(), fSwizzle);
John Stileseed56f02020-06-04 13:30:51 -0400278 }
Brian Salomon216f2e02017-07-25 15:52:51 -0400279
Brian Osmance425512017-03-22 14:37:50 -0400280 private:
John Stileseed56f02020-06-04 13:30:51 -0400281 SwizzleFragmentProcessor(std::unique_ptr<GrFragmentProcessor> fp, const GrSwizzle& swizzle)
282 : INHERITED(kSwizzleFragmentProcessor_ClassID, ProcessorOptimizationFlags(fp.get()))
283 , fSwizzle(swizzle) {
Michael Ludwig9aba6252020-06-22 14:46:36 -0400284 this->registerChild(std::move(fp));
John Stileseed56f02020-06-04 13:30:51 -0400285 }
Robert Phillips1c9686b2017-06-30 08:40:28 -0400286
Brian Salomon3176e862021-08-09 11:23:04 -0400287 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
Brian Salomonb25560a2021-08-10 13:56:13 -0400288 class Impl : public ProgramImpl {
Brian Osmance425512017-03-22 14:37:50 -0400289 public:
290 void emitCode(EmitArgs& args) override {
Brian Osman6b5dbb42020-07-15 15:31:05 -0400291 SkString childColor = this->invokeChild(0, args);
John Stileseed56f02020-06-04 13:30:51 -0400292
Brian Osmance425512017-03-22 14:37:50 -0400293 const SwizzleFragmentProcessor& sfp = args.fFp.cast<SwizzleFragmentProcessor>();
Brian Salomonb25560a2021-08-10 13:56:13 -0400294 const GrSwizzle& swizzle = sfp.fSwizzle;
Brian Osmance425512017-03-22 14:37:50 -0400295 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
296
John Stiles4bdc1212020-12-14 18:04:13 -0500297 fragBuilder->codeAppendf("return %s.%s;",
298 childColor.c_str(), swizzle.asString().c_str());
Brian Osmance425512017-03-22 14:37:50 -0400299 }
300 };
Brian Salomonb25560a2021-08-10 13:56:13 -0400301 return std::make_unique<Impl>();
Brian Osmance425512017-03-22 14:37:50 -0400302 }
303
Brian Salomon13b28732021-08-06 15:33:58 -0400304 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
Brian Osmance425512017-03-22 14:37:50 -0400305 b->add32(fSwizzle.asKey());
306 }
307
308 bool onIsEqual(const GrFragmentProcessor& other) const override {
309 const SwizzleFragmentProcessor& sfp = other.cast<SwizzleFragmentProcessor>();
310 return fSwizzle == sfp.fSwizzle;
311 }
312
Brian Osman1d5b5982018-10-01 13:41:39 -0400313 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
Brian Osman36f3d1a2021-03-22 16:36:14 -0400314 return fSwizzle.applyTo(ConstantOutputForConstantInput(this->childProcessor(0), input));
Brian Osmance425512017-03-22 14:37:50 -0400315 }
316
317 GrSwizzle fSwizzle;
318
John Stiles7571f9e2020-09-02 22:42:33 -0400319 using INHERITED = GrFragmentProcessor;
Brian Osmance425512017-03-22 14:37:50 -0400320 };
321
322 if (!fp) {
323 return nullptr;
324 }
325 if (GrSwizzle::RGBA() == swizzle) {
326 return fp;
327 }
John Stileseed56f02020-06-04 13:30:51 -0400328 return SwizzleFragmentProcessor::Make(std::move(fp), swizzle);
Brian Osmance425512017-03-22 14:37:50 -0400329}
330
Brian Salomonaff329b2017-08-11 09:40:37 -0400331std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::MakeInputPremulAndMulByOutput(
332 std::unique_ptr<GrFragmentProcessor> fp) {
bsalomonf1b7a1d2015-09-28 06:26:28 -0700333 class PremulFragmentProcessor : public GrFragmentProcessor {
334 public:
Brian Salomonaff329b2017-08-11 09:40:37 -0400335 static std::unique_ptr<GrFragmentProcessor> Make(
336 std::unique_ptr<GrFragmentProcessor> processor) {
337 return std::unique_ptr<GrFragmentProcessor>(
338 new PremulFragmentProcessor(std::move(processor)));
Robert Phillips1c9686b2017-06-30 08:40:28 -0400339 }
340
341 const char* name() const override { return "Premultiply"; }
342
Brian Salomonaff329b2017-08-11 09:40:37 -0400343 std::unique_ptr<GrFragmentProcessor> clone() const override {
Brian Osman12c5d292020-07-13 16:11:35 -0400344 return Make(this->childProcessor(0)->clone());
Brian Salomon216f2e02017-07-25 15:52:51 -0400345 }
346
Robert Phillips1c9686b2017-06-30 08:40:28 -0400347 private:
Brian Salomonaff329b2017-08-11 09:40:37 -0400348 PremulFragmentProcessor(std::unique_ptr<GrFragmentProcessor> processor)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400349 : INHERITED(kPremulFragmentProcessor_ClassID, OptFlags(processor.get())) {
Michael Ludwig9aba6252020-06-22 14:46:36 -0400350 this->registerChild(std::move(processor));
bsalomonf1b7a1d2015-09-28 06:26:28 -0700351 }
352
Brian Salomon3176e862021-08-09 11:23:04 -0400353 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
Brian Salomonb25560a2021-08-10 13:56:13 -0400354 class Impl : public ProgramImpl {
bsalomonf1b7a1d2015-09-28 06:26:28 -0700355 public:
bsalomonf1b7a1d2015-09-28 06:26:28 -0700356 void emitCode(EmitArgs& args) override {
cdalton85285412016-02-18 12:37:07 -0800357 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
John Stiles4bdc1212020-12-14 18:04:13 -0500358 SkString temp = this->invokeChild(/*childIndex=*/0, "half4(1)", args);
359 fragBuilder->codeAppendf("half4 color = %s;", temp.c_str());
360 fragBuilder->codeAppendf("color.rgb *= %s.rgb;", args.fInputColor);
361 fragBuilder->codeAppendf("return color * %s.a;", args.fInputColor);
bsalomonf1b7a1d2015-09-28 06:26:28 -0700362 }
363 };
Brian Salomonb25560a2021-08-10 13:56:13 -0400364 return std::make_unique<Impl>();
bsalomonf1b7a1d2015-09-28 06:26:28 -0700365 }
366
Brian Salomon13b28732021-08-06 15:33:58 -0400367 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
bsalomonf1b7a1d2015-09-28 06:26:28 -0700368
369 bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
370
Brian Salomon587e08f2017-01-27 10:59:27 -0500371 static OptimizationFlags OptFlags(const GrFragmentProcessor* inner) {
372 OptimizationFlags flags = kNone_OptimizationFlags;
373 if (inner->preservesOpaqueInput()) {
374 flags |= kPreservesOpaqueInput_OptimizationFlag;
375 }
376 if (inner->hasConstantOutputForConstantInput()) {
377 flags |= kConstantOutputForConstantInput_OptimizationFlag;
378 }
379 return flags;
380 }
bsalomonf1b7a1d2015-09-28 06:26:28 -0700381
Brian Osman1d5b5982018-10-01 13:41:39 -0400382 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
383 SkPMColor4f childColor = ConstantOutputForConstantInput(this->childProcessor(0),
Brian Osmanf28e55d2018-10-03 16:35:54 -0400384 SK_PMColor4fWHITE);
Brian Osman1d5b5982018-10-01 13:41:39 -0400385 SkPMColor4f premulInput = SkColor4f{ input.fR, input.fG, input.fB, input.fA }.premul();
386 return premulInput * childColor;
Brian Salomon587e08f2017-01-27 10:59:27 -0500387 }
388
John Stiles7571f9e2020-09-02 22:42:33 -0400389 using INHERITED = GrFragmentProcessor;
bsalomonf1b7a1d2015-09-28 06:26:28 -0700390 };
391 if (!fp) {
392 return nullptr;
393 }
Robert Phillips1c9686b2017-06-30 08:40:28 -0400394 return PremulFragmentProcessor::Make(std::move(fp));
bsalomonf1b7a1d2015-09-28 06:26:28 -0700395}
396
397//////////////////////////////////////////////////////////////////////////////
398
Brian Salomonaff329b2017-08-11 09:40:37 -0400399std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::OverrideInput(
Brian Salomonc0d79e52019-04-10 15:02:11 -0400400 std::unique_ptr<GrFragmentProcessor> fp, const SkPMColor4f& color, bool useUniform) {
Robert Phillips1c9686b2017-06-30 08:40:28 -0400401 if (!fp) {
402 return nullptr;
403 }
Brian Osman59465892021-06-18 09:15:44 -0400404 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
405 uniform colorFilter fp; // Declared as colorFilter so we can use sample(..., color)
406 uniform half4 color;
407 half4 main(half4 inColor) {
408 return sample(fp, color);
409 }
410 )");
411 SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
412 return GrSkSLFP::Make(effect, "OverrideInput", /*inputFP=*/nullptr,
413 color.isOpaque() ? GrSkSLFP::OptFlags::kPreservesOpaqueInput
414 : GrSkSLFP::OptFlags::kNone,
415 "fp", std::move(fp),
416 "color", GrSkSLFP::SpecializeIf(!useUniform, color));
bsalomonf1b7a1d2015-09-28 06:26:28 -0700417}
bsalomone25eea42015-09-29 06:38:55 -0700418
John Stiles024d7452020-07-22 19:07:15 -0400419//////////////////////////////////////////////////////////////////////////////
420
John Stiles2a6f73c2021-07-29 19:36:20 -0400421std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::UseDestColorAsInput(
422 std::unique_ptr<GrFragmentProcessor> fp) {
423 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForBlender, R"(
424 uniform colorFilter fp; // Declared as colorFilter so we can use sample(..., color)
425 half4 main(half4 src, half4 dst) {
426 return sample(fp, dst);
427 }
428 )");
429 return GrSkSLFP::Make(effect, "UseDestColorAsInput", /*inputFP=*/nullptr,
430 GrSkSLFP::OptFlags::kNone, "fp", std::move(fp));
431}
432
433//////////////////////////////////////////////////////////////////////////////
434
Brian Salomon25af4802021-07-07 16:24:16 -0400435std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::MakeInputOpaqueAndPostApplyAlpha(
436 std::unique_ptr<GrFragmentProcessor> fp) {
437 if (!fp) {
438 return nullptr;
439 }
440 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
441 uniform colorFilter fp; // Declared as colorFilter so we can use sample(..., color)
442 half4 main(half4 inColor) {
443 return inColor.a * sample(fp, unpremul(inColor).rgb1);
444 }
445 )");
446 return GrSkSLFP::Make(effect,
447 "MakeInputOpaque",
448 /*inputFP=*/nullptr,
449 GrSkSLFP::OptFlags::kPreservesOpaqueInput,
450 "fp", std::move(fp));
451}
452
453//////////////////////////////////////////////////////////////////////////////
454
John Stiles024d7452020-07-22 19:07:15 -0400455std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::Compose(
456 std::unique_ptr<GrFragmentProcessor> f, std::unique_ptr<GrFragmentProcessor> g) {
457 class ComposeProcessor : public GrFragmentProcessor {
458 public:
459 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> f,
460 std::unique_ptr<GrFragmentProcessor> g) {
461 return std::unique_ptr<GrFragmentProcessor>(new ComposeProcessor(std::move(f),
462 std::move(g)));
463 }
464
465 const char* name() const override { return "Compose"; }
466
467 std::unique_ptr<GrFragmentProcessor> clone() const override {
468 return std::unique_ptr<GrFragmentProcessor>(new ComposeProcessor(*this));
469 }
470
471 private:
Brian Salomon3176e862021-08-09 11:23:04 -0400472 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
Brian Salomonb25560a2021-08-10 13:56:13 -0400473 class Impl : public ProgramImpl {
John Stiles024d7452020-07-22 19:07:15 -0400474 public:
475 void emitCode(EmitArgs& args) override {
Brian Osmanc5422d02021-03-12 16:06:35 -0500476 SkString result = this->invokeChild(1, args); // g(x)
477 result = this->invokeChild(0, result.c_str(), args); // f(g(x))
John Stiles49643002020-10-19 18:52:40 -0400478 args.fFragBuilder->codeAppendf("return %s;", result.c_str());
John Stiles024d7452020-07-22 19:07:15 -0400479 }
480 };
Brian Salomonb25560a2021-08-10 13:56:13 -0400481 return std::make_unique<Impl>();
John Stiles024d7452020-07-22 19:07:15 -0400482 }
483
484 ComposeProcessor(std::unique_ptr<GrFragmentProcessor> f,
485 std::unique_ptr<GrFragmentProcessor> g)
486 : INHERITED(kSeriesFragmentProcessor_ClassID,
487 f->optimizationFlags() & g->optimizationFlags()) {
488 this->registerChild(std::move(f));
489 this->registerChild(std::move(g));
490 }
491
John Stiles307f8f52021-08-09 15:36:59 -0400492 ComposeProcessor(const ComposeProcessor& that) : INHERITED(that) {}
John Stiles024d7452020-07-22 19:07:15 -0400493
Brian Salomon13b28732021-08-06 15:33:58 -0400494 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
John Stiles024d7452020-07-22 19:07:15 -0400495
496 bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
497
498 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override {
499 SkPMColor4f color = inColor;
John Stiles024d7452020-07-22 19:07:15 -0400500 color = ConstantOutputForConstantInput(this->childProcessor(1), color);
Brian Osmanc5422d02021-03-12 16:06:35 -0500501 color = ConstantOutputForConstantInput(this->childProcessor(0), color);
John Stiles024d7452020-07-22 19:07:15 -0400502 return color;
503 }
504
John Stiles7571f9e2020-09-02 22:42:33 -0400505 using INHERITED = GrFragmentProcessor;
John Stiles024d7452020-07-22 19:07:15 -0400506 };
507
508 // Allow either of the composed functions to be null.
509 if (f == nullptr) {
510 return g;
511 }
512 if (g == nullptr) {
513 return f;
514 }
515
516 // Run an optimization pass on this composition.
517 GrProcessorAnalysisColor inputColor;
518 inputColor.setToUnknown();
519
Brian Osmanc5422d02021-03-12 16:06:35 -0500520 std::unique_ptr<GrFragmentProcessor> series[2] = {std::move(g), std::move(f)};
John Stiles024d7452020-07-22 19:07:15 -0400521 GrColorFragmentProcessorAnalysis info(inputColor, series, SK_ARRAY_COUNT(series));
522
523 SkPMColor4f knownColor;
524 int leadingFPsToEliminate = info.initialProcessorsToEliminate(&knownColor);
525 switch (leadingFPsToEliminate) {
526 default:
527 // We shouldn't eliminate more than we started with.
528 SkASSERT(leadingFPsToEliminate <= 2);
529 [[fallthrough]];
530 case 0:
531 // Compose the two processors as requested.
Brian Osmanc5422d02021-03-12 16:06:35 -0500532 return ComposeProcessor::Make(/*f=*/std::move(series[1]), /*g=*/std::move(series[0]));
John Stiles024d7452020-07-22 19:07:15 -0400533 case 1:
534 // Replace the first processor with a constant color.
Brian Osmanc5422d02021-03-12 16:06:35 -0500535 return ComposeProcessor::Make(/*f=*/std::move(series[1]),
Brian Salomon354147a2021-04-14 11:15:05 -0400536 /*g=*/MakeColor(knownColor));
John Stiles024d7452020-07-22 19:07:15 -0400537 case 2:
538 // Replace the entire composition with a constant color.
Brian Salomon354147a2021-04-14 11:15:05 -0400539 return MakeColor(knownColor);
John Stiles024d7452020-07-22 19:07:15 -0400540 }
541}
542
543//////////////////////////////////////////////////////////////////////////////
544
Brian Osman48f83fd2021-06-23 15:51:26 +0000545std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::ColorMatrix(
546 std::unique_ptr<GrFragmentProcessor> child,
547 const float matrix[20],
548 bool unpremulInput,
549 bool clampRGBOutput,
550 bool premulOutput) {
551 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
552 uniform half4x4 m;
553 uniform half4 v;
554 uniform int unpremulInput; // always specialized
555 uniform int clampRGBOutput; // always specialized
556 uniform int premulOutput; // always specialized
557 half4 main(half4 color) {
558 if (bool(unpremulInput)) {
559 color = unpremul(color);
560 }
561 color = m * color + v;
562 if (bool(clampRGBOutput)) {
563 color = saturate(color);
564 } else {
565 color.a = saturate(color.a);
566 }
567 if (bool(premulOutput)) {
568 color.rgb *= color.a;
569 }
570 return color;
571 }
572 )");
573 SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
574
575 SkM44 m44(matrix[ 0], matrix[ 1], matrix[ 2], matrix[ 3],
576 matrix[ 5], matrix[ 6], matrix[ 7], matrix[ 8],
577 matrix[10], matrix[11], matrix[12], matrix[13],
578 matrix[15], matrix[16], matrix[17], matrix[18]);
579 SkV4 v4 = {matrix[4], matrix[9], matrix[14], matrix[19]};
580 return GrSkSLFP::Make(effect, "ColorMatrix", std::move(child), GrSkSLFP::OptFlags::kNone,
581 "m", m44,
582 "v", v4,
583 "unpremulInput", GrSkSLFP::Specialize(unpremulInput ? 1 : 0),
584 "clampRGBOutput", GrSkSLFP::Specialize(clampRGBOutput ? 1 : 0),
585 "premulOutput", GrSkSLFP::Specialize(premulOutput ? 1 : 0));
586}
587
588//////////////////////////////////////////////////////////////////////////////
589
John Stiles5b3aff42021-07-29 17:20:22 -0400590std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::SurfaceColor() {
591 class SurfaceColorProcessor : public GrFragmentProcessor {
John Stilesbb04e3d2021-06-04 12:09:11 -0400592 public:
593 static std::unique_ptr<GrFragmentProcessor> Make() {
John Stiles5b3aff42021-07-29 17:20:22 -0400594 return std::unique_ptr<GrFragmentProcessor>(new SurfaceColorProcessor());
John Stilesbb04e3d2021-06-04 12:09:11 -0400595 }
596
597 std::unique_ptr<GrFragmentProcessor> clone() const override { return Make(); }
598
John Stiles5b3aff42021-07-29 17:20:22 -0400599 const char* name() const override { return "SurfaceColor"; }
John Stilesbb04e3d2021-06-04 12:09:11 -0400600
601 private:
Brian Salomon3176e862021-08-09 11:23:04 -0400602 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
Brian Salomonb25560a2021-08-10 13:56:13 -0400603 class Impl : public ProgramImpl {
John Stilesbb04e3d2021-06-04 12:09:11 -0400604 public:
605 void emitCode(EmitArgs& args) override {
John Stiles5b3aff42021-07-29 17:20:22 -0400606 const char* dstColor = args.fFragBuilder->dstColor();
607 args.fFragBuilder->codeAppendf("return %s;", dstColor);
John Stilesbb04e3d2021-06-04 12:09:11 -0400608 }
609 };
Brian Salomonb25560a2021-08-10 13:56:13 -0400610 return std::make_unique<Impl>();
John Stilesbb04e3d2021-06-04 12:09:11 -0400611 }
612
John Stiles5b3aff42021-07-29 17:20:22 -0400613 SurfaceColorProcessor()
614 : INHERITED(kSurfaceColorProcessor_ClassID, kNone_OptimizationFlags) {
John Stilesbc4bc5f2021-06-11 16:43:15 -0400615 this->setWillReadDstColor();
John Stilesbb04e3d2021-06-04 12:09:11 -0400616 }
617
Brian Salomon13b28732021-08-06 15:33:58 -0400618 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
John Stilesbb04e3d2021-06-04 12:09:11 -0400619
620 bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
621
622 using INHERITED = GrFragmentProcessor;
623 };
624
John Stiles5b3aff42021-07-29 17:20:22 -0400625 return SurfaceColorProcessor::Make();
John Stilesbb04e3d2021-06-04 12:09:11 -0400626}
627
628//////////////////////////////////////////////////////////////////////////////
629
Brian Osman62905552021-06-21 13:11:01 -0400630std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::DeviceSpace(
631 std::unique_ptr<GrFragmentProcessor> fp) {
Brian Salomon4f8d4be2021-07-30 18:21:32 -0400632 if (!fp) {
633 return nullptr;
634 }
635
636 class DeviceSpace : GrFragmentProcessor {
637 public:
638 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp) {
639 return std::unique_ptr<GrFragmentProcessor>(new DeviceSpace(std::move(fp)));
Brian Osman62905552021-06-21 13:11:01 -0400640 }
Brian Salomon4f8d4be2021-07-30 18:21:32 -0400641
642 private:
643 DeviceSpace(std::unique_ptr<GrFragmentProcessor> fp)
644 : GrFragmentProcessor(kDeviceSpace_ClassID, fp->optimizationFlags()) {
Brian Salomon9eca2ca2021-08-02 13:04:04 -0400645 // Passing FragCoord here is the reason this is a subclass and not a runtime-FP.
646 this->registerChild(std::move(fp), SkSL::SampleUsage::FragCoord());
Brian Salomon4f8d4be2021-07-30 18:21:32 -0400647 }
648
649 std::unique_ptr<GrFragmentProcessor> clone() const override {
650 auto child = this->childProcessor(0)->clone();
651 return std::unique_ptr<GrFragmentProcessor>(new DeviceSpace(std::move(child)));
652 }
653
654 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& f) const override {
655 return this->childProcessor(0)->constantOutputForConstantInput(f);
656 }
657
Brian Salomon3176e862021-08-09 11:23:04 -0400658 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
659 class Impl : public ProgramImpl {
Brian Salomon4f8d4be2021-07-30 18:21:32 -0400660 public:
661 Impl() = default;
Brian Salomon3176e862021-08-09 11:23:04 -0400662 void emitCode(ProgramImpl::EmitArgs& args) override {
Brian Salomon4f8d4be2021-07-30 18:21:32 -0400663 auto child = this->invokeChild(0, args.fInputColor, args, "sk_FragCoord.xy");
664 args.fFragBuilder->codeAppendf("return %s;", child.c_str());
665 }
666 };
667 return std::make_unique<Impl>();
668 }
669
Brian Salomon13b28732021-08-06 15:33:58 -0400670 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
Brian Salomon4f8d4be2021-07-30 18:21:32 -0400671
672 bool onIsEqual(const GrFragmentProcessor& processor) const override { return true; }
673
674 const char* name() const override { return "DeviceSpace"; }
675 };
676
677 return DeviceSpace::Make(std::move(fp));
Brian Osman62905552021-06-21 13:11:01 -0400678}
679
680//////////////////////////////////////////////////////////////////////////////
681
Brian Osmanb384eb22021-06-24 15:34:08 -0400682#define CLIP_EDGE_SKSL \
683 "const int kFillBW = 0;" \
684 "const int kFillAA = 1;" \
685 "const int kInverseFillBW = 2;" \
686 "const int kInverseFillAA = 3;"
687
688static_assert(static_cast<int>(GrClipEdgeType::kFillBW) == 0);
689static_assert(static_cast<int>(GrClipEdgeType::kFillAA) == 1);
690static_assert(static_cast<int>(GrClipEdgeType::kInverseFillBW) == 2);
691static_assert(static_cast<int>(GrClipEdgeType::kInverseFillAA) == 3);
692
693std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::Rect(
694 std::unique_ptr<GrFragmentProcessor> inputFP, GrClipEdgeType edgeType, SkRect rect) {
695 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, CLIP_EDGE_SKSL R"(
696 uniform int edgeType; // GrClipEdgeType, specialized
697 uniform float4 rectUniform;
698
699 half4 main(float2 xy, half4 inColor) {
700 half coverage;
701 if (edgeType == kFillBW || edgeType == kInverseFillBW) {
702 // non-AA
703 coverage = all(greaterThan(float4(sk_FragCoord.xy, rectUniform.zw),
704 float4(rectUniform.xy, sk_FragCoord.xy))) ? 1 : 0;
705 } else {
706 // compute coverage relative to left and right edges, add, then subtract 1 to
707 // account for double counting. And similar for top/bottom.
708 half4 dists4 = clamp(half4(1, 1, -1, -1) *
709 half4(sk_FragCoord.xyxy - rectUniform), 0, 1);
710 half2 dists2 = dists4.xy + dists4.zw - 1;
711 coverage = dists2.x * dists2.y;
712 }
713
714 if (edgeType == kInverseFillBW || edgeType == kInverseFillAA) {
715 coverage = 1.0 - coverage;
716 }
717
718 return inColor * coverage;
719 }
720 )");
721
722 SkASSERT(rect.isSorted());
723 // The AA math in the shader evaluates to 0 at the uploaded coordinates, so outset by 0.5
724 // to interpolate from 0 at a half pixel inset and 1 at a half pixel outset of rect.
Brian Osman50f0dad2021-07-08 13:47:25 -0400725 SkRect rectUniform = GrClipEdgeTypeIsAA(edgeType) ? rect.makeOutset(.5f, .5f) : rect;
Brian Osmanb384eb22021-06-24 15:34:08 -0400726
727 return GrSkSLFP::Make(effect, "Rect", std::move(inputFP),
728 GrSkSLFP::OptFlags::kCompatibleWithCoverageAsAlpha,
729 "edgeType", GrSkSLFP::Specialize(static_cast<int>(edgeType)),
730 "rectUniform", rectUniform);
731}
732
733GrFPResult GrFragmentProcessor::Circle(std::unique_ptr<GrFragmentProcessor> inputFP,
734 GrClipEdgeType edgeType,
735 SkPoint center,
736 float radius) {
737 // A radius below half causes the implicit insetting done by this processor to become
738 // inverted. We could handle this case by making the processor code more complicated.
Brian Osman50f0dad2021-07-08 13:47:25 -0400739 if (radius < .5f && GrClipEdgeTypeIsInverseFill(edgeType)) {
Brian Osmanb384eb22021-06-24 15:34:08 -0400740 return GrFPFailure(std::move(inputFP));
741 }
742
743 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, CLIP_EDGE_SKSL R"(
744 uniform int edgeType; // GrClipEdgeType, specialized
745 // The circle uniform is (center.x, center.y, radius + 0.5, 1 / (radius + 0.5)) for regular
746 // fills and (..., radius - 0.5, 1 / (radius - 0.5)) for inverse fills.
747 uniform float4 circle;
748
749 half4 main(float2 xy, half4 inColor) {
750 // TODO: Right now the distance to circle calculation is performed in a space normalized
751 // to the radius and then denormalized. This is to mitigate overflow on devices that
752 // don't have full float.
753 half d;
754 if (edgeType == kInverseFillBW || edgeType == kInverseFillAA) {
755 d = half((length((circle.xy - sk_FragCoord.xy) * circle.w) - 1.0) * circle.z);
756 } else {
757 d = half((1.0 - length((circle.xy - sk_FragCoord.xy) * circle.w)) * circle.z);
758 }
759 if (edgeType == kFillAA || edgeType == kInverseFillAA) {
760 return inColor * saturate(d);
761 } else {
762 return d > 0.5 ? inColor : half4(0);
763 }
764 }
765 )");
766
767 SkScalar effectiveRadius = radius;
Brian Osman50f0dad2021-07-08 13:47:25 -0400768 if (GrClipEdgeTypeIsInverseFill(edgeType)) {
Brian Osmanb384eb22021-06-24 15:34:08 -0400769 effectiveRadius -= 0.5f;
770 // When the radius is 0.5 effectiveRadius is 0 which causes an inf * 0 in the shader.
771 effectiveRadius = std::max(0.001f, effectiveRadius);
772 } else {
773 effectiveRadius += 0.5f;
774 }
775 SkV4 circle = {center.fX, center.fY, effectiveRadius, SkScalarInvert(effectiveRadius)};
776
777 return GrFPSuccess(GrSkSLFP::Make(effect, "Circle", std::move(inputFP),
778 GrSkSLFP::OptFlags::kCompatibleWithCoverageAsAlpha,
779 "edgeType", GrSkSLFP::Specialize(static_cast<int>(edgeType)),
780 "circle", circle));
781}
782
783GrFPResult GrFragmentProcessor::Ellipse(std::unique_ptr<GrFragmentProcessor> inputFP,
784 GrClipEdgeType edgeType,
785 SkPoint center,
786 SkPoint radii,
787 const GrShaderCaps& caps) {
788 const bool medPrecision = !caps.floatIs32Bits();
789
790 // Small radii produce bad results on devices without full float.
791 if (medPrecision && (radii.fX < 0.5f || radii.fY < 0.5f)) {
792 return GrFPFailure(std::move(inputFP));
793 }
794 // Very narrow ellipses produce bad results on devices without full float
795 if (medPrecision && (radii.fX > 255*radii.fY || radii.fY > 255*radii.fX)) {
796 return GrFPFailure(std::move(inputFP));
797 }
798 // Very large ellipses produce bad results on devices without full float
799 if (medPrecision && (radii.fX > 16384 || radii.fY > 16384)) {
800 return GrFPFailure(std::move(inputFP));
801 }
802
803 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, CLIP_EDGE_SKSL R"(
804 uniform int edgeType; // GrClipEdgeType, specialized
805 uniform int medPrecision; // !sk_Caps.floatIs32Bits, specialized
806
807 uniform float4 ellipse;
808 uniform float2 scale; // only for medPrecision
809
810 half4 main(float2 xy, half4 inColor) {
811 // d is the offset to the ellipse center
812 float2 d = sk_FragCoord.xy - ellipse.xy;
813 // If we're on a device with a "real" mediump then we'll do the distance computation in
814 // a space that is normalized by the larger radius or 128, whichever is smaller. The
815 // scale uniform will be scale, 1/scale. The inverse squared radii uniform values are
816 // already in this normalized space. The center is not.
817 if (bool(medPrecision)) {
818 d *= scale.y;
819 }
820 float2 Z = d * ellipse.zw;
821 // implicit is the evaluation of (x/rx)^2 + (y/ry)^2 - 1.
822 float implicit = dot(Z, d) - 1;
823 // grad_dot is the squared length of the gradient of the implicit.
824 float grad_dot = 4 * dot(Z, Z);
825 // Avoid calling inversesqrt on zero.
826 if (bool(medPrecision)) {
827 grad_dot = max(grad_dot, 6.1036e-5);
828 } else {
829 grad_dot = max(grad_dot, 1.1755e-38);
830 }
831 float approx_dist = implicit * inversesqrt(grad_dot);
832 if (bool(medPrecision)) {
833 approx_dist *= scale.x;
834 }
835
836 half alpha;
837 if (edgeType == kFillBW) {
838 alpha = approx_dist > 0.0 ? 0.0 : 1.0;
839 } else if (edgeType == kFillAA) {
840 alpha = saturate(0.5 - half(approx_dist));
841 } else if (edgeType == kInverseFillBW) {
842 alpha = approx_dist > 0.0 ? 1.0 : 0.0;
843 } else { // edgeType == kInverseFillAA
844 alpha = saturate(0.5 + half(approx_dist));
845 }
846 return inColor * alpha;
847 }
848 )");
849
850 float invRXSqd;
851 float invRYSqd;
852 SkV2 scale = {1, 1};
853 // If we're using a scale factor to work around precision issues, choose the larger radius as
854 // the scale factor. The inv radii need to be pre-adjusted by the scale factor.
855 if (medPrecision) {
856 if (radii.fX > radii.fY) {
857 invRXSqd = 1.f;
858 invRYSqd = (radii.fX * radii.fX) / (radii.fY * radii.fY);
859 scale = {radii.fX, 1.f / radii.fX};
860 } else {
861 invRXSqd = (radii.fY * radii.fY) / (radii.fX * radii.fX);
862 invRYSqd = 1.f;
863 scale = {radii.fY, 1.f / radii.fY};
864 }
865 } else {
866 invRXSqd = 1.f / (radii.fX * radii.fX);
867 invRYSqd = 1.f / (radii.fY * radii.fY);
868 }
869 SkV4 ellipse = {center.fX, center.fY, invRXSqd, invRYSqd};
870
871 return GrFPSuccess(GrSkSLFP::Make(effect, "Ellipse", std::move(inputFP),
872 GrSkSLFP::OptFlags::kCompatibleWithCoverageAsAlpha,
873 "edgeType", GrSkSLFP::Specialize(static_cast<int>(edgeType)),
874 "medPrecision", GrSkSLFP::Specialize<int>(medPrecision),
875 "ellipse", ellipse,
876 "scale", scale));
877}
878
879//////////////////////////////////////////////////////////////////////////////
880
Brian Osman043f0102021-06-30 14:30:34 -0400881std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::HighPrecision(
882 std::unique_ptr<GrFragmentProcessor> fp) {
883 class HighPrecisionFragmentProcessor : public GrFragmentProcessor {
884 public:
885 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp) {
886 return std::unique_ptr<GrFragmentProcessor>(
887 new HighPrecisionFragmentProcessor(std::move(fp)));
888 }
889
890 const char* name() const override { return "HighPrecision"; }
891
892 std::unique_ptr<GrFragmentProcessor> clone() const override {
893 return Make(this->childProcessor(0)->clone());
894 }
895
896 private:
897 HighPrecisionFragmentProcessor(std::unique_ptr<GrFragmentProcessor> fp)
898 : INHERITED(kHighPrecisionFragmentProcessor_ClassID,
899 ProcessorOptimizationFlags(fp.get())) {
900 this->registerChild(std::move(fp));
901 }
902
Brian Salomon3176e862021-08-09 11:23:04 -0400903 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
Brian Salomonb25560a2021-08-10 13:56:13 -0400904 class Impl : public ProgramImpl {
Brian Osman043f0102021-06-30 14:30:34 -0400905 public:
906 void emitCode(EmitArgs& args) override {
907 SkString childColor = this->invokeChild(0, args);
908
909 args.fFragBuilder->forceHighPrecision();
910 args.fFragBuilder->codeAppendf("return %s;", childColor.c_str());
911 }
912 };
Brian Salomonb25560a2021-08-10 13:56:13 -0400913 return std::make_unique<Impl>();
Brian Osman043f0102021-06-30 14:30:34 -0400914 }
915
Brian Salomon13b28732021-08-06 15:33:58 -0400916 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
Brian Osman043f0102021-06-30 14:30:34 -0400917 bool onIsEqual(const GrFragmentProcessor& other) const override { return true; }
918
919 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
920 return ConstantOutputForConstantInput(this->childProcessor(0), input);
921 }
922
923 using INHERITED = GrFragmentProcessor;
924 };
925
926 return HighPrecisionFragmentProcessor::Make(std::move(fp));
927}