blob: bdec6d0dce052bef2857f64970476d5b88a79a6b [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"; }
275 const GrSwizzle& swizzle() const { return fSwizzle; }
276
John Stileseed56f02020-06-04 13:30:51 -0400277 std::unique_ptr<GrFragmentProcessor> clone() const override {
Brian Osman12c5d292020-07-13 16:11:35 -0400278 return Make(this->childProcessor(0)->clone(), fSwizzle);
John Stileseed56f02020-06-04 13:30:51 -0400279 }
Brian Salomon216f2e02017-07-25 15:52:51 -0400280
Brian Osmance425512017-03-22 14:37:50 -0400281 private:
John Stileseed56f02020-06-04 13:30:51 -0400282 SwizzleFragmentProcessor(std::unique_ptr<GrFragmentProcessor> fp, const GrSwizzle& swizzle)
283 : INHERITED(kSwizzleFragmentProcessor_ClassID, ProcessorOptimizationFlags(fp.get()))
284 , fSwizzle(swizzle) {
Michael Ludwig9aba6252020-06-22 14:46:36 -0400285 this->registerChild(std::move(fp));
John Stileseed56f02020-06-04 13:30:51 -0400286 }
Robert Phillips1c9686b2017-06-30 08:40:28 -0400287
Brian Salomon3176e862021-08-09 11:23:04 -0400288 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
289 class GLFP : public ProgramImpl {
Brian Osmance425512017-03-22 14:37:50 -0400290 public:
291 void emitCode(EmitArgs& args) override {
Brian Osman6b5dbb42020-07-15 15:31:05 -0400292 SkString childColor = this->invokeChild(0, args);
John Stileseed56f02020-06-04 13:30:51 -0400293
Brian Osmance425512017-03-22 14:37:50 -0400294 const SwizzleFragmentProcessor& sfp = args.fFp.cast<SwizzleFragmentProcessor>();
295 const GrSwizzle& swizzle = sfp.swizzle();
296 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
297
John Stiles4bdc1212020-12-14 18:04:13 -0500298 fragBuilder->codeAppendf("return %s.%s;",
299 childColor.c_str(), swizzle.asString().c_str());
Brian Osmance425512017-03-22 14:37:50 -0400300 }
301 };
Brian Salomon18ab2032021-02-23 10:07:05 -0500302 return std::make_unique<GLFP>();
Brian Osmance425512017-03-22 14:37:50 -0400303 }
304
Brian Salomon13b28732021-08-06 15:33:58 -0400305 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const override {
Brian Osmance425512017-03-22 14:37:50 -0400306 b->add32(fSwizzle.asKey());
307 }
308
309 bool onIsEqual(const GrFragmentProcessor& other) const override {
310 const SwizzleFragmentProcessor& sfp = other.cast<SwizzleFragmentProcessor>();
311 return fSwizzle == sfp.fSwizzle;
312 }
313
Brian Osman1d5b5982018-10-01 13:41:39 -0400314 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
Brian Osman36f3d1a2021-03-22 16:36:14 -0400315 return fSwizzle.applyTo(ConstantOutputForConstantInput(this->childProcessor(0), input));
Brian Osmance425512017-03-22 14:37:50 -0400316 }
317
318 GrSwizzle fSwizzle;
319
John Stiles7571f9e2020-09-02 22:42:33 -0400320 using INHERITED = GrFragmentProcessor;
Brian Osmance425512017-03-22 14:37:50 -0400321 };
322
323 if (!fp) {
324 return nullptr;
325 }
326 if (GrSwizzle::RGBA() == swizzle) {
327 return fp;
328 }
John Stileseed56f02020-06-04 13:30:51 -0400329 return SwizzleFragmentProcessor::Make(std::move(fp), swizzle);
Brian Osmance425512017-03-22 14:37:50 -0400330}
331
Brian Salomonaff329b2017-08-11 09:40:37 -0400332std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::MakeInputPremulAndMulByOutput(
333 std::unique_ptr<GrFragmentProcessor> fp) {
bsalomonf1b7a1d2015-09-28 06:26:28 -0700334 class PremulFragmentProcessor : public GrFragmentProcessor {
335 public:
Brian Salomonaff329b2017-08-11 09:40:37 -0400336 static std::unique_ptr<GrFragmentProcessor> Make(
337 std::unique_ptr<GrFragmentProcessor> processor) {
338 return std::unique_ptr<GrFragmentProcessor>(
339 new PremulFragmentProcessor(std::move(processor)));
Robert Phillips1c9686b2017-06-30 08:40:28 -0400340 }
341
342 const char* name() const override { return "Premultiply"; }
343
Brian Salomonaff329b2017-08-11 09:40:37 -0400344 std::unique_ptr<GrFragmentProcessor> clone() const override {
Brian Osman12c5d292020-07-13 16:11:35 -0400345 return Make(this->childProcessor(0)->clone());
Brian Salomon216f2e02017-07-25 15:52:51 -0400346 }
347
Robert Phillips1c9686b2017-06-30 08:40:28 -0400348 private:
Brian Salomonaff329b2017-08-11 09:40:37 -0400349 PremulFragmentProcessor(std::unique_ptr<GrFragmentProcessor> processor)
Ethan Nicholasabff9562017-10-09 10:54:08 -0400350 : INHERITED(kPremulFragmentProcessor_ClassID, OptFlags(processor.get())) {
Michael Ludwig9aba6252020-06-22 14:46:36 -0400351 this->registerChild(std::move(processor));
bsalomonf1b7a1d2015-09-28 06:26:28 -0700352 }
353
Brian Salomon3176e862021-08-09 11:23:04 -0400354 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
355 class GLFP : public ProgramImpl {
bsalomonf1b7a1d2015-09-28 06:26:28 -0700356 public:
bsalomonf1b7a1d2015-09-28 06:26:28 -0700357 void emitCode(EmitArgs& args) override {
cdalton85285412016-02-18 12:37:07 -0800358 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
John Stiles4bdc1212020-12-14 18:04:13 -0500359 SkString temp = this->invokeChild(/*childIndex=*/0, "half4(1)", args);
360 fragBuilder->codeAppendf("half4 color = %s;", temp.c_str());
361 fragBuilder->codeAppendf("color.rgb *= %s.rgb;", args.fInputColor);
362 fragBuilder->codeAppendf("return color * %s.a;", args.fInputColor);
bsalomonf1b7a1d2015-09-28 06:26:28 -0700363 }
364 };
Brian Salomon18ab2032021-02-23 10:07:05 -0500365 return std::make_unique<GLFP>();
bsalomonf1b7a1d2015-09-28 06:26:28 -0700366 }
367
Brian Salomon13b28732021-08-06 15:33:58 -0400368 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
bsalomonf1b7a1d2015-09-28 06:26:28 -0700369
370 bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
371
Brian Salomon587e08f2017-01-27 10:59:27 -0500372 static OptimizationFlags OptFlags(const GrFragmentProcessor* inner) {
373 OptimizationFlags flags = kNone_OptimizationFlags;
374 if (inner->preservesOpaqueInput()) {
375 flags |= kPreservesOpaqueInput_OptimizationFlag;
376 }
377 if (inner->hasConstantOutputForConstantInput()) {
378 flags |= kConstantOutputForConstantInput_OptimizationFlag;
379 }
380 return flags;
381 }
bsalomonf1b7a1d2015-09-28 06:26:28 -0700382
Brian Osman1d5b5982018-10-01 13:41:39 -0400383 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
384 SkPMColor4f childColor = ConstantOutputForConstantInput(this->childProcessor(0),
Brian Osmanf28e55d2018-10-03 16:35:54 -0400385 SK_PMColor4fWHITE);
Brian Osman1d5b5982018-10-01 13:41:39 -0400386 SkPMColor4f premulInput = SkColor4f{ input.fR, input.fG, input.fB, input.fA }.premul();
387 return premulInput * childColor;
Brian Salomon587e08f2017-01-27 10:59:27 -0500388 }
389
John Stiles7571f9e2020-09-02 22:42:33 -0400390 using INHERITED = GrFragmentProcessor;
bsalomonf1b7a1d2015-09-28 06:26:28 -0700391 };
392 if (!fp) {
393 return nullptr;
394 }
Robert Phillips1c9686b2017-06-30 08:40:28 -0400395 return PremulFragmentProcessor::Make(std::move(fp));
bsalomonf1b7a1d2015-09-28 06:26:28 -0700396}
397
398//////////////////////////////////////////////////////////////////////////////
399
Brian Salomonaff329b2017-08-11 09:40:37 -0400400std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::OverrideInput(
Brian Salomonc0d79e52019-04-10 15:02:11 -0400401 std::unique_ptr<GrFragmentProcessor> fp, const SkPMColor4f& color, bool useUniform) {
Robert Phillips1c9686b2017-06-30 08:40:28 -0400402 if (!fp) {
403 return nullptr;
404 }
Brian Osman59465892021-06-18 09:15:44 -0400405 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
406 uniform colorFilter fp; // Declared as colorFilter so we can use sample(..., color)
407 uniform half4 color;
408 half4 main(half4 inColor) {
409 return sample(fp, color);
410 }
411 )");
412 SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
413 return GrSkSLFP::Make(effect, "OverrideInput", /*inputFP=*/nullptr,
414 color.isOpaque() ? GrSkSLFP::OptFlags::kPreservesOpaqueInput
415 : GrSkSLFP::OptFlags::kNone,
416 "fp", std::move(fp),
417 "color", GrSkSLFP::SpecializeIf(!useUniform, color));
bsalomonf1b7a1d2015-09-28 06:26:28 -0700418}
bsalomone25eea42015-09-29 06:38:55 -0700419
John Stiles024d7452020-07-22 19:07:15 -0400420//////////////////////////////////////////////////////////////////////////////
421
John Stiles2a6f73c2021-07-29 19:36:20 -0400422std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::UseDestColorAsInput(
423 std::unique_ptr<GrFragmentProcessor> fp) {
424 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForBlender, R"(
425 uniform colorFilter fp; // Declared as colorFilter so we can use sample(..., color)
426 half4 main(half4 src, half4 dst) {
427 return sample(fp, dst);
428 }
429 )");
430 return GrSkSLFP::Make(effect, "UseDestColorAsInput", /*inputFP=*/nullptr,
431 GrSkSLFP::OptFlags::kNone, "fp", std::move(fp));
432}
433
434//////////////////////////////////////////////////////////////////////////////
435
Brian Salomon25af4802021-07-07 16:24:16 -0400436std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::MakeInputOpaqueAndPostApplyAlpha(
437 std::unique_ptr<GrFragmentProcessor> fp) {
438 if (!fp) {
439 return nullptr;
440 }
441 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
442 uniform colorFilter fp; // Declared as colorFilter so we can use sample(..., color)
443 half4 main(half4 inColor) {
444 return inColor.a * sample(fp, unpremul(inColor).rgb1);
445 }
446 )");
447 return GrSkSLFP::Make(effect,
448 "MakeInputOpaque",
449 /*inputFP=*/nullptr,
450 GrSkSLFP::OptFlags::kPreservesOpaqueInput,
451 "fp", std::move(fp));
452}
453
454//////////////////////////////////////////////////////////////////////////////
455
John Stiles024d7452020-07-22 19:07:15 -0400456std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::Compose(
457 std::unique_ptr<GrFragmentProcessor> f, std::unique_ptr<GrFragmentProcessor> g) {
458 class ComposeProcessor : public GrFragmentProcessor {
459 public:
460 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> f,
461 std::unique_ptr<GrFragmentProcessor> g) {
462 return std::unique_ptr<GrFragmentProcessor>(new ComposeProcessor(std::move(f),
463 std::move(g)));
464 }
465
466 const char* name() const override { return "Compose"; }
467
468 std::unique_ptr<GrFragmentProcessor> clone() const override {
469 return std::unique_ptr<GrFragmentProcessor>(new ComposeProcessor(*this));
470 }
471
472 private:
Brian Salomon3176e862021-08-09 11:23:04 -0400473 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
474 class GLFP : public ProgramImpl {
John Stiles024d7452020-07-22 19:07:15 -0400475 public:
476 void emitCode(EmitArgs& args) override {
Brian Osmanc5422d02021-03-12 16:06:35 -0500477 SkString result = this->invokeChild(1, args); // g(x)
478 result = this->invokeChild(0, result.c_str(), args); // f(g(x))
John Stiles49643002020-10-19 18:52:40 -0400479 args.fFragBuilder->codeAppendf("return %s;", result.c_str());
John Stiles024d7452020-07-22 19:07:15 -0400480 }
481 };
Brian Salomon18ab2032021-02-23 10:07:05 -0500482 return std::make_unique<GLFP>();
John Stiles024d7452020-07-22 19:07:15 -0400483 }
484
485 ComposeProcessor(std::unique_ptr<GrFragmentProcessor> f,
486 std::unique_ptr<GrFragmentProcessor> g)
487 : INHERITED(kSeriesFragmentProcessor_ClassID,
488 f->optimizationFlags() & g->optimizationFlags()) {
489 this->registerChild(std::move(f));
490 this->registerChild(std::move(g));
491 }
492
John Stiles307f8f52021-08-09 15:36:59 -0400493 ComposeProcessor(const ComposeProcessor& that) : INHERITED(that) {}
John Stiles024d7452020-07-22 19:07:15 -0400494
Brian Salomon13b28732021-08-06 15:33:58 -0400495 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
John Stiles024d7452020-07-22 19:07:15 -0400496
497 bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
498
499 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override {
500 SkPMColor4f color = inColor;
John Stiles024d7452020-07-22 19:07:15 -0400501 color = ConstantOutputForConstantInput(this->childProcessor(1), color);
Brian Osmanc5422d02021-03-12 16:06:35 -0500502 color = ConstantOutputForConstantInput(this->childProcessor(0), color);
John Stiles024d7452020-07-22 19:07:15 -0400503 return color;
504 }
505
John Stiles7571f9e2020-09-02 22:42:33 -0400506 using INHERITED = GrFragmentProcessor;
John Stiles024d7452020-07-22 19:07:15 -0400507 };
508
509 // Allow either of the composed functions to be null.
510 if (f == nullptr) {
511 return g;
512 }
513 if (g == nullptr) {
514 return f;
515 }
516
517 // Run an optimization pass on this composition.
518 GrProcessorAnalysisColor inputColor;
519 inputColor.setToUnknown();
520
Brian Osmanc5422d02021-03-12 16:06:35 -0500521 std::unique_ptr<GrFragmentProcessor> series[2] = {std::move(g), std::move(f)};
John Stiles024d7452020-07-22 19:07:15 -0400522 GrColorFragmentProcessorAnalysis info(inputColor, series, SK_ARRAY_COUNT(series));
523
524 SkPMColor4f knownColor;
525 int leadingFPsToEliminate = info.initialProcessorsToEliminate(&knownColor);
526 switch (leadingFPsToEliminate) {
527 default:
528 // We shouldn't eliminate more than we started with.
529 SkASSERT(leadingFPsToEliminate <= 2);
530 [[fallthrough]];
531 case 0:
532 // Compose the two processors as requested.
Brian Osmanc5422d02021-03-12 16:06:35 -0500533 return ComposeProcessor::Make(/*f=*/std::move(series[1]), /*g=*/std::move(series[0]));
John Stiles024d7452020-07-22 19:07:15 -0400534 case 1:
535 // Replace the first processor with a constant color.
Brian Osmanc5422d02021-03-12 16:06:35 -0500536 return ComposeProcessor::Make(/*f=*/std::move(series[1]),
Brian Salomon354147a2021-04-14 11:15:05 -0400537 /*g=*/MakeColor(knownColor));
John Stiles024d7452020-07-22 19:07:15 -0400538 case 2:
539 // Replace the entire composition with a constant color.
Brian Salomon354147a2021-04-14 11:15:05 -0400540 return MakeColor(knownColor);
John Stiles024d7452020-07-22 19:07:15 -0400541 }
542}
543
544//////////////////////////////////////////////////////////////////////////////
545
Brian Osman48f83fd2021-06-23 15:51:26 +0000546std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::ColorMatrix(
547 std::unique_ptr<GrFragmentProcessor> child,
548 const float matrix[20],
549 bool unpremulInput,
550 bool clampRGBOutput,
551 bool premulOutput) {
552 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
553 uniform half4x4 m;
554 uniform half4 v;
555 uniform int unpremulInput; // always specialized
556 uniform int clampRGBOutput; // always specialized
557 uniform int premulOutput; // always specialized
558 half4 main(half4 color) {
559 if (bool(unpremulInput)) {
560 color = unpremul(color);
561 }
562 color = m * color + v;
563 if (bool(clampRGBOutput)) {
564 color = saturate(color);
565 } else {
566 color.a = saturate(color.a);
567 }
568 if (bool(premulOutput)) {
569 color.rgb *= color.a;
570 }
571 return color;
572 }
573 )");
574 SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
575
576 SkM44 m44(matrix[ 0], matrix[ 1], matrix[ 2], matrix[ 3],
577 matrix[ 5], matrix[ 6], matrix[ 7], matrix[ 8],
578 matrix[10], matrix[11], matrix[12], matrix[13],
579 matrix[15], matrix[16], matrix[17], matrix[18]);
580 SkV4 v4 = {matrix[4], matrix[9], matrix[14], matrix[19]};
581 return GrSkSLFP::Make(effect, "ColorMatrix", std::move(child), GrSkSLFP::OptFlags::kNone,
582 "m", m44,
583 "v", v4,
584 "unpremulInput", GrSkSLFP::Specialize(unpremulInput ? 1 : 0),
585 "clampRGBOutput", GrSkSLFP::Specialize(clampRGBOutput ? 1 : 0),
586 "premulOutput", GrSkSLFP::Specialize(premulOutput ? 1 : 0));
587}
588
589//////////////////////////////////////////////////////////////////////////////
590
John Stiles5b3aff42021-07-29 17:20:22 -0400591std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::SurfaceColor() {
592 class SurfaceColorProcessor : public GrFragmentProcessor {
John Stilesbb04e3d2021-06-04 12:09:11 -0400593 public:
594 static std::unique_ptr<GrFragmentProcessor> Make() {
John Stiles5b3aff42021-07-29 17:20:22 -0400595 return std::unique_ptr<GrFragmentProcessor>(new SurfaceColorProcessor());
John Stilesbb04e3d2021-06-04 12:09:11 -0400596 }
597
598 std::unique_ptr<GrFragmentProcessor> clone() const override { return Make(); }
599
John Stiles5b3aff42021-07-29 17:20:22 -0400600 const char* name() const override { return "SurfaceColor"; }
John Stilesbb04e3d2021-06-04 12:09:11 -0400601
602 private:
Brian Salomon3176e862021-08-09 11:23:04 -0400603 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
604 class GLFP : public ProgramImpl {
John Stilesbb04e3d2021-06-04 12:09:11 -0400605 public:
606 void emitCode(EmitArgs& args) override {
John Stiles5b3aff42021-07-29 17:20:22 -0400607 const char* dstColor = args.fFragBuilder->dstColor();
608 args.fFragBuilder->codeAppendf("return %s;", dstColor);
John Stilesbb04e3d2021-06-04 12:09:11 -0400609 }
610 };
611 return std::make_unique<GLFP>();
612 }
613
John Stiles5b3aff42021-07-29 17:20:22 -0400614 SurfaceColorProcessor()
615 : INHERITED(kSurfaceColorProcessor_ClassID, kNone_OptimizationFlags) {
John Stilesbc4bc5f2021-06-11 16:43:15 -0400616 this->setWillReadDstColor();
John Stilesbb04e3d2021-06-04 12:09:11 -0400617 }
618
Brian Salomon13b28732021-08-06 15:33:58 -0400619 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
John Stilesbb04e3d2021-06-04 12:09:11 -0400620
621 bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
622
623 using INHERITED = GrFragmentProcessor;
624 };
625
John Stiles5b3aff42021-07-29 17:20:22 -0400626 return SurfaceColorProcessor::Make();
John Stilesbb04e3d2021-06-04 12:09:11 -0400627}
628
629//////////////////////////////////////////////////////////////////////////////
630
Brian Osman62905552021-06-21 13:11:01 -0400631std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::DeviceSpace(
632 std::unique_ptr<GrFragmentProcessor> fp) {
Brian Salomon4f8d4be2021-07-30 18:21:32 -0400633 if (!fp) {
634 return nullptr;
635 }
636
637 class DeviceSpace : GrFragmentProcessor {
638 public:
639 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp) {
640 return std::unique_ptr<GrFragmentProcessor>(new DeviceSpace(std::move(fp)));
Brian Osman62905552021-06-21 13:11:01 -0400641 }
Brian Salomon4f8d4be2021-07-30 18:21:32 -0400642
643 private:
644 DeviceSpace(std::unique_ptr<GrFragmentProcessor> fp)
645 : GrFragmentProcessor(kDeviceSpace_ClassID, fp->optimizationFlags()) {
Brian Salomon9eca2ca2021-08-02 13:04:04 -0400646 // Passing FragCoord here is the reason this is a subclass and not a runtime-FP.
647 this->registerChild(std::move(fp), SkSL::SampleUsage::FragCoord());
Brian Salomon4f8d4be2021-07-30 18:21:32 -0400648 }
649
650 std::unique_ptr<GrFragmentProcessor> clone() const override {
651 auto child = this->childProcessor(0)->clone();
652 return std::unique_ptr<GrFragmentProcessor>(new DeviceSpace(std::move(child)));
653 }
654
655 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& f) const override {
656 return this->childProcessor(0)->constantOutputForConstantInput(f);
657 }
658
Brian Salomon3176e862021-08-09 11:23:04 -0400659 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
660 class Impl : public ProgramImpl {
Brian Salomon4f8d4be2021-07-30 18:21:32 -0400661 public:
662 Impl() = default;
Brian Salomon3176e862021-08-09 11:23:04 -0400663 void emitCode(ProgramImpl::EmitArgs& args) override {
Brian Salomon4f8d4be2021-07-30 18:21:32 -0400664 auto child = this->invokeChild(0, args.fInputColor, args, "sk_FragCoord.xy");
665 args.fFragBuilder->codeAppendf("return %s;", child.c_str());
666 }
667 };
668 return std::make_unique<Impl>();
669 }
670
Brian Salomon13b28732021-08-06 15:33:58 -0400671 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
Brian Salomon4f8d4be2021-07-30 18:21:32 -0400672
673 bool onIsEqual(const GrFragmentProcessor& processor) const override { return true; }
674
675 const char* name() const override { return "DeviceSpace"; }
676 };
677
678 return DeviceSpace::Make(std::move(fp));
Brian Osman62905552021-06-21 13:11:01 -0400679}
680
681//////////////////////////////////////////////////////////////////////////////
682
Brian Osmanb384eb22021-06-24 15:34:08 -0400683#define CLIP_EDGE_SKSL \
684 "const int kFillBW = 0;" \
685 "const int kFillAA = 1;" \
686 "const int kInverseFillBW = 2;" \
687 "const int kInverseFillAA = 3;"
688
689static_assert(static_cast<int>(GrClipEdgeType::kFillBW) == 0);
690static_assert(static_cast<int>(GrClipEdgeType::kFillAA) == 1);
691static_assert(static_cast<int>(GrClipEdgeType::kInverseFillBW) == 2);
692static_assert(static_cast<int>(GrClipEdgeType::kInverseFillAA) == 3);
693
694std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::Rect(
695 std::unique_ptr<GrFragmentProcessor> inputFP, GrClipEdgeType edgeType, SkRect rect) {
696 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, CLIP_EDGE_SKSL R"(
697 uniform int edgeType; // GrClipEdgeType, specialized
698 uniform float4 rectUniform;
699
700 half4 main(float2 xy, half4 inColor) {
701 half coverage;
702 if (edgeType == kFillBW || edgeType == kInverseFillBW) {
703 // non-AA
704 coverage = all(greaterThan(float4(sk_FragCoord.xy, rectUniform.zw),
705 float4(rectUniform.xy, sk_FragCoord.xy))) ? 1 : 0;
706 } else {
707 // compute coverage relative to left and right edges, add, then subtract 1 to
708 // account for double counting. And similar for top/bottom.
709 half4 dists4 = clamp(half4(1, 1, -1, -1) *
710 half4(sk_FragCoord.xyxy - rectUniform), 0, 1);
711 half2 dists2 = dists4.xy + dists4.zw - 1;
712 coverage = dists2.x * dists2.y;
713 }
714
715 if (edgeType == kInverseFillBW || edgeType == kInverseFillAA) {
716 coverage = 1.0 - coverage;
717 }
718
719 return inColor * coverage;
720 }
721 )");
722
723 SkASSERT(rect.isSorted());
724 // The AA math in the shader evaluates to 0 at the uploaded coordinates, so outset by 0.5
725 // 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 -0400726 SkRect rectUniform = GrClipEdgeTypeIsAA(edgeType) ? rect.makeOutset(.5f, .5f) : rect;
Brian Osmanb384eb22021-06-24 15:34:08 -0400727
728 return GrSkSLFP::Make(effect, "Rect", std::move(inputFP),
729 GrSkSLFP::OptFlags::kCompatibleWithCoverageAsAlpha,
730 "edgeType", GrSkSLFP::Specialize(static_cast<int>(edgeType)),
731 "rectUniform", rectUniform);
732}
733
734GrFPResult GrFragmentProcessor::Circle(std::unique_ptr<GrFragmentProcessor> inputFP,
735 GrClipEdgeType edgeType,
736 SkPoint center,
737 float radius) {
738 // A radius below half causes the implicit insetting done by this processor to become
739 // inverted. We could handle this case by making the processor code more complicated.
Brian Osman50f0dad2021-07-08 13:47:25 -0400740 if (radius < .5f && GrClipEdgeTypeIsInverseFill(edgeType)) {
Brian Osmanb384eb22021-06-24 15:34:08 -0400741 return GrFPFailure(std::move(inputFP));
742 }
743
744 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, CLIP_EDGE_SKSL R"(
745 uniform int edgeType; // GrClipEdgeType, specialized
746 // The circle uniform is (center.x, center.y, radius + 0.5, 1 / (radius + 0.5)) for regular
747 // fills and (..., radius - 0.5, 1 / (radius - 0.5)) for inverse fills.
748 uniform float4 circle;
749
750 half4 main(float2 xy, half4 inColor) {
751 // TODO: Right now the distance to circle calculation is performed in a space normalized
752 // to the radius and then denormalized. This is to mitigate overflow on devices that
753 // don't have full float.
754 half d;
755 if (edgeType == kInverseFillBW || edgeType == kInverseFillAA) {
756 d = half((length((circle.xy - sk_FragCoord.xy) * circle.w) - 1.0) * circle.z);
757 } else {
758 d = half((1.0 - length((circle.xy - sk_FragCoord.xy) * circle.w)) * circle.z);
759 }
760 if (edgeType == kFillAA || edgeType == kInverseFillAA) {
761 return inColor * saturate(d);
762 } else {
763 return d > 0.5 ? inColor : half4(0);
764 }
765 }
766 )");
767
768 SkScalar effectiveRadius = radius;
Brian Osman50f0dad2021-07-08 13:47:25 -0400769 if (GrClipEdgeTypeIsInverseFill(edgeType)) {
Brian Osmanb384eb22021-06-24 15:34:08 -0400770 effectiveRadius -= 0.5f;
771 // When the radius is 0.5 effectiveRadius is 0 which causes an inf * 0 in the shader.
772 effectiveRadius = std::max(0.001f, effectiveRadius);
773 } else {
774 effectiveRadius += 0.5f;
775 }
776 SkV4 circle = {center.fX, center.fY, effectiveRadius, SkScalarInvert(effectiveRadius)};
777
778 return GrFPSuccess(GrSkSLFP::Make(effect, "Circle", std::move(inputFP),
779 GrSkSLFP::OptFlags::kCompatibleWithCoverageAsAlpha,
780 "edgeType", GrSkSLFP::Specialize(static_cast<int>(edgeType)),
781 "circle", circle));
782}
783
784GrFPResult GrFragmentProcessor::Ellipse(std::unique_ptr<GrFragmentProcessor> inputFP,
785 GrClipEdgeType edgeType,
786 SkPoint center,
787 SkPoint radii,
788 const GrShaderCaps& caps) {
789 const bool medPrecision = !caps.floatIs32Bits();
790
791 // Small radii produce bad results on devices without full float.
792 if (medPrecision && (radii.fX < 0.5f || radii.fY < 0.5f)) {
793 return GrFPFailure(std::move(inputFP));
794 }
795 // Very narrow ellipses produce bad results on devices without full float
796 if (medPrecision && (radii.fX > 255*radii.fY || radii.fY > 255*radii.fX)) {
797 return GrFPFailure(std::move(inputFP));
798 }
799 // Very large ellipses produce bad results on devices without full float
800 if (medPrecision && (radii.fX > 16384 || radii.fY > 16384)) {
801 return GrFPFailure(std::move(inputFP));
802 }
803
804 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, CLIP_EDGE_SKSL R"(
805 uniform int edgeType; // GrClipEdgeType, specialized
806 uniform int medPrecision; // !sk_Caps.floatIs32Bits, specialized
807
808 uniform float4 ellipse;
809 uniform float2 scale; // only for medPrecision
810
811 half4 main(float2 xy, half4 inColor) {
812 // d is the offset to the ellipse center
813 float2 d = sk_FragCoord.xy - ellipse.xy;
814 // If we're on a device with a "real" mediump then we'll do the distance computation in
815 // a space that is normalized by the larger radius or 128, whichever is smaller. The
816 // scale uniform will be scale, 1/scale. The inverse squared radii uniform values are
817 // already in this normalized space. The center is not.
818 if (bool(medPrecision)) {
819 d *= scale.y;
820 }
821 float2 Z = d * ellipse.zw;
822 // implicit is the evaluation of (x/rx)^2 + (y/ry)^2 - 1.
823 float implicit = dot(Z, d) - 1;
824 // grad_dot is the squared length of the gradient of the implicit.
825 float grad_dot = 4 * dot(Z, Z);
826 // Avoid calling inversesqrt on zero.
827 if (bool(medPrecision)) {
828 grad_dot = max(grad_dot, 6.1036e-5);
829 } else {
830 grad_dot = max(grad_dot, 1.1755e-38);
831 }
832 float approx_dist = implicit * inversesqrt(grad_dot);
833 if (bool(medPrecision)) {
834 approx_dist *= scale.x;
835 }
836
837 half alpha;
838 if (edgeType == kFillBW) {
839 alpha = approx_dist > 0.0 ? 0.0 : 1.0;
840 } else if (edgeType == kFillAA) {
841 alpha = saturate(0.5 - half(approx_dist));
842 } else if (edgeType == kInverseFillBW) {
843 alpha = approx_dist > 0.0 ? 1.0 : 0.0;
844 } else { // edgeType == kInverseFillAA
845 alpha = saturate(0.5 + half(approx_dist));
846 }
847 return inColor * alpha;
848 }
849 )");
850
851 float invRXSqd;
852 float invRYSqd;
853 SkV2 scale = {1, 1};
854 // If we're using a scale factor to work around precision issues, choose the larger radius as
855 // the scale factor. The inv radii need to be pre-adjusted by the scale factor.
856 if (medPrecision) {
857 if (radii.fX > radii.fY) {
858 invRXSqd = 1.f;
859 invRYSqd = (radii.fX * radii.fX) / (radii.fY * radii.fY);
860 scale = {radii.fX, 1.f / radii.fX};
861 } else {
862 invRXSqd = (radii.fY * radii.fY) / (radii.fX * radii.fX);
863 invRYSqd = 1.f;
864 scale = {radii.fY, 1.f / radii.fY};
865 }
866 } else {
867 invRXSqd = 1.f / (radii.fX * radii.fX);
868 invRYSqd = 1.f / (radii.fY * radii.fY);
869 }
870 SkV4 ellipse = {center.fX, center.fY, invRXSqd, invRYSqd};
871
872 return GrFPSuccess(GrSkSLFP::Make(effect, "Ellipse", std::move(inputFP),
873 GrSkSLFP::OptFlags::kCompatibleWithCoverageAsAlpha,
874 "edgeType", GrSkSLFP::Specialize(static_cast<int>(edgeType)),
875 "medPrecision", GrSkSLFP::Specialize<int>(medPrecision),
876 "ellipse", ellipse,
877 "scale", scale));
878}
879
880//////////////////////////////////////////////////////////////////////////////
881
Brian Osman043f0102021-06-30 14:30:34 -0400882std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::HighPrecision(
883 std::unique_ptr<GrFragmentProcessor> fp) {
884 class HighPrecisionFragmentProcessor : public GrFragmentProcessor {
885 public:
886 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp) {
887 return std::unique_ptr<GrFragmentProcessor>(
888 new HighPrecisionFragmentProcessor(std::move(fp)));
889 }
890
891 const char* name() const override { return "HighPrecision"; }
892
893 std::unique_ptr<GrFragmentProcessor> clone() const override {
894 return Make(this->childProcessor(0)->clone());
895 }
896
897 private:
898 HighPrecisionFragmentProcessor(std::unique_ptr<GrFragmentProcessor> fp)
899 : INHERITED(kHighPrecisionFragmentProcessor_ClassID,
900 ProcessorOptimizationFlags(fp.get())) {
901 this->registerChild(std::move(fp));
902 }
903
Brian Salomon3176e862021-08-09 11:23:04 -0400904 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
905 class GLFP : public ProgramImpl {
Brian Osman043f0102021-06-30 14:30:34 -0400906 public:
907 void emitCode(EmitArgs& args) override {
908 SkString childColor = this->invokeChild(0, args);
909
910 args.fFragBuilder->forceHighPrecision();
911 args.fFragBuilder->codeAppendf("return %s;", childColor.c_str());
912 }
913 };
914 return std::make_unique<GLFP>();
915 }
916
Brian Salomon13b28732021-08-06 15:33:58 -0400917 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
Brian Osman043f0102021-06-30 14:30:34 -0400918 bool onIsEqual(const GrFragmentProcessor& other) const override { return true; }
919
920 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
921 return ConstantOutputForConstantInput(this->childProcessor(0), input);
922 }
923
924 using INHERITED = GrFragmentProcessor;
925 };
926
927 return HighPrecisionFragmentProcessor::Make(std::move(fp));
928}