blob: 390105d6a26b1689c7bc7e28a4b94404860e3d06 [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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "src/gpu/GrFragmentProcessor.h"
Brian Salomon48959462021-08-11 13:01:06 -04009
10#include "src/core/SkRuntimeEffectPriv.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "src/gpu/GrPipeline.h"
12#include "src/gpu/GrProcessorAnalysis.h"
Brian Salomon48959462021-08-11 13:01:06 -040013#include "src/gpu/GrShaderCaps.h"
John Stilesf743d4e2020-07-23 11:35:08 -040014#include "src/gpu/effects/GrBlendFragmentProcessor.h"
Brian Salomon354147a2021-04-14 11:15:05 -040015#include "src/gpu/effects/GrSkSLFP.h"
Robert Phillips550de7f2021-07-06 16:28:52 -040016#include "src/gpu/effects/GrTextureEffect.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
Brian Salomon48959462021-08-11 13:01:06 -040018#include "src/gpu/glsl/GrGLSLProgramBuilder.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050019#include "src/gpu/glsl/GrGLSLProgramDataManager.h"
20#include "src/gpu/glsl/GrGLSLUniformHandler.h"
bsalomonbf877302015-09-22 09:06:13 -070021
bsalomon7312ff82016-09-12 08:55:38 -070022bool GrFragmentProcessor::isEqual(const GrFragmentProcessor& that) const {
Brian Salomone782f842018-07-31 13:53:11 -040023 if (this->classID() != that.classID()) {
bsalomonbf877302015-09-22 09:06:13 -070024 return false;
25 }
Brian Salomon66b500a2021-08-02 12:37:14 -040026 if (this->sampleUsage() != that.sampleUsage()) {
bsalomonbf877302015-09-22 09:06:13 -070027 return false;
28 }
29 if (!this->onIsEqual(that)) {
30 return false;
31 }
32 if (this->numChildProcessors() != that.numChildProcessors()) {
33 return false;
34 }
35 for (int i = 0; i < this->numChildProcessors(); ++i) {
Brian Osman12c5d292020-07-13 16:11:35 -040036 auto thisChild = this->childProcessor(i),
37 thatChild = that .childProcessor(i);
38 if (SkToBool(thisChild) != SkToBool(thatChild)) {
39 return false;
40 }
41 if (thisChild && !thisChild->isEqual(*thatChild)) {
bsalomonbf877302015-09-22 09:06:13 -070042 return false;
43 }
44 }
45 return true;
46}
47
Robert Phillips294723d2021-06-17 09:23:58 -040048void GrFragmentProcessor::visitProxies(const GrVisitProxyFunc& func) const {
Brian Salomond90b3d32020-07-09 12:04:31 -040049 this->visitTextureEffects([&func](const GrTextureEffect& te) {
Brian Salomone69b9ef2020-07-22 11:18:06 -040050 func(te.view().proxy(), te.samplerState().mipmapped());
Brian Salomond90b3d32020-07-09 12:04:31 -040051 });
52}
53
54void GrFragmentProcessor::visitTextureEffects(
55 const std::function<void(const GrTextureEffect&)>& func) const {
56 if (auto* te = this->asTextureEffect()) {
57 func(*te);
Brian Salomone782f842018-07-31 13:53:11 -040058 }
Brian Salomond90b3d32020-07-09 12:04:31 -040059 for (auto& child : fChildProcessors) {
Brian Osman12c5d292020-07-13 16:11:35 -040060 if (child) {
61 child->visitTextureEffects(func);
62 }
Brian Salomond90b3d32020-07-09 12:04:31 -040063 }
64}
65
Brian Salomon91398032021-08-05 10:02:08 -040066void GrFragmentProcessor::visitWithImpls(
Brian Salomon3176e862021-08-09 11:23:04 -040067 const std::function<void(const GrFragmentProcessor&, ProgramImpl&)>& f,
68 ProgramImpl& impl) const {
Brian Salomon91398032021-08-05 10:02:08 -040069 f(*this, impl);
70 SkASSERT(impl.numChildProcessors() == this->numChildProcessors());
71 for (int i = 0; i < this->numChildProcessors(); ++i) {
72 if (const auto* child = this->childProcessor(i)) {
73 child->visitWithImpls(f, *impl.childProcessor(i));
74 }
75 }
76}
77
Brian Salomond90b3d32020-07-09 12:04:31 -040078GrTextureEffect* GrFragmentProcessor::asTextureEffect() {
79 if (this->classID() == kGrTextureEffect_ClassID) {
80 return static_cast<GrTextureEffect*>(this);
81 }
82 return nullptr;
83}
84
85const GrTextureEffect* GrFragmentProcessor::asTextureEffect() const {
86 if (this->classID() == kGrTextureEffect_ClassID) {
87 return static_cast<const GrTextureEffect*>(this);
88 }
89 return nullptr;
Brian Salomone782f842018-07-31 13:53:11 -040090}
91
John Stiles8d9bf642020-08-12 15:07:45 -040092#if GR_TEST_UTILS
John Stilesba1879d2020-08-11 13:58:32 -040093static void recursive_dump_tree_info(const GrFragmentProcessor& fp,
94 SkString indent,
95 SkString* text) {
96 for (int index = 0; index < fp.numChildProcessors(); ++index) {
97 text->appendf("\n%s(#%d) -> ", indent.c_str(), index);
98 if (const GrFragmentProcessor* childFP = fp.childProcessor(index)) {
99 text->append(childFP->dumpInfo());
100 indent.append("\t");
101 recursive_dump_tree_info(*childFP, indent, text);
102 } else {
103 text->append("null");
104 }
105 }
106}
107
108SkString GrFragmentProcessor::dumpTreeInfo() const {
109 SkString text = this->dumpInfo();
110 recursive_dump_tree_info(*this, SkString("\t"), &text);
111 text.append("\n");
112 return text;
113}
114#endif
115
Brian Salomon3176e862021-08-09 11:23:04 -0400116std::unique_ptr<GrFragmentProcessor::ProgramImpl> GrFragmentProcessor::makeProgramImpl() const {
117 std::unique_ptr<ProgramImpl> impl = this->onMakeProgramImpl();
118 impl->fChildProcessors.push_back_n(fChildProcessors.count());
bsalomonbf877302015-09-22 09:06:13 -0700119 for (int i = 0; i < fChildProcessors.count(); ++i) {
Brian Salomon3176e862021-08-09 11:23:04 -0400120 impl->fChildProcessors[i] = fChildProcessors[i] ? fChildProcessors[i]->makeProgramImpl()
121 : nullptr;
bsalomonbf877302015-09-22 09:06:13 -0700122 }
Brian Salomon3176e862021-08-09 11:23:04 -0400123 return impl;
bsalomonbf877302015-09-22 09:06:13 -0700124}
125
Brian Osman12c5d292020-07-13 16:11:35 -0400126int GrFragmentProcessor::numNonNullChildProcessors() const {
127 return std::count_if(fChildProcessors.begin(), fChildProcessors.end(),
128 [](const auto& c) { return c != nullptr; });
129}
130
Robert Phillips82774f82019-06-20 14:38:27 -0400131#ifdef SK_DEBUG
132bool GrFragmentProcessor::isInstantiated() const {
Brian Salomond90b3d32020-07-09 12:04:31 -0400133 bool result = true;
134 this->visitTextureEffects([&result](const GrTextureEffect& te) {
135 if (!te.texture()) {
136 result = false;
Brian Salomone782f842018-07-31 13:53:11 -0400137 }
Brian Salomond90b3d32020-07-09 12:04:31 -0400138 });
139 return result;
Robert Phillips9bee2e52017-05-29 12:37:20 -0400140}
Robert Phillips82774f82019-06-20 14:38:27 -0400141#endif
Robert Phillips9bee2e52017-05-29 12:37:20 -0400142
Brian Osman12c5d292020-07-13 16:11:35 -0400143void GrFragmentProcessor::registerChild(std::unique_ptr<GrFragmentProcessor> child,
144 SkSL::SampleUsage sampleUsage) {
Brian Osman201b72a2021-09-08 11:16:29 -0400145 SkASSERT(sampleUsage.isSampled());
146
Brian Osman54867de2020-07-10 14:22:57 -0400147 if (!child) {
Brian Osman12c5d292020-07-13 16:11:35 -0400148 fChildProcessors.push_back(nullptr);
149 return;
Brian Osman54867de2020-07-10 14:22:57 -0400150 }
151
Michael Ludwige88320b2020-06-24 09:04:56 -0400152 // The child should not have been attached to another FP already and not had any sampling
153 // strategy set on it.
Brian Salomon66b500a2021-08-02 12:37:14 -0400154 SkASSERT(!child->fParent && !child->sampleUsage().isSampled());
Michael Ludwige88320b2020-06-24 09:04:56 -0400155
Michael Ludwig9aba6252020-06-22 14:46:36 -0400156 // Configure child's sampling state first
Brian Osman1298bc42020-06-30 13:39:35 -0400157 child->fUsage = sampleUsage;
158
John Stilese69f25f2021-06-03 12:23:33 -0400159 // Propagate the "will read dest-color" flag up to parent FPs.
John Stilesbc4bc5f2021-06-11 16:43:15 -0400160 if (child->willReadDstColor()) {
161 this->setWillReadDstColor();
John Stilese69f25f2021-06-03 12:23:33 -0400162 }
163
Brian Salomon66b500a2021-08-02 12:37:14 -0400164 // If this child receives passthrough or matrix transformed coords from its parent then note
165 // that the parent's coords are used indirectly to ensure that they aren't omitted.
166 if ((sampleUsage.isPassThrough() || sampleUsage.isUniformMatrix()) &&
167 child->usesSampleCoords()) {
168 fFlags |= kUsesSampleCoordsIndirectly_Flag;
Michael Ludwige88320b2020-06-24 09:04:56 -0400169 }
170
Michael Ludwige88320b2020-06-24 09:04:56 -0400171 // Record that the child is attached to us; this FP is the source of any uniform data needed
172 // to evaluate the child sample matrix.
173 child->fParent = this;
Brian Salomonaff329b2017-08-11 09:40:37 -0400174 fChildProcessors.push_back(std::move(child));
Michael Ludwige88320b2020-06-24 09:04:56 -0400175
Leon Scroggins III982fff22020-07-31 14:09:06 -0400176 // Validate: our sample strategy comes from a parent we shouldn't have yet.
Brian Salomon66b500a2021-08-02 12:37:14 -0400177 SkASSERT(!fUsage.isSampled() && !fParent);
John Stiles3779f442020-06-15 10:48:49 -0400178}
179
John Stiles9ec6b052020-06-15 12:06:10 -0400180void GrFragmentProcessor::cloneAndRegisterAllChildProcessors(const GrFragmentProcessor& src) {
181 for (int i = 0; i < src.numChildProcessors(); ++i) {
Brian Osman12c5d292020-07-13 16:11:35 -0400182 if (auto fp = src.childProcessor(i)) {
183 this->registerChild(fp->clone(), fp->sampleUsage());
184 } else {
185 this->registerChild(nullptr);
186 }
John Stiles9ec6b052020-06-15 12:06:10 -0400187 }
188}
189
Brian Salomon354147a2021-04-14 11:15:05 -0400190std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::MakeColor(SkPMColor4f color) {
Brian Osman4cd134c2021-04-28 17:25:31 -0400191 // Use ColorFilter signature/factory to get the constant output for constant input optimization
Brian Osmand1b530a2021-05-25 16:09:16 -0400192 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
Brian Salomon354147a2021-04-14 11:15:05 -0400193 uniform half4 color;
Brian Osman4cd134c2021-04-28 17:25:31 -0400194 half4 main(half4 inColor) { return color; }
Brian Osmand1b530a2021-05-25 16:09:16 -0400195 )");
Brian Osmanbe545c92021-06-18 09:41:15 -0400196 SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
Brian Osman171fba72021-06-16 17:10:21 -0400197 return GrSkSLFP::Make(effect, "color_fp", /*inputFP=*/nullptr,
198 color.isOpaque() ? GrSkSLFP::OptFlags::kPreservesOpaqueInput
199 : GrSkSLFP::OptFlags::kNone,
200 "color", color);
Brian Salomon354147a2021-04-14 11:15:05 -0400201}
202
Mike Reed28eaed22018-02-01 11:24:53 -0500203std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::MulChildByInputAlpha(
Brian Salomonaff329b2017-08-11 09:40:37 -0400204 std::unique_ptr<GrFragmentProcessor> fp) {
bsalomonf1b7a1d2015-09-28 06:26:28 -0700205 if (!fp) {
206 return nullptr;
207 }
Brian Salomon4b6e2f02021-07-08 14:04:21 -0400208 return GrBlendFragmentProcessor::Make(/*src=*/nullptr,
209 OverrideInput(std::move(fp), SK_PMColor4fWHITE),
210 SkBlendMode::kDstIn);
bsalomonbf877302015-09-22 09:06:13 -0700211}
212
Mike Reed28eaed22018-02-01 11:24:53 -0500213std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::MulInputByChildAlpha(
214 std::unique_ptr<GrFragmentProcessor> fp) {
215 if (!fp) {
216 return nullptr;
217 }
Brian Salomon4b6e2f02021-07-08 14:04:21 -0400218 return GrBlendFragmentProcessor::Make(/*src=*/nullptr,
219 OverrideInput(std::move(fp), SK_PMColor4fWHITE),
220 SkBlendMode::kSrcIn);
Mike Reed28eaed22018-02-01 11:24:53 -0500221}
222
John Stiles7bf26002020-07-13 11:30:12 -0400223std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::ModulateAlpha(
224 std::unique_ptr<GrFragmentProcessor> inputFP, const SkPMColor4f& color) {
Brian Salomon354147a2021-04-14 11:15:05 -0400225 auto colorFP = MakeColor(color);
Brian Salomon4b6e2f02021-07-08 14:04:21 -0400226 return GrBlendFragmentProcessor::Make(std::move(colorFP),
227 std::move(inputFP),
228 SkBlendMode::kSrcIn);
John Stiles7bf26002020-07-13 11:30:12 -0400229}
230
John Stiles85894302020-07-13 11:39:52 -0400231std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::ModulateRGBA(
232 std::unique_ptr<GrFragmentProcessor> inputFP, const SkPMColor4f& color) {
Brian Salomon354147a2021-04-14 11:15:05 -0400233 auto colorFP = MakeColor(color);
Brian Salomon4b6e2f02021-07-08 14:04:21 -0400234 return GrBlendFragmentProcessor::Make(std::move(colorFP),
235 std::move(inputFP),
236 SkBlendMode::kModulate);
John Stiles85894302020-07-13 11:39:52 -0400237}
238
Brian Osman8e814b32021-06-17 14:14:26 -0400239std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::ClampOutput(
240 std::unique_ptr<GrFragmentProcessor> fp) {
241 SkASSERT(fp);
242 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
243 half4 main(half4 inColor) {
244 return saturate(inColor);
245 }
246 )");
Brian Osmanbe545c92021-06-18 09:41:15 -0400247 SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
Brian Osman8e814b32021-06-17 14:14:26 -0400248 return GrSkSLFP::Make(
249 effect, "Clamp", std::move(fp), GrSkSLFP::OptFlags::kPreservesOpaqueInput);
250}
251
Brian Osman6f5e9402020-01-22 10:39:31 -0500252std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::ClampPremulOutput(
253 std::unique_ptr<GrFragmentProcessor> fp) {
Brian Osman8e814b32021-06-17 14:14:26 -0400254 SkASSERT(fp);
255 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
256 half4 main(half4 inColor) {
257 half alpha = saturate(inColor.a);
258 return half4(clamp(inColor.rgb, 0, alpha), alpha);
259 }
260 )");
Brian Osmanbe545c92021-06-18 09:41:15 -0400261 SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
Brian Osman8e814b32021-06-17 14:14:26 -0400262 return GrSkSLFP::Make(
263 effect, "ClampPremul", std::move(fp), GrSkSLFP::OptFlags::kPreservesOpaqueInput);
Brian Osman6f5e9402020-01-22 10:39:31 -0500264}
265
Brian Salomonaff329b2017-08-11 09:40:37 -0400266std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::SwizzleOutput(
267 std::unique_ptr<GrFragmentProcessor> fp, const GrSwizzle& swizzle) {
Brian Osmance425512017-03-22 14:37:50 -0400268 class SwizzleFragmentProcessor : public GrFragmentProcessor {
269 public:
John Stileseed56f02020-06-04 13:30:51 -0400270 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp,
271 const GrSwizzle& swizzle) {
272 return std::unique_ptr<GrFragmentProcessor>(
John Stiles4bdc1212020-12-14 18:04:13 -0500273 new SwizzleFragmentProcessor(std::move(fp), swizzle));
Brian Osmance425512017-03-22 14:37:50 -0400274 }
275
276 const char* name() const override { return "Swizzle"; }
Brian Osmance425512017-03-22 14:37:50 -0400277
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 Salomon3176e862021-08-09 11:23:04 -0400289 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
Brian Salomonb25560a2021-08-10 13:56:13 -0400290 class Impl : public ProgramImpl {
Brian Osmance425512017-03-22 14:37:50 -0400291 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>();
Brian Salomonb25560a2021-08-10 13:56:13 -0400296 const GrSwizzle& swizzle = sfp.fSwizzle;
Brian Osmance425512017-03-22 14:37:50 -0400297 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 Salomonb25560a2021-08-10 13:56:13 -0400303 return std::make_unique<Impl>();
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 Salomon3176e862021-08-09 11:23:04 -0400355 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
Brian Salomonb25560a2021-08-10 13:56:13 -0400356 class Impl : public ProgramImpl {
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 Salomonb25560a2021-08-10 13:56:13 -0400366 return std::make_unique<Impl>();
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"(
Brian Osman293497e2021-08-24 14:08:50 -0400407 uniform colorFilter fp; // Declared as colorFilter so we can pass a color
Brian Osman59465892021-06-18 09:15:44 -0400408 uniform half4 color;
409 half4 main(half4 inColor) {
Brian Osmancbfa34a2021-09-02 09:26:27 -0400410 return fp.eval(color);
Brian Osman59465892021-06-18 09:15:44 -0400411 }
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"(
Brian Osman293497e2021-08-24 14:08:50 -0400426 uniform colorFilter fp; // Declared as colorFilter so we can pass a color
John Stiles2a6f73c2021-07-29 19:36:20 -0400427 half4 main(half4 src, half4 dst) {
Brian Osmancbfa34a2021-09-02 09:26:27 -0400428 return fp.eval(dst);
John Stiles2a6f73c2021-07-29 19:36:20 -0400429 }
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"(
Brian Osman293497e2021-08-24 14:08:50 -0400443 uniform colorFilter fp; // Declared as colorFilter so we can pass a color
Brian Salomon25af4802021-07-07 16:24:16 -0400444 half4 main(half4 inColor) {
Brian Osmancbfa34a2021-09-02 09:26:27 -0400445 return inColor.a * fp.eval(unpremul(inColor).rgb1);
Brian Salomon25af4802021-07-07 16:24:16 -0400446 }
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 Salomon3176e862021-08-09 11:23:04 -0400474 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
Brian Salomonb25560a2021-08-10 13:56:13 -0400475 class Impl : public ProgramImpl {
John Stiles024d7452020-07-22 19:07:15 -0400476 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 Salomonb25560a2021-08-10 13:56:13 -0400483 return std::make_unique<Impl>();
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
John Stiles307f8f52021-08-09 15:36:59 -0400494 ComposeProcessor(const ComposeProcessor& that) : INHERITED(that) {}
John Stiles024d7452020-07-22 19:07:15 -0400495
Brian Salomon13b28732021-08-06 15:33:58 -0400496 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
John Stiles024d7452020-07-22 19:07:15 -0400497
498 bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
499
500 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& inColor) const override {
501 SkPMColor4f color = inColor;
John Stiles024d7452020-07-22 19:07:15 -0400502 color = ConstantOutputForConstantInput(this->childProcessor(1), color);
Brian Osmanc5422d02021-03-12 16:06:35 -0500503 color = ConstantOutputForConstantInput(this->childProcessor(0), color);
John Stiles024d7452020-07-22 19:07:15 -0400504 return color;
505 }
506
John Stiles7571f9e2020-09-02 22:42:33 -0400507 using INHERITED = GrFragmentProcessor;
John Stiles024d7452020-07-22 19:07:15 -0400508 };
509
510 // Allow either of the composed functions to be null.
511 if (f == nullptr) {
512 return g;
513 }
514 if (g == nullptr) {
515 return f;
516 }
517
518 // Run an optimization pass on this composition.
519 GrProcessorAnalysisColor inputColor;
520 inputColor.setToUnknown();
521
Brian Osmanc5422d02021-03-12 16:06:35 -0500522 std::unique_ptr<GrFragmentProcessor> series[2] = {std::move(g), std::move(f)};
John Stiles024d7452020-07-22 19:07:15 -0400523 GrColorFragmentProcessorAnalysis info(inputColor, series, SK_ARRAY_COUNT(series));
524
525 SkPMColor4f knownColor;
526 int leadingFPsToEliminate = info.initialProcessorsToEliminate(&knownColor);
527 switch (leadingFPsToEliminate) {
528 default:
529 // We shouldn't eliminate more than we started with.
530 SkASSERT(leadingFPsToEliminate <= 2);
531 [[fallthrough]];
532 case 0:
533 // Compose the two processors as requested.
Brian Osmanc5422d02021-03-12 16:06:35 -0500534 return ComposeProcessor::Make(/*f=*/std::move(series[1]), /*g=*/std::move(series[0]));
John Stiles024d7452020-07-22 19:07:15 -0400535 case 1:
536 // Replace the first processor with a constant color.
Brian Osmanc5422d02021-03-12 16:06:35 -0500537 return ComposeProcessor::Make(/*f=*/std::move(series[1]),
Brian Salomon354147a2021-04-14 11:15:05 -0400538 /*g=*/MakeColor(knownColor));
John Stiles024d7452020-07-22 19:07:15 -0400539 case 2:
540 // Replace the entire composition with a constant color.
Brian Salomon354147a2021-04-14 11:15:05 -0400541 return MakeColor(knownColor);
John Stiles024d7452020-07-22 19:07:15 -0400542 }
543}
544
545//////////////////////////////////////////////////////////////////////////////
546
Brian Osman48f83fd2021-06-23 15:51:26 +0000547std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::ColorMatrix(
548 std::unique_ptr<GrFragmentProcessor> child,
549 const float matrix[20],
550 bool unpremulInput,
551 bool clampRGBOutput,
552 bool premulOutput) {
553 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForColorFilter, R"(
554 uniform half4x4 m;
555 uniform half4 v;
556 uniform int unpremulInput; // always specialized
557 uniform int clampRGBOutput; // always specialized
558 uniform int premulOutput; // always specialized
559 half4 main(half4 color) {
560 if (bool(unpremulInput)) {
561 color = unpremul(color);
562 }
563 color = m * color + v;
564 if (bool(clampRGBOutput)) {
565 color = saturate(color);
566 } else {
567 color.a = saturate(color.a);
568 }
569 if (bool(premulOutput)) {
570 color.rgb *= color.a;
571 }
572 return color;
573 }
574 )");
575 SkASSERT(SkRuntimeEffectPriv::SupportsConstantOutputForConstantInput(effect));
576
577 SkM44 m44(matrix[ 0], matrix[ 1], matrix[ 2], matrix[ 3],
578 matrix[ 5], matrix[ 6], matrix[ 7], matrix[ 8],
579 matrix[10], matrix[11], matrix[12], matrix[13],
580 matrix[15], matrix[16], matrix[17], matrix[18]);
581 SkV4 v4 = {matrix[4], matrix[9], matrix[14], matrix[19]};
582 return GrSkSLFP::Make(effect, "ColorMatrix", std::move(child), GrSkSLFP::OptFlags::kNone,
583 "m", m44,
584 "v", v4,
585 "unpremulInput", GrSkSLFP::Specialize(unpremulInput ? 1 : 0),
586 "clampRGBOutput", GrSkSLFP::Specialize(clampRGBOutput ? 1 : 0),
587 "premulOutput", GrSkSLFP::Specialize(premulOutput ? 1 : 0));
588}
589
590//////////////////////////////////////////////////////////////////////////////
591
John Stiles5b3aff42021-07-29 17:20:22 -0400592std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::SurfaceColor() {
593 class SurfaceColorProcessor : public GrFragmentProcessor {
John Stilesbb04e3d2021-06-04 12:09:11 -0400594 public:
595 static std::unique_ptr<GrFragmentProcessor> Make() {
John Stiles5b3aff42021-07-29 17:20:22 -0400596 return std::unique_ptr<GrFragmentProcessor>(new SurfaceColorProcessor());
John Stilesbb04e3d2021-06-04 12:09:11 -0400597 }
598
599 std::unique_ptr<GrFragmentProcessor> clone() const override { return Make(); }
600
John Stiles5b3aff42021-07-29 17:20:22 -0400601 const char* name() const override { return "SurfaceColor"; }
John Stilesbb04e3d2021-06-04 12:09:11 -0400602
603 private:
Brian Salomon3176e862021-08-09 11:23:04 -0400604 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
Brian Salomonb25560a2021-08-10 13:56:13 -0400605 class Impl : public ProgramImpl {
John Stilesbb04e3d2021-06-04 12:09:11 -0400606 public:
607 void emitCode(EmitArgs& args) override {
John Stiles5b3aff42021-07-29 17:20:22 -0400608 const char* dstColor = args.fFragBuilder->dstColor();
609 args.fFragBuilder->codeAppendf("return %s;", dstColor);
John Stilesbb04e3d2021-06-04 12:09:11 -0400610 }
611 };
Brian Salomonb25560a2021-08-10 13:56:13 -0400612 return std::make_unique<Impl>();
John Stilesbb04e3d2021-06-04 12:09:11 -0400613 }
614
John Stiles5b3aff42021-07-29 17:20:22 -0400615 SurfaceColorProcessor()
616 : INHERITED(kSurfaceColorProcessor_ClassID, kNone_OptimizationFlags) {
John Stilesbc4bc5f2021-06-11 16:43:15 -0400617 this->setWillReadDstColor();
John Stilesbb04e3d2021-06-04 12:09:11 -0400618 }
619
Brian Salomon13b28732021-08-06 15:33:58 -0400620 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
John Stilesbb04e3d2021-06-04 12:09:11 -0400621
622 bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
623
624 using INHERITED = GrFragmentProcessor;
625 };
626
John Stiles5b3aff42021-07-29 17:20:22 -0400627 return SurfaceColorProcessor::Make();
John Stilesbb04e3d2021-06-04 12:09:11 -0400628}
629
630//////////////////////////////////////////////////////////////////////////////
631
Brian Osman62905552021-06-21 13:11:01 -0400632std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::DeviceSpace(
633 std::unique_ptr<GrFragmentProcessor> fp) {
Brian Salomon4f8d4be2021-07-30 18:21:32 -0400634 if (!fp) {
635 return nullptr;
636 }
637
638 class DeviceSpace : GrFragmentProcessor {
639 public:
640 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp) {
641 return std::unique_ptr<GrFragmentProcessor>(new DeviceSpace(std::move(fp)));
Brian Osman62905552021-06-21 13:11:01 -0400642 }
Brian Salomon4f8d4be2021-07-30 18:21:32 -0400643
644 private:
645 DeviceSpace(std::unique_ptr<GrFragmentProcessor> fp)
646 : GrFragmentProcessor(kDeviceSpace_ClassID, fp->optimizationFlags()) {
Brian Salomon9eca2ca2021-08-02 13:04:04 -0400647 // Passing FragCoord here is the reason this is a subclass and not a runtime-FP.
648 this->registerChild(std::move(fp), SkSL::SampleUsage::FragCoord());
Brian Salomon4f8d4be2021-07-30 18:21:32 -0400649 }
650
651 std::unique_ptr<GrFragmentProcessor> clone() const override {
652 auto child = this->childProcessor(0)->clone();
653 return std::unique_ptr<GrFragmentProcessor>(new DeviceSpace(std::move(child)));
654 }
655
656 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& f) const override {
657 return this->childProcessor(0)->constantOutputForConstantInput(f);
658 }
659
Brian Salomon3176e862021-08-09 11:23:04 -0400660 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
661 class Impl : public ProgramImpl {
Brian Salomon4f8d4be2021-07-30 18:21:32 -0400662 public:
663 Impl() = default;
Brian Salomon3176e862021-08-09 11:23:04 -0400664 void emitCode(ProgramImpl::EmitArgs& args) override {
Brian Salomon4f8d4be2021-07-30 18:21:32 -0400665 auto child = this->invokeChild(0, args.fInputColor, args, "sk_FragCoord.xy");
666 args.fFragBuilder->codeAppendf("return %s;", child.c_str());
667 }
668 };
669 return std::make_unique<Impl>();
670 }
671
Brian Salomon13b28732021-08-06 15:33:58 -0400672 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
Brian Salomon4f8d4be2021-07-30 18:21:32 -0400673
674 bool onIsEqual(const GrFragmentProcessor& processor) const override { return true; }
675
676 const char* name() const override { return "DeviceSpace"; }
677 };
678
679 return DeviceSpace::Make(std::move(fp));
Brian Osman62905552021-06-21 13:11:01 -0400680}
681
682//////////////////////////////////////////////////////////////////////////////
683
Brian Osmanb384eb22021-06-24 15:34:08 -0400684#define CLIP_EDGE_SKSL \
685 "const int kFillBW = 0;" \
686 "const int kFillAA = 1;" \
687 "const int kInverseFillBW = 2;" \
688 "const int kInverseFillAA = 3;"
689
690static_assert(static_cast<int>(GrClipEdgeType::kFillBW) == 0);
691static_assert(static_cast<int>(GrClipEdgeType::kFillAA) == 1);
692static_assert(static_cast<int>(GrClipEdgeType::kInverseFillBW) == 2);
693static_assert(static_cast<int>(GrClipEdgeType::kInverseFillAA) == 3);
694
695std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::Rect(
696 std::unique_ptr<GrFragmentProcessor> inputFP, GrClipEdgeType edgeType, SkRect rect) {
697 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, CLIP_EDGE_SKSL R"(
698 uniform int edgeType; // GrClipEdgeType, specialized
699 uniform float4 rectUniform;
700
701 half4 main(float2 xy, half4 inColor) {
702 half coverage;
703 if (edgeType == kFillBW || edgeType == kInverseFillBW) {
704 // non-AA
705 coverage = all(greaterThan(float4(sk_FragCoord.xy, rectUniform.zw),
706 float4(rectUniform.xy, sk_FragCoord.xy))) ? 1 : 0;
707 } else {
708 // compute coverage relative to left and right edges, add, then subtract 1 to
709 // account for double counting. And similar for top/bottom.
710 half4 dists4 = clamp(half4(1, 1, -1, -1) *
711 half4(sk_FragCoord.xyxy - rectUniform), 0, 1);
712 half2 dists2 = dists4.xy + dists4.zw - 1;
713 coverage = dists2.x * dists2.y;
714 }
715
716 if (edgeType == kInverseFillBW || edgeType == kInverseFillAA) {
717 coverage = 1.0 - coverage;
718 }
719
720 return inColor * coverage;
721 }
722 )");
723
724 SkASSERT(rect.isSorted());
725 // The AA math in the shader evaluates to 0 at the uploaded coordinates, so outset by 0.5
726 // 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 -0400727 SkRect rectUniform = GrClipEdgeTypeIsAA(edgeType) ? rect.makeOutset(.5f, .5f) : rect;
Brian Osmanb384eb22021-06-24 15:34:08 -0400728
729 return GrSkSLFP::Make(effect, "Rect", std::move(inputFP),
730 GrSkSLFP::OptFlags::kCompatibleWithCoverageAsAlpha,
731 "edgeType", GrSkSLFP::Specialize(static_cast<int>(edgeType)),
732 "rectUniform", rectUniform);
733}
734
735GrFPResult GrFragmentProcessor::Circle(std::unique_ptr<GrFragmentProcessor> inputFP,
736 GrClipEdgeType edgeType,
737 SkPoint center,
738 float radius) {
739 // A radius below half causes the implicit insetting done by this processor to become
740 // inverted. We could handle this case by making the processor code more complicated.
Brian Osman50f0dad2021-07-08 13:47:25 -0400741 if (radius < .5f && GrClipEdgeTypeIsInverseFill(edgeType)) {
Brian Osmanb384eb22021-06-24 15:34:08 -0400742 return GrFPFailure(std::move(inputFP));
743 }
744
745 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, CLIP_EDGE_SKSL R"(
746 uniform int edgeType; // GrClipEdgeType, specialized
747 // The circle uniform is (center.x, center.y, radius + 0.5, 1 / (radius + 0.5)) for regular
748 // fills and (..., radius - 0.5, 1 / (radius - 0.5)) for inverse fills.
749 uniform float4 circle;
750
751 half4 main(float2 xy, half4 inColor) {
752 // TODO: Right now the distance to circle calculation is performed in a space normalized
753 // to the radius and then denormalized. This is to mitigate overflow on devices that
754 // don't have full float.
755 half d;
756 if (edgeType == kInverseFillBW || edgeType == kInverseFillAA) {
757 d = half((length((circle.xy - sk_FragCoord.xy) * circle.w) - 1.0) * circle.z);
758 } else {
759 d = half((1.0 - length((circle.xy - sk_FragCoord.xy) * circle.w)) * circle.z);
760 }
761 if (edgeType == kFillAA || edgeType == kInverseFillAA) {
762 return inColor * saturate(d);
763 } else {
764 return d > 0.5 ? inColor : half4(0);
765 }
766 }
767 )");
768
769 SkScalar effectiveRadius = radius;
Brian Osman50f0dad2021-07-08 13:47:25 -0400770 if (GrClipEdgeTypeIsInverseFill(edgeType)) {
Brian Osmanb384eb22021-06-24 15:34:08 -0400771 effectiveRadius -= 0.5f;
772 // When the radius is 0.5 effectiveRadius is 0 which causes an inf * 0 in the shader.
773 effectiveRadius = std::max(0.001f, effectiveRadius);
774 } else {
775 effectiveRadius += 0.5f;
776 }
777 SkV4 circle = {center.fX, center.fY, effectiveRadius, SkScalarInvert(effectiveRadius)};
778
779 return GrFPSuccess(GrSkSLFP::Make(effect, "Circle", std::move(inputFP),
780 GrSkSLFP::OptFlags::kCompatibleWithCoverageAsAlpha,
781 "edgeType", GrSkSLFP::Specialize(static_cast<int>(edgeType)),
782 "circle", circle));
783}
784
785GrFPResult GrFragmentProcessor::Ellipse(std::unique_ptr<GrFragmentProcessor> inputFP,
786 GrClipEdgeType edgeType,
787 SkPoint center,
788 SkPoint radii,
789 const GrShaderCaps& caps) {
790 const bool medPrecision = !caps.floatIs32Bits();
791
792 // Small radii produce bad results on devices without full float.
793 if (medPrecision && (radii.fX < 0.5f || radii.fY < 0.5f)) {
794 return GrFPFailure(std::move(inputFP));
795 }
796 // Very narrow ellipses produce bad results on devices without full float
797 if (medPrecision && (radii.fX > 255*radii.fY || radii.fY > 255*radii.fX)) {
798 return GrFPFailure(std::move(inputFP));
799 }
800 // Very large ellipses produce bad results on devices without full float
801 if (medPrecision && (radii.fX > 16384 || radii.fY > 16384)) {
802 return GrFPFailure(std::move(inputFP));
803 }
804
805 static auto effect = SkMakeRuntimeEffect(SkRuntimeEffect::MakeForShader, CLIP_EDGE_SKSL R"(
806 uniform int edgeType; // GrClipEdgeType, specialized
807 uniform int medPrecision; // !sk_Caps.floatIs32Bits, specialized
808
809 uniform float4 ellipse;
810 uniform float2 scale; // only for medPrecision
811
812 half4 main(float2 xy, half4 inColor) {
813 // d is the offset to the ellipse center
814 float2 d = sk_FragCoord.xy - ellipse.xy;
815 // If we're on a device with a "real" mediump then we'll do the distance computation in
816 // a space that is normalized by the larger radius or 128, whichever is smaller. The
817 // scale uniform will be scale, 1/scale. The inverse squared radii uniform values are
818 // already in this normalized space. The center is not.
819 if (bool(medPrecision)) {
820 d *= scale.y;
821 }
822 float2 Z = d * ellipse.zw;
823 // implicit is the evaluation of (x/rx)^2 + (y/ry)^2 - 1.
824 float implicit = dot(Z, d) - 1;
825 // grad_dot is the squared length of the gradient of the implicit.
826 float grad_dot = 4 * dot(Z, Z);
827 // Avoid calling inversesqrt on zero.
828 if (bool(medPrecision)) {
829 grad_dot = max(grad_dot, 6.1036e-5);
830 } else {
831 grad_dot = max(grad_dot, 1.1755e-38);
832 }
833 float approx_dist = implicit * inversesqrt(grad_dot);
834 if (bool(medPrecision)) {
835 approx_dist *= scale.x;
836 }
837
838 half alpha;
839 if (edgeType == kFillBW) {
840 alpha = approx_dist > 0.0 ? 0.0 : 1.0;
841 } else if (edgeType == kFillAA) {
842 alpha = saturate(0.5 - half(approx_dist));
843 } else if (edgeType == kInverseFillBW) {
844 alpha = approx_dist > 0.0 ? 1.0 : 0.0;
845 } else { // edgeType == kInverseFillAA
846 alpha = saturate(0.5 + half(approx_dist));
847 }
848 return inColor * alpha;
849 }
850 )");
851
852 float invRXSqd;
853 float invRYSqd;
854 SkV2 scale = {1, 1};
855 // If we're using a scale factor to work around precision issues, choose the larger radius as
856 // the scale factor. The inv radii need to be pre-adjusted by the scale factor.
857 if (medPrecision) {
858 if (radii.fX > radii.fY) {
859 invRXSqd = 1.f;
860 invRYSqd = (radii.fX * radii.fX) / (radii.fY * radii.fY);
861 scale = {radii.fX, 1.f / radii.fX};
862 } else {
863 invRXSqd = (radii.fY * radii.fY) / (radii.fX * radii.fX);
864 invRYSqd = 1.f;
865 scale = {radii.fY, 1.f / radii.fY};
866 }
867 } else {
868 invRXSqd = 1.f / (radii.fX * radii.fX);
869 invRYSqd = 1.f / (radii.fY * radii.fY);
870 }
871 SkV4 ellipse = {center.fX, center.fY, invRXSqd, invRYSqd};
872
873 return GrFPSuccess(GrSkSLFP::Make(effect, "Ellipse", std::move(inputFP),
874 GrSkSLFP::OptFlags::kCompatibleWithCoverageAsAlpha,
875 "edgeType", GrSkSLFP::Specialize(static_cast<int>(edgeType)),
876 "medPrecision", GrSkSLFP::Specialize<int>(medPrecision),
877 "ellipse", ellipse,
878 "scale", scale));
879}
880
881//////////////////////////////////////////////////////////////////////////////
882
Brian Osman043f0102021-06-30 14:30:34 -0400883std::unique_ptr<GrFragmentProcessor> GrFragmentProcessor::HighPrecision(
884 std::unique_ptr<GrFragmentProcessor> fp) {
885 class HighPrecisionFragmentProcessor : public GrFragmentProcessor {
886 public:
887 static std::unique_ptr<GrFragmentProcessor> Make(std::unique_ptr<GrFragmentProcessor> fp) {
888 return std::unique_ptr<GrFragmentProcessor>(
889 new HighPrecisionFragmentProcessor(std::move(fp)));
890 }
891
892 const char* name() const override { return "HighPrecision"; }
893
894 std::unique_ptr<GrFragmentProcessor> clone() const override {
895 return Make(this->childProcessor(0)->clone());
896 }
897
898 private:
899 HighPrecisionFragmentProcessor(std::unique_ptr<GrFragmentProcessor> fp)
900 : INHERITED(kHighPrecisionFragmentProcessor_ClassID,
901 ProcessorOptimizationFlags(fp.get())) {
902 this->registerChild(std::move(fp));
903 }
904
Brian Salomon3176e862021-08-09 11:23:04 -0400905 std::unique_ptr<ProgramImpl> onMakeProgramImpl() const override {
Brian Salomonb25560a2021-08-10 13:56:13 -0400906 class Impl : public ProgramImpl {
Brian Osman043f0102021-06-30 14:30:34 -0400907 public:
908 void emitCode(EmitArgs& args) override {
909 SkString childColor = this->invokeChild(0, args);
910
911 args.fFragBuilder->forceHighPrecision();
912 args.fFragBuilder->codeAppendf("return %s;", childColor.c_str());
913 }
914 };
Brian Salomonb25560a2021-08-10 13:56:13 -0400915 return std::make_unique<Impl>();
Brian Osman043f0102021-06-30 14:30:34 -0400916 }
917
Brian Salomon13b28732021-08-06 15:33:58 -0400918 void onAddToKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override {}
Brian Osman043f0102021-06-30 14:30:34 -0400919 bool onIsEqual(const GrFragmentProcessor& other) const override { return true; }
920
921 SkPMColor4f constantOutputForConstantInput(const SkPMColor4f& input) const override {
922 return ConstantOutputForConstantInput(this->childProcessor(0), input);
923 }
924
925 using INHERITED = GrFragmentProcessor;
926 };
927
928 return HighPrecisionFragmentProcessor::Make(std::move(fp));
929}
Brian Salomon48959462021-08-11 13:01:06 -0400930
931//////////////////////////////////////////////////////////////////////////////
932
933using ProgramImpl = GrFragmentProcessor::ProgramImpl;
934
935void ProgramImpl::setData(const GrGLSLProgramDataManager& pdman,
936 const GrFragmentProcessor& processor) {
937 this->onSetData(pdman, processor);
938}
939
Brian Salomon48959462021-08-11 13:01:06 -0400940SkString ProgramImpl::invokeChild(int childIndex,
941 const char* inputColor,
942 const char* destColor,
943 EmitArgs& args,
944 SkSL::String skslCoords) {
945 SkASSERT(childIndex >= 0);
946
947 if (!inputColor) {
948 inputColor = args.fInputColor;
949 }
950
951 const GrFragmentProcessor* childProc = args.fFp.childProcessor(childIndex);
952 if (!childProc) {
953 // If no child processor is provided, return the input color as-is.
954 return SkString(inputColor);
955 }
956
957 auto invocation = SkStringPrintf("%s(%s", this->childProcessor(childIndex)->functionName(),
958 inputColor);
959
960 if (childProc->isBlendFunction()) {
961 if (!destColor) {
962 destColor = args.fFp.isBlendFunction() ? args.fDestColor : "half4(1)";
963 }
964 invocation.appendf(", %s", destColor);
965 }
966
967 // Assert that the child has no sample matrix. A uniform matrix sample call would go through
968 // invokeChildWithMatrix, not here.
969 SkASSERT(!childProc->sampleUsage().isUniformMatrix());
970
971 if (args.fFragBuilder->getProgramBuilder()->fragmentProcessorHasCoordsParam(childProc)) {
972 SkASSERT(!childProc->sampleUsage().isFragCoord() || skslCoords == "sk_FragCoord.xy");
973 // The child's function takes a half4 color and a float2 coordinate
974 invocation.appendf(", %s", skslCoords.empty() ? args.fSampleCoord : skslCoords.c_str());
975 }
976
977 invocation.append(")");
978 return invocation;
979}
980
981SkString ProgramImpl::invokeChildWithMatrix(int childIndex,
982 const char* inputColor,
983 const char* destColor,
984 EmitArgs& args) {
985 SkASSERT(childIndex >= 0);
986
987 if (!inputColor) {
988 inputColor = args.fInputColor;
989 }
990
991 const GrFragmentProcessor* childProc = args.fFp.childProcessor(childIndex);
992 if (!childProc) {
993 // If no child processor is provided, return the input color as-is.
994 return SkString(inputColor);
995 }
996
997 SkASSERT(childProc->sampleUsage().isUniformMatrix());
998
999 // Every uniform matrix has the same (initial) name. Resolve that into the mangled name:
1000 GrShaderVar uniform = args.fUniformHandler->getUniformMapping(
1001 args.fFp, SkString(SkSL::SampleUsage::MatrixUniformName()));
1002 SkASSERT(uniform.getType() == kFloat3x3_GrSLType);
1003 const SkString& matrixName(uniform.getName());
1004
1005 auto invocation = SkStringPrintf("%s(%s", this->childProcessor(childIndex)->functionName(),
1006 inputColor);
1007
1008 if (childProc->isBlendFunction()) {
1009 if (!destColor) {
1010 destColor = args.fFp.isBlendFunction() ? args.fDestColor : "half4(1)";
1011 }
1012 invocation.appendf(", %s", destColor);
1013 }
1014
1015 // Produce a string containing the call to the helper function. We have a uniform variable
1016 // containing our transform (matrixName). If the parent coords were produced by uniform
1017 // transforms, then the entire expression (matrixName * coords) is lifted to a vertex shader
1018 // and is stored in a varying. In that case, childProc will not be sampled explicitly, so its
1019 // function signature will not take in coords.
1020 //
1021 // In all other cases, we need to insert sksl to compute matrix * parent coords and then invoke
1022 // the function.
1023 if (args.fFragBuilder->getProgramBuilder()->fragmentProcessorHasCoordsParam(childProc)) {
1024 // Only check perspective for this specific matrix transform, not the aggregate FP property.
1025 // Any parent perspective will have already been applied when evaluated in the FS.
1026 if (childProc->sampleUsage().hasPerspective()) {
1027 invocation.appendf(", proj((%s) * %s.xy1)", matrixName.c_str(), args.fSampleCoord);
1028 } else if (args.fShaderCaps->nonsquareMatrixSupport()) {
1029 invocation.appendf(", float3x2(%s) * %s.xy1", matrixName.c_str(), args.fSampleCoord);
1030 } else {
1031 invocation.appendf(", ((%s) * %s.xy1).xy", matrixName.c_str(), args.fSampleCoord);
1032 }
1033 }
1034
1035 invocation.append(")");
1036 return invocation;
1037}