blob: dc1357b402de0ce8eecd94b7fabce8be57792f25 [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(
65 const std::function<void(const GrFragmentProcessor&, GrGLSLFragmentProcessor&)>& f,
66 GrGLSLFragmentProcessor& impl) const {
67 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 Salomon18ab2032021-02-23 10:07:05 -0500114std::unique_ptr<GrGLSLFragmentProcessor> GrFragmentProcessor::makeProgramImpl() const {
115 std::unique_ptr<GrGLSLFragmentProcessor> glFragProc = this->onMakeProgramImpl();
bsalomonbf877302015-09-22 09:06:13 -0700116 glFragProc->fChildProcessors.push_back_n(fChildProcessors.count());
117 for (int i = 0; i < fChildProcessors.count(); ++i) {
Brian Salomon18ab2032021-02-23 10:07:05 -0500118 glFragProc->fChildProcessors[i] = fChildProcessors[i]
119 ? fChildProcessors[i]->makeProgramImpl()
120 : nullptr;
bsalomonbf877302015-09-22 09:06:13 -0700121 }
122 return glFragProc;
123}
124
Brian Osman12c5d292020-07-13 16:11:35 -0400125int GrFragmentProcessor::numNonNullChildProcessors() const {
126 return std::count_if(fChildProcessors.begin(), fChildProcessors.end(),
127 [](const auto& c) { return c != nullptr; });
128}
129
Robert Phillips82774f82019-06-20 14:38:27 -0400130#ifdef SK_DEBUG
131bool GrFragmentProcessor::isInstantiated() const {
Brian Salomond90b3d32020-07-09 12:04:31 -0400132 bool result = true;
133 this->visitTextureEffects([&result](const GrTextureEffect& te) {
134 if (!te.texture()) {
135 result = false;
Brian Salomone782f842018-07-31 13:53:11 -0400136 }
Brian Salomond90b3d32020-07-09 12:04:31 -0400137 });
138 return result;
Robert Phillips9bee2e52017-05-29 12:37:20 -0400139}
Robert Phillips82774f82019-06-20 14:38:27 -0400140#endif
Robert Phillips9bee2e52017-05-29 12:37:20 -0400141
Brian Osman12c5d292020-07-13 16:11:35 -0400142void GrFragmentProcessor::registerChild(std::unique_ptr<GrFragmentProcessor> child,
143 SkSL::SampleUsage sampleUsage) {
Brian Osman54867de2020-07-10 14:22:57 -0400144 if (!child) {
Brian Osman12c5d292020-07-13 16:11:35 -0400145 fChildProcessors.push_back(nullptr);
146 return;
Brian Osman54867de2020-07-10 14:22:57 -0400147 }
148
Michael Ludwige88320b2020-06-24 09:04:56 -0400149 // The child should not have been attached to another FP already and not had any sampling
150 // strategy set on it.
Brian Salomon66b500a2021-08-02 12:37:14 -0400151 SkASSERT(!child->fParent && !child->sampleUsage().isSampled());
Michael Ludwige88320b2020-06-24 09:04:56 -0400152
Michael Ludwig9aba6252020-06-22 14:46:36 -0400153 // Configure child's sampling state first
Brian Osman1298bc42020-06-30 13:39:35 -0400154 child->fUsage = sampleUsage;
155
John Stilese69f25f2021-06-03 12:23:33 -0400156 // Propagate the "will read dest-color" flag up to parent FPs.
John Stilesbc4bc5f2021-06-11 16:43:15 -0400157 if (child->willReadDstColor()) {
158 this->setWillReadDstColor();
John Stilese69f25f2021-06-03 12:23:33 -0400159 }
160
Brian Salomon66b500a2021-08-02 12:37:14 -0400161 // If this child receives passthrough or matrix transformed coords from its parent then note
162 // that the parent's coords are used indirectly to ensure that they aren't omitted.
163 if ((sampleUsage.isPassThrough() || sampleUsage.isUniformMatrix()) &&
164 child->usesSampleCoords()) {
165 fFlags |= kUsesSampleCoordsIndirectly_Flag;
Michael Ludwige88320b2020-06-24 09:04:56 -0400166 }
167
Chris Daltond7291ba2019-03-07 14:17:03 -0700168 fRequestedFeatures |= child->fRequestedFeatures;
bsalomonbf877302015-09-22 09:06:13 -0700169
Michael Ludwige88320b2020-06-24 09:04:56 -0400170 // Record that the child is attached to us; this FP is the source of any uniform data needed
171 // to evaluate the child sample matrix.
172 child->fParent = this;
Brian Salomonaff329b2017-08-11 09:40:37 -0400173 fChildProcessors.push_back(std::move(child));
Michael Ludwige88320b2020-06-24 09:04:56 -0400174
Leon Scroggins III982fff22020-07-31 14:09:06 -0400175 // Validate: our sample strategy comes from a parent we shouldn't have yet.
Brian Salomon66b500a2021-08-02 12:37:14 -0400176 SkASSERT(!fUsage.isSampled() && !fParent);
John Stiles3779f442020-06-15 10:48:49 -0400177}
178
John Stiles9ec6b052020-06-15 12:06:10 -0400179void GrFragmentProcessor::cloneAndRegisterAllChildProcessors(const GrFragmentProcessor& src) {
180 for (int i = 0; i < src.numChildProcessors(); ++i) {
Brian Osman12c5d292020-07-13 16:11:35 -0400181 if (auto fp = src.childProcessor(i)) {
182 this->registerChild(fp->clone(), fp->sampleUsage());
183 } else {
184 this->registerChild(nullptr);
185 }
John Stiles9ec6b052020-06-15 12:06:10 -0400186 }
187}
188
Brian Salomon354147a2021-04-14 11:15:05 -0400189std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::MakeColor(SkPMColor4f color) {
Brian Osman4cd134c2021-04-28 17:25:31 -0400190 // Use ColorFilter signature/factory to get the constant output for constant input optimization
Brian Osmand1b530a2021-05-25 16:09:16 -0400191 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
Brian Salomon354147a2021-04-14 11:15:05 -0400192 uniform half4 color;
Brian Osman4cd134c2021-04-28 17:25:31 -0400193 half4 main(half4 inColor) { return color; }
Brian Osmand1b530a2021-05-25 16:09:16 -0400194 )");
Brian Osmanbe545c92021-06-18 09:41:15 -0400195 SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
Brian Osman171fba72021-06-16 17:10:21 -0400196 return GrSkSLFP::Make(effect, "color_fp", /*inputFP=*/nullptr,
197 color.isOpaque() ? GrSkSLFP::OptFlags::kPreservesOpaqueInput
198 : GrSkSLFP::OptFlags::kNone,
199 "color", color);
Brian Salomon354147a2021-04-14 11:15:05 -0400200}
201
Mike Reed28eaed22018-02-01 11:24:53 -0500202std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::MulChildByInputAlpha(
Brian Salomonaff329b2017-08-11 09:40:37 -0400203 std::unique_ptr<GrFragmentProcessor> fp) {
bsalomonf1b7a1d2015-09-28 06:26:28 -0700204 if (!fp) {
205 return nullptr;
206 }
Brian Salomon4b6e2f02021-07-08 14:04:21 -0400207 return GrBlendFragmentProcessor::Make(/*src=*/nullptr,
208 OverrideInput(std::move(fp), SK_PMColor4fWHITE),
209 SkBlendMode::kDstIn);
bsalomonbf877302015-09-22 09:06:13 -0700210}
211
Mike Reed28eaed22018-02-01 11:24:53 -0500212std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::MulInputByChildAlpha(
213 std::unique_ptr<GrFragmentProcessor> fp) {
214 if (!fp) {
215 return nullptr;
216 }
Brian Salomon4b6e2f02021-07-08 14:04:21 -0400217 return GrBlendFragmentProcessor::Make(/*src=*/nullptr,
218 OverrideInput(std::move(fp), SK_PMColor4fWHITE),
219 SkBlendMode::kSrcIn);
Mike Reed28eaed22018-02-01 11:24:53 -0500220}
221
John Stiles7bf26002020-07-13 11:30:12 -0400222std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::ModulateAlpha(
223 std::unique_ptr<GrFragmentProcessor> inputFP, const SkPMColor4f& color) {
Brian Salomon354147a2021-04-14 11:15:05 -0400224 auto colorFP = MakeColor(color);
Brian Salomon4b6e2f02021-07-08 14:04:21 -0400225 return GrBlendFragmentProcessor::Make(std::move(colorFP),
226 std::move(inputFP),
227 SkBlendMode::kSrcIn);
John Stiles7bf26002020-07-13 11:30:12 -0400228}
229
John Stiles85894302020-07-13 11:39:52 -0400230std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::ModulateRGBA(
231 std::unique_ptr<GrFragmentProcessor> inputFP, const SkPMColor4f& color) {
Brian Salomon354147a2021-04-14 11:15:05 -0400232 auto colorFP = MakeColor(color);
Brian Salomon4b6e2f02021-07-08 14:04:21 -0400233 return GrBlendFragmentProcessor::Make(std::move(colorFP),
234 std::move(inputFP),
235 SkBlendMode::kModulate);
John Stiles85894302020-07-13 11:39:52 -0400236}
237
Brian Osman8e814b32021-06-17 14:14:26 -0400238std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::ClampOutput(
239 std::unique_ptr<GrFragmentProcessor> fp) {
240 SkASSERT(fp);
241 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
242 half4 main(half4 inColor) {
243 return saturate(inColor);
244 }
245 )");
Brian Osmanbe545c92021-06-18 09:41:15 -0400246 SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
Brian Osman8e814b32021-06-17 14:14:26 -0400247 return GrSkSLFP::Make(
248 effect, "Clamp", std::move(fp), GrSkSLFP::OptFlags::kPreservesOpaqueInput);
249}
250
Brian Osman6f5e9402020-01-22 10:39:31 -0500251std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::ClampPremulOutput(
252 std::unique_ptr<GrFragmentProcessor> fp) {
Brian Osman8e814b32021-06-17 14:14:26 -0400253 SkASSERT(fp);
254 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
255 half4 main(half4 inColor) {
256 half alpha = saturate(inColor.a);
257 return half4(clamp(inColor.rgb, 0, alpha), alpha);
258 }
259 )");
Brian Osmanbe545c92021-06-18 09:41:15 -0400260 SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
Brian Osman8e814b32021-06-17 14:14:26 -0400261 return GrSkSLFP::Make(
262 effect, "ClampPremul", std::move(fp), GrSkSLFP::OptFlags::kPreservesOpaqueInput);
Brian Osman6f5e9402020-01-22 10:39:31 -0500263}
264
Brian Salomonaff329b2017-08-11 09:40:37 -0400265std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::SwizzleOutput(
266 std::unique_ptr<GrFragmentProcessor> fp, const GrSwizzle& swizzle) {
Brian Osmance425512017-03-22 14:37:50 -0400267 class SwizzleFragmentProcessor : public GrFragmentProcessor {
268 public:
John Stileseed56f02020-06-04 13:30:51 -0400269 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp,
270 const GrSwizzle& swizzle) {
271 return std::unique_ptr<GrFragmentProcessor>(
John Stiles4bdc1212020-12-14 18:04:13 -0500272 new SwizzleFragmentProcessor(std::move(fp), swizzle));
Brian Osmance425512017-03-22 14:37:50 -0400273 }
274
275 const char* name() const override { return "Swizzle"; }
276 const GrSwizzle& swizzle() const { return fSwizzle; }
277
John Stileseed56f02020-06-04 13:30:51 -0400278 std::unique_ptr<GrFragmentProcessor> clone() const override {
Brian Osman12c5d292020-07-13 16:11:35 -0400279 return Make(this->childProcessor(0)->clone(), fSwizzle);
John Stileseed56f02020-06-04 13:30:51 -0400280 }
Brian Salomon216f2e02017-07-25 15:52:51 -0400281
Brian Osmance425512017-03-22 14:37:50 -0400282 private:
John Stileseed56f02020-06-04 13:30:51 -0400283 SwizzleFragmentProcessor(std::unique_ptr<GrFragmentProcessor> fp, const GrSwizzle& swizzle)
284 : INHERITED(kSwizzleFragmentProcessor_ClassID, ProcessorOptimizationFlags(fp.get()))
285 , fSwizzle(swizzle) {
Michael Ludwig9aba6252020-06-22 14:46:36 -0400286 this->registerChild(std::move(fp));
John Stileseed56f02020-06-04 13:30:51 -0400287 }
Robert Phillips1c9686b2017-06-30 08:40:28 -0400288
Brian Salomon18ab2032021-02-23 10:07:05 -0500289 std::unique_ptr<GrGLSLFragmentProcessor> onMakeProgramImpl() const override {
Brian Osmance425512017-03-22 14:37:50 -0400290 class GLFP : public GrGLSLFragmentProcessor {
291 public:
292 void emitCode(EmitArgs& args) override {
Brian Osman6b5dbb42020-07-15 15:31:05 -0400293 SkString childColor = this->invokeChild(0, args);
John Stileseed56f02020-06-04 13:30:51 -0400294
Brian Osmance425512017-03-22 14:37:50 -0400295 const SwizzleFragmentProcessor& sfp = args.fFp.cast<SwizzleFragmentProcessor>();
296 const GrSwizzle& swizzle = sfp.swizzle();
297 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
298
John Stiles4bdc1212020-12-14 18:04:13 -0500299 fragBuilder->codeAppendf("return %s.%s;",
300 childColor.c_str(), swizzle.asString().c_str());
Brian Osmance425512017-03-22 14:37:50 -0400301 }
302 };
Brian Salomon18ab2032021-02-23 10:07:05 -0500303 return std::make_unique<GLFP>();
Brian Osmance425512017-03-22 14:37:50 -0400304 }
305
Brian Salomon13b28732021-08-06 15:33:58 -0400306 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
Brian Osmance425512017-03-22 14:37:50 -0400307 b->add32(fSwizzle.asKey());
308 }
309
310 bool onIsEqual(const GrFragmentProcessor& other) const override {
311 const SwizzleFragmentProcessor& sfp = other.cast<SwizzleFragmentProcessor>();
312 return fSwizzle == sfp.fSwizzle;
313 }
314
Brian Osman1d5b5982018-10-01 13:41:39 -0400315 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
Brian Osman36f3d1a2021-03-22 16:36:14 -0400316 return fSwizzle.applyTo(ConstantOutputForConstantInput(this->childProcessor(0), input));
Brian Osmance425512017-03-22 14:37:50 -0400317 }
318
319 GrSwizzle fSwizzle;
320
John Stiles7571f9e2020-09-02 22:42:33 -0400321 using INHERITED = GrFragmentProcessor;
Brian Osmance425512017-03-22 14:37:50 -0400322 };
323
324 if (!fp) {
325 return nullptr;
326 }
327 if (GrSwizzle::RGBA() == swizzle) {
328 return fp;
329 }
John Stileseed56f02020-06-04 13:30:51 -0400330 return SwizzleFragmentProcessor::Make(std::move(fp), swizzle);
Brian Osmance425512017-03-22 14:37:50 -0400331}
332
Brian Salomonaff329b2017-08-11 09:40:37 -0400333std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::MakeInputPremulAndMulByOutput(
334 std::unique_ptr<GrFragmentProcessor> fp) {
bsalomonf1b7a1d2015-09-28 06:26:28 -0700335 class PremulFragmentProcessor : public GrFragmentProcessor {
336 public:
Brian Salomonaff329b2017-08-11 09:40:37 -0400337 static std::unique_ptr<GrFragmentProcessor> Make(
338 std::unique_ptr<GrFragmentProcessor> processor) {
339 return std::unique_ptr<GrFragmentProcessor>(
340 new PremulFragmentProcessor(std::move(processor)));
Robert Phillips1c9686b2017-06-30 08:40:28 -0400341 }
342
343 const char* name() const override { return "Premultiply"; }
344
Brian Salomonaff329b2017-08-11 09:40:37 -0400345 std::unique_ptr<GrFragmentProcessor> clone() const override {
Brian Osman12c5d292020-07-13 16:11:35 -0400346 return Make(this->childProcessor(0)->clone());
Brian Salomon216f2e02017-07-25 15:52:51 -0400347 }
348
Robert Phillips1c9686b2017-06-30 08:40:28 -0400349 private:
Brian Salomonaff329b2017-08-11 09:40:37 -0400350 PremulFragmentProcessor(std::unique_ptr<GrFragmentProcessor> processor)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400351 : INHERITED(kPremulFragmentProcessor_ClassID, OptFlags(processor.get())) {
Michael Ludwig9aba6252020-06-22 14:46:36 -0400352 this->registerChild(std::move(processor));
bsalomonf1b7a1d2015-09-28 06:26:28 -0700353 }
354
Brian Salomon18ab2032021-02-23 10:07:05 -0500355 std::unique_ptr<GrGLSLFragmentProcessor> onMakeProgramImpl() const override {
egdaniel64c47282015-11-13 06:54:19 -0800356 class GLFP : public GrGLSLFragmentProcessor {
bsalomonf1b7a1d2015-09-28 06:26:28 -0700357 public:
bsalomonf1b7a1d2015-09-28 06:26:28 -0700358 void emitCode(EmitArgs& args) override {
cdalton85285412016-02-18 12:37:07 -0800359 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
John Stiles4bdc1212020-12-14 18:04:13 -0500360 SkString temp = this->invokeChild(/*childIndex=*/0, "half4(1)", args);
361 fragBuilder->codeAppendf("half4 color = %s;", temp.c_str());
362 fragBuilder->codeAppendf("color.rgb *= %s.rgb;", args.fInputColor);
363 fragBuilder->codeAppendf("return color * %s.a;", args.fInputColor);
bsalomonf1b7a1d2015-09-28 06:26:28 -0700364 }
365 };
Brian Salomon18ab2032021-02-23 10:07:05 -0500366 return std::make_unique<GLFP>();
bsalomonf1b7a1d2015-09-28 06:26:28 -0700367 }
368
Brian Salomon13b28732021-08-06 15:33:58 -0400369 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
bsalomonf1b7a1d2015-09-28 06:26:28 -0700370
371 bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
372
Brian Salomon587e08f2017-01-27 10:59:27 -0500373 static OptimizationFlags OptFlags(const GrFragmentProcessor* inner) {
374 OptimizationFlags flags = kNone_OptimizationFlags;
375 if (inner->preservesOpaqueInput()) {
376 flags |= kPreservesOpaqueInput_OptimizationFlag;
377 }
378 if (inner->hasConstantOutputForConstantInput()) {
379 flags |= kConstantOutputForConstantInput_OptimizationFlag;
380 }
381 return flags;
382 }
bsalomonf1b7a1d2015-09-28 06:26:28 -0700383
Brian Osman1d5b5982018-10-01 13:41:39 -0400384 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
385 SkPMColor4f childColor = ConstantOutputForConstantInput(this->childProcessor(0),
Brian Osmanf28e55d2018-10-03 16:35:54 -0400386 SK_PMColor4fWHITE);
Brian Osman1d5b5982018-10-01 13:41:39 -0400387 SkPMColor4f premulInput = SkColor4f{ input.fR, input.fG, input.fB, input.fA }.premul();
388 return premulInput * childColor;
Brian Salomon587e08f2017-01-27 10:59:27 -0500389 }
390
John Stiles7571f9e2020-09-02 22:42:33 -0400391 using INHERITED = GrFragmentProcessor;
bsalomonf1b7a1d2015-09-28 06:26:28 -0700392 };
393 if (!fp) {
394 return nullptr;
395 }
Robert Phillips1c9686b2017-06-30 08:40:28 -0400396 return PremulFragmentProcessor::Make(std::move(fp));
bsalomonf1b7a1d2015-09-28 06:26:28 -0700397}
398
399//////////////////////////////////////////////////////////////////////////////
400
Brian Salomonaff329b2017-08-11 09:40:37 -0400401std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::OverrideInput(
Brian Salomonc0d79e52019-04-10 15:02:11 -0400402 std::unique_ptr<GrFragmentProcessor> fp, const SkPMColor4f& color, bool useUniform) {
Robert Phillips1c9686b2017-06-30 08:40:28 -0400403 if (!fp) {
404 return nullptr;
405 }
Brian Osman59465892021-06-18 09:15:44 -0400406 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
407 uniform colorFilter fp; // Declared as colorFilter so we can use sample(..., color)
408 uniform half4 color;
409 half4 main(half4 inColor) {
410 return sample(fp, color);
411 }
412 )");
413 SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
414 return GrSkSLFP::Make(effect, "OverrideInput", /*inputFP=*/nullptr,
415 color.isOpaque() ? GrSkSLFP::OptFlags::kPreservesOpaqueInput
416 : GrSkSLFP::OptFlags::kNone,
417 "fp", std::move(fp),
418 "color", GrSkSLFP::SpecializeIf(!useUniform, color));
bsalomonf1b7a1d2015-09-28 06:26:28 -0700419}
bsalomone25eea42015-09-29 06:38:55 -0700420
John Stiles024d7452020-07-22 19:07:15 -0400421//////////////////////////////////////////////////////////////////////////////
422
John Stiles2a6f73c2021-07-29 19:36:20 -0400423std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::UseDestColorAsInput(
424 std::unique_ptr<GrFragmentProcessor> fp) {
425 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForBlender, R"(
426 uniform colorFilter fp; // Declared as colorFilter so we can use sample(..., color)
427 half4 main(half4 src, half4 dst) {
428 return sample(fp, dst);
429 }
430 )");
431 return GrSkSLFP::Make(effect, "UseDestColorAsInput", /*inputFP=*/nullptr,
432 GrSkSLFP::OptFlags::kNone, "fp", std::move(fp));
433}
434
435//////////////////////////////////////////////////////////////////////////////
436
Brian Salomon25af4802021-07-07 16:24:16 -0400437std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::MakeInputOpaqueAndPostApplyAlpha(
438 std::unique_ptr<GrFragmentProcessor> fp) {
439 if (!fp) {
440 return nullptr;
441 }
442 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
443 uniform colorFilter fp; // Declared as colorFilter so we can use sample(..., color)
444 half4 main(half4 inColor) {
445 return inColor.a * sample(fp, unpremul(inColor).rgb1);
446 }
447 )");
448 return GrSkSLFP::Make(effect,
449 "MakeInputOpaque",
450 /*inputFP=*/nullptr,
451 GrSkSLFP::OptFlags::kPreservesOpaqueInput,
452 "fp", std::move(fp));
453}
454
455//////////////////////////////////////////////////////////////////////////////
456
John Stiles024d7452020-07-22 19:07:15 -0400457std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::Compose(
458 std::unique_ptr<GrFragmentProcessor> f, std::unique_ptr<GrFragmentProcessor> g) {
459 class ComposeProcessor : public GrFragmentProcessor {
460 public:
461 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> f,
462 std::unique_ptr<GrFragmentProcessor> g) {
463 return std::unique_ptr<GrFragmentProcessor>(new ComposeProcessor(std::move(f),
464 std::move(g)));
465 }
466
467 const char* name() const override { return "Compose"; }
468
469 std::unique_ptr<GrFragmentProcessor> clone() const override {
470 return std::unique_ptr<GrFragmentProcessor>(new ComposeProcessor(*this));
471 }
472
473 private:
Brian Salomon18ab2032021-02-23 10:07:05 -0500474 std::unique_ptr<GrGLSLFragmentProcessor> onMakeProgramImpl() const override {
John Stiles024d7452020-07-22 19:07:15 -0400475 class GLFP : public GrGLSLFragmentProcessor {
476 public:
477 void emitCode(EmitArgs& args) override {
Brian Osmanc5422d02021-03-12 16:06:35 -0500478 SkString result = this->invokeChild(1, args); // g(x)
479 result = this->invokeChild(0, result.c_str(), args); // f(g(x))
John Stiles49643002020-10-19 18:52:40 -0400480 args.fFragBuilder->codeAppendf("return %s;", result.c_str());
John Stiles024d7452020-07-22 19:07:15 -0400481 }
482 };
Brian Salomon18ab2032021-02-23 10:07:05 -0500483 return std::make_unique<GLFP>();
John Stiles024d7452020-07-22 19:07:15 -0400484 }
485
486 ComposeProcessor(std::unique_ptr<GrFragmentProcessor> f,
487 std::unique_ptr<GrFragmentProcessor> g)
488 : INHERITED(kSeriesFragmentProcessor_ClassID,
489 f->optimizationFlags() & g->optimizationFlags()) {
490 this->registerChild(std::move(f));
491 this->registerChild(std::move(g));
492 }
493
494 ComposeProcessor(const ComposeProcessor& that)
495 : INHERITED(kSeriesFragmentProcessor_ClassID, that.optimizationFlags()) {
496 this->cloneAndRegisterAllChildProcessors(that);
497 }
498
Brian Salomon13b28732021-08-06 15:33:58 -0400499 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
John Stiles024d7452020-07-22 19:07:15 -0400500
501 bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
502
503 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override {
504 SkPMColor4f color = inColor;
John Stiles024d7452020-07-22 19:07:15 -0400505 color = ConstantOutputForConstantInput(this->childProcessor(1), color);
Brian Osmanc5422d02021-03-12 16:06:35 -0500506 color = ConstantOutputForConstantInput(this->childProcessor(0), color);
John Stiles024d7452020-07-22 19:07:15 -0400507 return color;
508 }
509
John Stiles7571f9e2020-09-02 22:42:33 -0400510 using INHERITED = GrFragmentProcessor;
John Stiles024d7452020-07-22 19:07:15 -0400511 };
512
513 // Allow either of the composed functions to be null.
514 if (f == nullptr) {
515 return g;
516 }
517 if (g == nullptr) {
518 return f;
519 }
520
521 // Run an optimization pass on this composition.
522 GrProcessorAnalysisColor inputColor;
523 inputColor.setToUnknown();
524
Brian Osmanc5422d02021-03-12 16:06:35 -0500525 std::unique_ptr<GrFragmentProcessor> series[2] = {std::move(g), std::move(f)};
John Stiles024d7452020-07-22 19:07:15 -0400526 GrColorFragmentProcessorAnalysis info(inputColor, series, SK_ARRAY_COUNT(series));
527
528 SkPMColor4f knownColor;
529 int leadingFPsToEliminate = info.initialProcessorsToEliminate(&knownColor);
530 switch (leadingFPsToEliminate) {
531 default:
532 // We shouldn't eliminate more than we started with.
533 SkASSERT(leadingFPsToEliminate <= 2);
534 [[fallthrough]];
535 case 0:
536 // Compose the two processors as requested.
Brian Osmanc5422d02021-03-12 16:06:35 -0500537 return ComposeProcessor::Make(/*f=*/std::move(series[1]), /*g=*/std::move(series[0]));
John Stiles024d7452020-07-22 19:07:15 -0400538 case 1:
539 // Replace the first processor with a constant color.
Brian Osmanc5422d02021-03-12 16:06:35 -0500540 return ComposeProcessor::Make(/*f=*/std::move(series[1]),
Brian Salomon354147a2021-04-14 11:15:05 -0400541 /*g=*/MakeColor(knownColor));
John Stiles024d7452020-07-22 19:07:15 -0400542 case 2:
543 // Replace the entire composition with a constant color.
Brian Salomon354147a2021-04-14 11:15:05 -0400544 return MakeColor(knownColor);
John Stiles024d7452020-07-22 19:07:15 -0400545 }
546}
547
548//////////////////////////////////////////////////////////////////////////////
549
Brian Osman48f83fd2021-06-23 15:51:26 +0000550std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::ColorMatrix(
551 std::unique_ptr<GrFragmentProcessor> child,
552 const float matrix[20],
553 bool unpremulInput,
554 bool clampRGBOutput,
555 bool premulOutput) {
556 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
557 uniform half4x4 m;
558 uniform half4 v;
559 uniform int unpremulInput; // always specialized
560 uniform int clampRGBOutput; // always specialized
561 uniform int premulOutput; // always specialized
562 half4 main(half4 color) {
563 if (bool(unpremulInput)) {
564 color = unpremul(color);
565 }
566 color = m * color + v;
567 if (bool(clampRGBOutput)) {
568 color = saturate(color);
569 } else {
570 color.a = saturate(color.a);
571 }
572 if (bool(premulOutput)) {
573 color.rgb *= color.a;
574 }
575 return color;
576 }
577 )");
578 SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
579
580 SkM44 m44(matrix[ 0], matrix[ 1], matrix[ 2], matrix[ 3],
581 matrix[ 5], matrix[ 6], matrix[ 7], matrix[ 8],
582 matrix[10], matrix[11], matrix[12], matrix[13],
583 matrix[15], matrix[16], matrix[17], matrix[18]);
584 SkV4 v4 = {matrix[4], matrix[9], matrix[14], matrix[19]};
585 return GrSkSLFP::Make(effect, "ColorMatrix", std::move(child), GrSkSLFP::OptFlags::kNone,
586 "m", m44,
587 "v", v4,
588 "unpremulInput", GrSkSLFP::Specialize(unpremulInput ? 1 : 0),
589 "clampRGBOutput", GrSkSLFP::Specialize(clampRGBOutput ? 1 : 0),
590 "premulOutput", GrSkSLFP::Specialize(premulOutput ? 1 : 0));
591}
592
593//////////////////////////////////////////////////////////////////////////////
594
John Stiles5b3aff42021-07-29 17:20:22 -0400595std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::SurfaceColor() {
596 class SurfaceColorProcessor : public GrFragmentProcessor {
John Stilesbb04e3d2021-06-04 12:09:11 -0400597 public:
598 static std::unique_ptr<GrFragmentProcessor> Make() {
John Stiles5b3aff42021-07-29 17:20:22 -0400599 return std::unique_ptr<GrFragmentProcessor>(new SurfaceColorProcessor());
John Stilesbb04e3d2021-06-04 12:09:11 -0400600 }
601
602 std::unique_ptr<GrFragmentProcessor> clone() const override { return Make(); }
603
John Stiles5b3aff42021-07-29 17:20:22 -0400604 const char* name() const override { return "SurfaceColor"; }
John Stilesbb04e3d2021-06-04 12:09:11 -0400605
606 private:
607 std::unique_ptr<GrGLSLFragmentProcessor> onMakeProgramImpl() const override {
608 class GLFP : public GrGLSLFragmentProcessor {
609 public:
610 void emitCode(EmitArgs& args) override {
John Stiles5b3aff42021-07-29 17:20:22 -0400611 const char* dstColor = args.fFragBuilder->dstColor();
612 args.fFragBuilder->codeAppendf("return %s;", dstColor);
John Stilesbb04e3d2021-06-04 12:09:11 -0400613 }
614 };
615 return std::make_unique<GLFP>();
616 }
617
John Stiles5b3aff42021-07-29 17:20:22 -0400618 SurfaceColorProcessor()
619 : INHERITED(kSurfaceColorProcessor_ClassID, kNone_OptimizationFlags) {
John Stilesbc4bc5f2021-06-11 16:43:15 -0400620 this->setWillReadDstColor();
John Stilesbb04e3d2021-06-04 12:09:11 -0400621 }
622
Brian Salomon13b28732021-08-06 15:33:58 -0400623 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
John Stilesbb04e3d2021-06-04 12:09:11 -0400624
625 bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
626
627 using INHERITED = GrFragmentProcessor;
628 };
629
John Stiles5b3aff42021-07-29 17:20:22 -0400630 return SurfaceColorProcessor::Make();
John Stilesbb04e3d2021-06-04 12:09:11 -0400631}
632
633//////////////////////////////////////////////////////////////////////////////
634
Brian Osman62905552021-06-21 13:11:01 -0400635std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::DeviceSpace(
636 std::unique_ptr<GrFragmentProcessor> fp) {
Brian Salomon4f8d4be2021-07-30 18:21:32 -0400637 if (!fp) {
638 return nullptr;
639 }
640
641 class DeviceSpace : GrFragmentProcessor {
642 public:
643 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp) {
644 return std::unique_ptr<GrFragmentProcessor>(new DeviceSpace(std::move(fp)));
Brian Osman62905552021-06-21 13:11:01 -0400645 }
Brian Salomon4f8d4be2021-07-30 18:21:32 -0400646
647 private:
648 DeviceSpace(std::unique_ptr<GrFragmentProcessor> fp)
649 : GrFragmentProcessor(kDeviceSpace_ClassID, fp->optimizationFlags()) {
Brian Salomon9eca2ca2021-08-02 13:04:04 -0400650 // Passing FragCoord here is the reason this is a subclass and not a runtime-FP.
651 this->registerChild(std::move(fp), SkSL::SampleUsage::FragCoord());
Brian Salomon4f8d4be2021-07-30 18:21:32 -0400652 }
653
654 std::unique_ptr<GrFragmentProcessor> clone() const override {
655 auto child = this->childProcessor(0)->clone();
656 return std::unique_ptr<GrFragmentProcessor>(new DeviceSpace(std::move(child)));
657 }
658
659 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& f) const override {
660 return this->childProcessor(0)->constantOutputForConstantInput(f);
661 }
662
663 std::unique_ptr<GrGLSLFragmentProcessor> onMakeProgramImpl() const override {
664 class Impl : public GrGLSLFragmentProcessor {
665 public:
666 Impl() = default;
667 void emitCode(GrGLSLFragmentProcessor::EmitArgs& args) override {
668 auto child = this->invokeChild(0, args.fInputColor, args, "sk_FragCoord.xy");
669 args.fFragBuilder->codeAppendf("return %s;", child.c_str());
670 }
671 };
672 return std::make_unique<Impl>();
673 }
674
Brian Salomon13b28732021-08-06 15:33:58 -0400675 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
Brian Salomon4f8d4be2021-07-30 18:21:32 -0400676
677 bool onIsEqual(const GrFragmentProcessor& processor) const override { return true; }
678
679 const char* name() const override { return "DeviceSpace"; }
680 };
681
682 return DeviceSpace::Make(std::move(fp));
Brian Osman62905552021-06-21 13:11:01 -0400683}
684
685//////////////////////////////////////////////////////////////////////////////
686
Brian Osmanb384eb22021-06-24 15:34:08 -0400687#define CLIP_EDGE_SKSL \
688 "const int kFillBW = 0;" \
689 "const int kFillAA = 1;" \
690 "const int kInverseFillBW = 2;" \
691 "const int kInverseFillAA = 3;"
692
693static_assert(static_cast<int>(GrClipEdgeType::kFillBW) == 0);
694static_assert(static_cast<int>(GrClipEdgeType::kFillAA) == 1);
695static_assert(static_cast<int>(GrClipEdgeType::kInverseFillBW) == 2);
696static_assert(static_cast<int>(GrClipEdgeType::kInverseFillAA) == 3);
697
698std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::Rect(
699 std::unique_ptr<GrFragmentProcessor> inputFP, GrClipEdgeType edgeType, SkRect rect) {
700 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, CLIP_EDGE_SKSL R"(
701 uniform int edgeType; // GrClipEdgeType, specialized
702 uniform float4 rectUniform;
703
704 half4 main(float2 xy, half4 inColor) {
705 half coverage;
706 if (edgeType == kFillBW || edgeType == kInverseFillBW) {
707 // non-AA
708 coverage = all(greaterThan(float4(sk_FragCoord.xy, rectUniform.zw),
709 float4(rectUniform.xy, sk_FragCoord.xy))) ? 1 : 0;
710 } else {
711 // compute coverage relative to left and right edges, add, then subtract 1 to
712 // account for double counting. And similar for top/bottom.
713 half4 dists4 = clamp(half4(1, 1, -1, -1) *
714 half4(sk_FragCoord.xyxy - rectUniform), 0, 1);
715 half2 dists2 = dists4.xy + dists4.zw - 1;
716 coverage = dists2.x * dists2.y;
717 }
718
719 if (edgeType == kInverseFillBW || edgeType == kInverseFillAA) {
720 coverage = 1.0 - coverage;
721 }
722
723 return inColor * coverage;
724 }
725 )");
726
727 SkASSERT(rect.isSorted());
728 // The AA math in the shader evaluates to 0 at the uploaded coordinates, so outset by 0.5
729 // 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 -0400730 SkRect rectUniform = GrClipEdgeTypeIsAA(edgeType) ? rect.makeOutset(.5f, .5f) : rect;
Brian Osmanb384eb22021-06-24 15:34:08 -0400731
732 return GrSkSLFP::Make(effect, "Rect", std::move(inputFP),
733 GrSkSLFP::OptFlags::kCompatibleWithCoverageAsAlpha,
734 "edgeType", GrSkSLFP::Specialize(static_cast<int>(edgeType)),
735 "rectUniform", rectUniform);
736}
737
738GrFPResult GrFragmentProcessor::Circle(std::unique_ptr<GrFragmentProcessor> inputFP,
739 GrClipEdgeType edgeType,
740 SkPoint center,
741 float radius) {
742 // A radius below half causes the implicit insetting done by this processor to become
743 // inverted. We could handle this case by making the processor code more complicated.
Brian Osman50f0dad2021-07-08 13:47:25 -0400744 if (radius < .5f && GrClipEdgeTypeIsInverseFill(edgeType)) {
Brian Osmanb384eb22021-06-24 15:34:08 -0400745 return GrFPFailure(std::move(inputFP));
746 }
747
748 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, CLIP_EDGE_SKSL R"(
749 uniform int edgeType; // GrClipEdgeType, specialized
750 // The circle uniform is (center.x, center.y, radius + 0.5, 1 / (radius + 0.5)) for regular
751 // fills and (..., radius - 0.5, 1 / (radius - 0.5)) for inverse fills.
752 uniform float4 circle;
753
754 half4 main(float2 xy, half4 inColor) {
755 // TODO: Right now the distance to circle calculation is performed in a space normalized
756 // to the radius and then denormalized. This is to mitigate overflow on devices that
757 // don't have full float.
758 half d;
759 if (edgeType == kInverseFillBW || edgeType == kInverseFillAA) {
760 d = half((length((circle.xy - sk_FragCoord.xy) * circle.w) - 1.0) * circle.z);
761 } else {
762 d = half((1.0 - length((circle.xy - sk_FragCoord.xy) * circle.w)) * circle.z);
763 }
764 if (edgeType == kFillAA || edgeType == kInverseFillAA) {
765 return inColor * saturate(d);
766 } else {
767 return d > 0.5 ? inColor : half4(0);
768 }
769 }
770 )");
771
772 SkScalar effectiveRadius = radius;
Brian Osman50f0dad2021-07-08 13:47:25 -0400773 if (GrClipEdgeTypeIsInverseFill(edgeType)) {
Brian Osmanb384eb22021-06-24 15:34:08 -0400774 effectiveRadius -= 0.5f;
775 // When the radius is 0.5 effectiveRadius is 0 which causes an inf * 0 in the shader.
776 effectiveRadius = std::max(0.001f, effectiveRadius);
777 } else {
778 effectiveRadius += 0.5f;
779 }
780 SkV4 circle = {center.fX, center.fY, effectiveRadius, SkScalarInvert(effectiveRadius)};
781
782 return GrFPSuccess(GrSkSLFP::Make(effect, "Circle", std::move(inputFP),
783 GrSkSLFP::OptFlags::kCompatibleWithCoverageAsAlpha,
784 "edgeType", GrSkSLFP::Specialize(static_cast<int>(edgeType)),
785 "circle", circle));
786}
787
788GrFPResult GrFragmentProcessor::Ellipse(std::unique_ptr<GrFragmentProcessor> inputFP,
789 GrClipEdgeType edgeType,
790 SkPoint center,
791 SkPoint radii,
792 const GrShaderCaps& caps) {
793 const bool medPrecision = !caps.floatIs32Bits();
794
795 // Small radii produce bad results on devices without full float.
796 if (medPrecision && (radii.fX < 0.5f || radii.fY < 0.5f)) {
797 return GrFPFailure(std::move(inputFP));
798 }
799 // Very narrow ellipses produce bad results on devices without full float
800 if (medPrecision && (radii.fX > 255*radii.fY || radii.fY > 255*radii.fX)) {
801 return GrFPFailure(std::move(inputFP));
802 }
803 // Very large ellipses produce bad results on devices without full float
804 if (medPrecision && (radii.fX > 16384 || radii.fY > 16384)) {
805 return GrFPFailure(std::move(inputFP));
806 }
807
808 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, CLIP_EDGE_SKSL R"(
809 uniform int edgeType; // GrClipEdgeType, specialized
810 uniform int medPrecision; // !sk_Caps.floatIs32Bits, specialized
811
812 uniform float4 ellipse;
813 uniform float2 scale; // only for medPrecision
814
815 half4 main(float2 xy, half4 inColor) {
816 // d is the offset to the ellipse center
817 float2 d = sk_FragCoord.xy - ellipse.xy;
818 // If we're on a device with a "real" mediump then we'll do the distance computation in
819 // a space that is normalized by the larger radius or 128, whichever is smaller. The
820 // scale uniform will be scale, 1/scale. The inverse squared radii uniform values are
821 // already in this normalized space. The center is not.
822 if (bool(medPrecision)) {
823 d *= scale.y;
824 }
825 float2 Z = d * ellipse.zw;
826 // implicit is the evaluation of (x/rx)^2 + (y/ry)^2 - 1.
827 float implicit = dot(Z, d) - 1;
828 // grad_dot is the squared length of the gradient of the implicit.
829 float grad_dot = 4 * dot(Z, Z);
830 // Avoid calling inversesqrt on zero.
831 if (bool(medPrecision)) {
832 grad_dot = max(grad_dot, 6.1036e-5);
833 } else {
834 grad_dot = max(grad_dot, 1.1755e-38);
835 }
836 float approx_dist = implicit * inversesqrt(grad_dot);
837 if (bool(medPrecision)) {
838 approx_dist *= scale.x;
839 }
840
841 half alpha;
842 if (edgeType == kFillBW) {
843 alpha = approx_dist > 0.0 ? 0.0 : 1.0;
844 } else if (edgeType == kFillAA) {
845 alpha = saturate(0.5 - half(approx_dist));
846 } else if (edgeType == kInverseFillBW) {
847 alpha = approx_dist > 0.0 ? 1.0 : 0.0;
848 } else { // edgeType == kInverseFillAA
849 alpha = saturate(0.5 + half(approx_dist));
850 }
851 return inColor * alpha;
852 }
853 )");
854
855 float invRXSqd;
856 float invRYSqd;
857 SkV2 scale = {1, 1};
858 // If we're using a scale factor to work around precision issues, choose the larger radius as
859 // the scale factor. The inv radii need to be pre-adjusted by the scale factor.
860 if (medPrecision) {
861 if (radii.fX > radii.fY) {
862 invRXSqd = 1.f;
863 invRYSqd = (radii.fX * radii.fX) / (radii.fY * radii.fY);
864 scale = {radii.fX, 1.f / radii.fX};
865 } else {
866 invRXSqd = (radii.fY * radii.fY) / (radii.fX * radii.fX);
867 invRYSqd = 1.f;
868 scale = {radii.fY, 1.f / radii.fY};
869 }
870 } else {
871 invRXSqd = 1.f / (radii.fX * radii.fX);
872 invRYSqd = 1.f / (radii.fY * radii.fY);
873 }
874 SkV4 ellipse = {center.fX, center.fY, invRXSqd, invRYSqd};
875
876 return GrFPSuccess(GrSkSLFP::Make(effect, "Ellipse", std::move(inputFP),
877 GrSkSLFP::OptFlags::kCompatibleWithCoverageAsAlpha,
878 "edgeType", GrSkSLFP::Specialize(static_cast<int>(edgeType)),
879 "medPrecision", GrSkSLFP::Specialize<int>(medPrecision),
880 "ellipse", ellipse,
881 "scale", scale));
882}
883
884//////////////////////////////////////////////////////////////////////////////
885
Brian Osman043f0102021-06-30 14:30:34 -0400886std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::HighPrecision(
887 std::unique_ptr<GrFragmentProcessor> fp) {
888 class HighPrecisionFragmentProcessor : public GrFragmentProcessor {
889 public:
890 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp) {
891 return std::unique_ptr<GrFragmentProcessor>(
892 new HighPrecisionFragmentProcessor(std::move(fp)));
893 }
894
895 const char* name() const override { return "HighPrecision"; }
896
897 std::unique_ptr<GrFragmentProcessor> clone() const override {
898 return Make(this->childProcessor(0)->clone());
899 }
900
901 private:
902 HighPrecisionFragmentProcessor(std::unique_ptr<GrFragmentProcessor> fp)
903 : INHERITED(kHighPrecisionFragmentProcessor_ClassID,
904 ProcessorOptimizationFlags(fp.get())) {
905 this->registerChild(std::move(fp));
906 }
907
908 std::unique_ptr<GrGLSLFragmentProcessor> onMakeProgramImpl() const override {
909 class GLFP : public GrGLSLFragmentProcessor {
910 public:
911 void emitCode(EmitArgs& args) override {
912 SkString childColor = this->invokeChild(0, args);
913
914 args.fFragBuilder->forceHighPrecision();
915 args.fFragBuilder->codeAppendf("return %s;", childColor.c_str());
916 }
917 };
918 return std::make_unique<GLFP>();
919 }
920
Brian Salomon13b28732021-08-06 15:33:58 -0400921 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
Brian Osman043f0102021-06-30 14:30:34 -0400922 bool onIsEqual(const GrFragmentProcessor& other) const override { return true; }
923
924 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
925 return ConstantOutputForConstantInput(this->childProcessor(0), input);
926 }
927
928 using INHERITED = GrFragmentProcessor;
929 };
930
931 return HighPrecisionFragmentProcessor::Make(std::move(fp));
932}