blob: ccfc72e6104918aeb3d91de4e0e42945189423fc [file] [log] [blame]
commit-bot@chromium.org3eedb802014-03-28 15:58:31 +00001/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrOvalEffect.h"
joshualitteb2a6762014-12-04 11:35:33 -08009
Ethan Nicholas83d11852017-07-13 16:00:16 -040010#include "GrCircleEffect.h"
joshualitteb2a6762014-12-04 11:35:33 -080011#include "GrFragmentProcessor.h"
joshualitteb2a6762014-12-04 11:35:33 -080012#include "SkRect.h"
Brian Salomon94efbf52016-11-29 13:43:05 -050013#include "GrShaderCaps.h"
egdaniel64c47282015-11-13 06:54:19 -080014#include "glsl/GrGLSLFragmentProcessor.h"
egdaniel2d721d32015-11-11 13:06:05 -080015#include "glsl/GrGLSLFragmentShaderBuilder.h"
egdaniel018fb622015-10-28 07:26:40 -070016#include "glsl/GrGLSLProgramDataManager.h"
egdaniel7ea439b2015-12-03 09:20:44 -080017#include "glsl/GrGLSLUniformHandler.h"
Brian Salomon94efbf52016-11-29 13:43:05 -050018#include "../private/GrGLSL.h"
commit-bot@chromium.org3eedb802014-03-28 15:58:31 +000019
20//////////////////////////////////////////////////////////////////////////////
21
joshualittb0a8a372014-09-23 09:50:21 -070022class EllipseEffect : public GrFragmentProcessor {
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +000023public:
bungeman06ca8ec2016-06-09 08:01:03 -070024 static sk_sp<GrFragmentProcessor> Make(GrPrimitiveEdgeType, const SkPoint& center,
25 SkScalar rx, SkScalar ry);
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +000026
Brian Salomond3b65972017-03-22 12:05:03 -040027 ~EllipseEffect() override {}
joshualitteb2a6762014-12-04 11:35:33 -080028
mtklein36352bf2015-03-25 18:17:31 -070029 const char* name() const override { return "Ellipse"; }
joshualitteb2a6762014-12-04 11:35:33 -080030
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +000031 const SkPoint& getCenter() const { return fCenter; }
32 SkVector getRadii() const { return fRadii; }
33
joshualittb0a8a372014-09-23 09:50:21 -070034 GrPrimitiveEdgeType getEdgeType() const { return fEdgeType; }
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +000035
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +000036private:
joshualittb0a8a372014-09-23 09:50:21 -070037 EllipseEffect(GrPrimitiveEdgeType, const SkPoint& center, SkScalar rx, SkScalar ry);
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +000038
egdaniel57d3b032015-11-13 11:57:27 -080039 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -070040
Brian Salomon94efbf52016-11-29 13:43:05 -050041 void onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -070042
mtklein36352bf2015-03-25 18:17:31 -070043 bool onIsEqual(const GrFragmentProcessor&) const override;
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +000044
45 SkPoint fCenter;
46 SkVector fRadii;
joshualittb0a8a372014-09-23 09:50:21 -070047 GrPrimitiveEdgeType fEdgeType;
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +000048
Brian Salomon0c26a9d2017-07-06 10:09:38 -040049 GR_DECLARE_FRAGMENT_PROCESSOR_TEST
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +000050
joshualittb0a8a372014-09-23 09:50:21 -070051 typedef GrFragmentProcessor INHERITED;
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +000052};
53
bungeman06ca8ec2016-06-09 08:01:03 -070054sk_sp<GrFragmentProcessor> EllipseEffect::Make(GrPrimitiveEdgeType edgeType,
55 const SkPoint& center,
56 SkScalar rx,
57 SkScalar ry) {
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +000058 SkASSERT(rx >= 0 && ry >= 0);
bungeman06ca8ec2016-06-09 08:01:03 -070059 return sk_sp<GrFragmentProcessor>(new EllipseEffect(edgeType, center, rx, ry));
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +000060}
61
Brian Salomon587e08f2017-01-27 10:59:27 -050062EllipseEffect::EllipseEffect(GrPrimitiveEdgeType edgeType, const SkPoint& c, SkScalar rx,
63 SkScalar ry)
Brian Salomonf3b995b2017-02-15 10:22:23 -050064 : INHERITED(kCompatibleWithCoverageAsAlpha_OptimizationFlag)
Brian Salomon587e08f2017-01-27 10:59:27 -050065 , fCenter(c)
66 , fRadii(SkVector::Make(rx, ry))
67 , fEdgeType(edgeType) {
joshualitteb2a6762014-12-04 11:35:33 -080068 this->initClassID<EllipseEffect>();
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +000069}
70
bsalomon0e08fc12014-10-15 08:19:04 -070071bool EllipseEffect::onIsEqual(const GrFragmentProcessor& other) const {
joshualitt49586be2014-09-16 08:21:41 -070072 const EllipseEffect& ee = other.cast<EllipseEffect>();
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +000073 return fEdgeType == ee.fEdgeType && fCenter == ee.fCenter && fRadii == ee.fRadii;
74}
75
76//////////////////////////////////////////////////////////////////////////////
77
joshualittb0a8a372014-09-23 09:50:21 -070078GR_DEFINE_FRAGMENT_PROCESSOR_TEST(EllipseEffect);
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +000079
Hal Canary6f6961e2017-01-31 13:50:44 -050080#if GR_TEST_UTILS
bungeman06ca8ec2016-06-09 08:01:03 -070081sk_sp<GrFragmentProcessor> EllipseEffect::TestCreate(GrProcessorTestData* d) {
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +000082 SkPoint center;
joshualitt0067ff52015-07-08 14:26:19 -070083 center.fX = d->fRandom->nextRangeScalar(0.f, 1000.f);
84 center.fY = d->fRandom->nextRangeScalar(0.f, 1000.f);
85 SkScalar rx = d->fRandom->nextRangeF(0.f, 1000.f);
86 SkScalar ry = d->fRandom->nextRangeF(0.f, 1000.f);
joshualittb0a8a372014-09-23 09:50:21 -070087 GrPrimitiveEdgeType et;
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +000088 do {
joshualitt0067ff52015-07-08 14:26:19 -070089 et = (GrPrimitiveEdgeType)d->fRandom->nextULessThan(kGrProcessorEdgeTypeCnt);
joshualittb0a8a372014-09-23 09:50:21 -070090 } while (kHairlineAA_GrProcessorEdgeType == et);
bungeman06ca8ec2016-06-09 08:01:03 -070091 return EllipseEffect::Make(et, center, rx, ry);
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +000092}
Hal Canary6f6961e2017-01-31 13:50:44 -050093#endif
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +000094
95//////////////////////////////////////////////////////////////////////////////
96
egdaniel64c47282015-11-13 06:54:19 -080097class GLEllipseEffect : public GrGLSLFragmentProcessor {
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +000098public:
robertphillips9cdb9922016-02-03 12:25:40 -080099 GLEllipseEffect() {
100 fPrevRadii.fX = -1.0f;
101 }
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +0000102
robertphillips9cdb9922016-02-03 12:25:40 -0800103 void emitCode(EmitArgs&) override;
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +0000104
Brian Salomon94efbf52016-11-29 13:43:05 -0500105 static inline void GenKey(const GrProcessor&, const GrShaderCaps&, GrProcessorKeyBuilder*);
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +0000106
wangyixb1daa862015-08-18 11:29:31 -0700107protected:
Brian Salomonab015ef2017-04-04 10:15:51 -0400108 void onSetData(const GrGLSLProgramDataManager&, const GrFragmentProcessor&) override;
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +0000109
110private:
egdaniel018fb622015-10-28 07:26:40 -0700111 GrGLSLProgramDataManager::UniformHandle fEllipseUniform;
bsalomone87256c42015-12-09 17:14:40 -0800112 GrGLSLProgramDataManager::UniformHandle fScaleUniform;
egdaniel018fb622015-10-28 07:26:40 -0700113 SkPoint fPrevCenter;
114 SkVector fPrevRadii;
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +0000115
egdaniel64c47282015-11-13 06:54:19 -0800116 typedef GrGLSLFragmentProcessor INHERITED;
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +0000117};
118
wangyix7c157a92015-07-22 15:08:53 -0700119void GLEllipseEffect::emitCode(EmitArgs& args) {
120 const EllipseEffect& ee = args.fFp.cast<EllipseEffect>();
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +0000121 const char *ellipseName;
122 // The ellipse uniform is (center.x, center.y, 1 / rx^2, 1 / ry^2)
bsalomonc41f4d62015-08-03 14:23:03 -0700123 // The last two terms can underflow on mediump, so we use highp.
cdalton5e58cee2016-02-11 12:49:47 -0800124 fEllipseUniform = args.fUniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800125 kVec4f_GrSLType, kHigh_GrSLPrecision,
126 "ellipse",
127 &ellipseName);
bsalomone87256c42015-12-09 17:14:40 -0800128 // If we're on a device with a "real" mediump then we'll do the distance computation in a space
129 // that is normalized by the larger radius. The scale uniform will be scale, 1/scale. The
130 // inverse squared radii uniform values are already in this normalized space. The center is
131 // not.
132 const char* scaleName = nullptr;
Brian Salomon1edc5b92016-11-29 13:43:46 -0500133 if (args.fShaderCaps->floatPrecisionVaries()) {
bsalomone87256c42015-12-09 17:14:40 -0800134 fScaleUniform = args.fUniformHandler->addUniform(
cdalton5e58cee2016-02-11 12:49:47 -0800135 kFragment_GrShaderFlag, kVec2f_GrSLType, kDefault_GrSLPrecision,
bsalomone87256c42015-12-09 17:14:40 -0800136 "scale", &scaleName);
137 }
joshualitt30ba4362014-08-21 20:18:45 -0700138
cdalton85285412016-02-18 12:37:07 -0800139 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +0000140
141 // d is the offset to the ellipse center
Ethan Nicholas38657112017-02-09 17:01:22 -0500142 fragBuilder->codeAppendf("vec2 d = sk_FragCoord.xy - %s.xy;", ellipseName);
bsalomone87256c42015-12-09 17:14:40 -0800143 if (scaleName) {
144 fragBuilder->codeAppendf("d *= %s.y;", scaleName);
145 }
146 fragBuilder->codeAppendf("vec2 Z = d * %s.zw;", ellipseName);
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +0000147 // implicit is the evaluation of (x/rx)^2 + (y/ry)^2 - 1.
bsalomone87256c42015-12-09 17:14:40 -0800148 fragBuilder->codeAppend("float implicit = dot(Z, d) - 1.0;");
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +0000149 // grad_dot is the squared length of the gradient of the implicit.
bsalomone87256c42015-12-09 17:14:40 -0800150 fragBuilder->codeAppendf("float grad_dot = 4.0 * dot(Z, Z);");
151 // Avoid calling inversesqrt on zero.
152 fragBuilder->codeAppend("grad_dot = max(grad_dot, 1.0e-4);");
153 fragBuilder->codeAppendf("float approx_dist = implicit * inversesqrt(grad_dot);");
154 if (scaleName) {
155 fragBuilder->codeAppendf("approx_dist *= %s.x;", scaleName);
156 }
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +0000157
158 switch (ee.getEdgeType()) {
joshualittb0a8a372014-09-23 09:50:21 -0700159 case kFillAA_GrProcessorEdgeType:
bsalomone87256c42015-12-09 17:14:40 -0800160 fragBuilder->codeAppend("float alpha = clamp(0.5 - approx_dist, 0.0, 1.0);");
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +0000161 break;
joshualittb0a8a372014-09-23 09:50:21 -0700162 case kInverseFillAA_GrProcessorEdgeType:
bsalomone87256c42015-12-09 17:14:40 -0800163 fragBuilder->codeAppend("float alpha = clamp(0.5 + approx_dist, 0.0, 1.0);");
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +0000164 break;
joshualittb0a8a372014-09-23 09:50:21 -0700165 case kFillBW_GrProcessorEdgeType:
bsalomone87256c42015-12-09 17:14:40 -0800166 fragBuilder->codeAppend("float alpha = approx_dist > 0.0 ? 0.0 : 1.0;");
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +0000167 break;
joshualittb0a8a372014-09-23 09:50:21 -0700168 case kInverseFillBW_GrProcessorEdgeType:
bsalomone87256c42015-12-09 17:14:40 -0800169 fragBuilder->codeAppend("float alpha = approx_dist > 0.0 ? 1.0 : 0.0;");
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +0000170 break;
joshualittb0a8a372014-09-23 09:50:21 -0700171 case kHairlineAA_GrProcessorEdgeType:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +0000172 SkFAIL("Hairline not expected here.");
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +0000173 }
174
Ethan Nicholas2983f402017-05-08 09:36:08 -0400175 fragBuilder->codeAppendf("%s = %s * alpha;", args.fOutputColor, args.fInputColor);
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +0000176}
177
Brian Salomon94efbf52016-11-29 13:43:05 -0500178void GLEllipseEffect::GenKey(const GrProcessor& effect, const GrShaderCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700179 GrProcessorKeyBuilder* b) {
joshualitt49586be2014-09-16 08:21:41 -0700180 const EllipseEffect& ee = effect.cast<EllipseEffect>();
bsalomon63e99f72014-07-21 08:03:14 -0700181 b->add32(ee.getEdgeType());
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +0000182}
183
egdaniel018fb622015-10-28 07:26:40 -0700184void GLEllipseEffect::onSetData(const GrGLSLProgramDataManager& pdman,
Brian Salomonab015ef2017-04-04 10:15:51 -0400185 const GrFragmentProcessor& effect) {
joshualitt49586be2014-09-16 08:21:41 -0700186 const EllipseEffect& ee = effect.cast<EllipseEffect>();
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +0000187 if (ee.getRadii() != fPrevRadii || ee.getCenter() != fPrevCenter) {
bsalomone87256c42015-12-09 17:14:40 -0800188 float invRXSqd;
189 float invRYSqd;
190 // If we're using a scale factor to work around precision issues, choose the larger radius
191 // as the scale factor. The inv radii need to be pre-adjusted by the scale factor.
192 if (fScaleUniform.isValid()) {
193 if (ee.getRadii().fX > ee.getRadii().fY) {
194 invRXSqd = 1.f;
195 invRYSqd = (ee.getRadii().fX * ee.getRadii().fX) /
196 (ee.getRadii().fY * ee.getRadii().fY);
197 pdman.set2f(fScaleUniform, ee.getRadii().fX, 1.f / ee.getRadii().fX);
198 } else {
199 invRXSqd = (ee.getRadii().fY * ee.getRadii().fY) /
200 (ee.getRadii().fX * ee.getRadii().fX);
201 invRYSqd = 1.f;
202 pdman.set2f(fScaleUniform, ee.getRadii().fY, 1.f / ee.getRadii().fY);
203 }
204 } else {
205 invRXSqd = 1.f / (ee.getRadii().fX * ee.getRadii().fX);
206 invRYSqd = 1.f / (ee.getRadii().fY * ee.getRadii().fY);
207 }
kkinnunen7510b222014-07-30 00:04:16 -0700208 pdman.set4f(fEllipseUniform, ee.getCenter().fX, ee.getCenter().fY, invRXSqd, invRYSqd);
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +0000209 fPrevCenter = ee.getCenter();
210 fPrevRadii = ee.getRadii();
211 }
212}
213
joshualitteb2a6762014-12-04 11:35:33 -0800214///////////////////////////////////////////////////////////////////////////////////////////////////
215
Brian Salomon94efbf52016-11-29 13:43:05 -0500216void EllipseEffect::onGetGLSLProcessorKey(const GrShaderCaps& caps,
egdaniel57d3b032015-11-13 11:57:27 -0800217 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -0800218 GLEllipseEffect::GenKey(*this, caps, b);
219}
220
egdaniel57d3b032015-11-13 11:57:27 -0800221GrGLSLFragmentProcessor* EllipseEffect::onCreateGLSLInstance() const {
robertphillips9cdb9922016-02-03 12:25:40 -0800222 return new GLEllipseEffect;
joshualitteb2a6762014-12-04 11:35:33 -0800223}
224
commit-bot@chromium.org3eedb802014-03-28 15:58:31 +0000225//////////////////////////////////////////////////////////////////////////////
226
bungeman06ca8ec2016-06-09 08:01:03 -0700227sk_sp<GrFragmentProcessor> GrOvalEffect::Make(GrPrimitiveEdgeType edgeType, const SkRect& oval) {
joshualittb0a8a372014-09-23 09:50:21 -0700228 if (kHairlineAA_GrProcessorEdgeType == edgeType) {
halcanary96fcdcc2015-08-27 07:41:13 -0700229 return nullptr;
commit-bot@chromium.org3eedb802014-03-28 15:58:31 +0000230 }
231 SkScalar w = oval.width();
232 SkScalar h = oval.height();
233 if (SkScalarNearlyEqual(w, h)) {
234 w /= 2;
Ethan Nicholas83d11852017-07-13 16:00:16 -0400235 return GrCircleEffect::Make(edgeType, SkPoint::Make(oval.fLeft + w, oval.fTop + w), w);
commit-bot@chromium.orgd0a50292014-04-02 15:00:39 +0000236 } else {
237 w /= 2;
238 h /= 2;
bungeman06ca8ec2016-06-09 08:01:03 -0700239 return EllipseEffect::Make(edgeType, SkPoint::Make(oval.fLeft + w, oval.fTop + h), w, h);
commit-bot@chromium.org3eedb802014-03-28 15:58:31 +0000240 }
241
halcanary96fcdcc2015-08-27 07:41:13 -0700242 return nullptr;
commit-bot@chromium.org3eedb802014-03-28 15:58:31 +0000243}