blob: 91b0a9326db84e52c7db5828155277d3ee3af0de [file] [log] [blame]
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +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 */
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00007
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00008#include "SkTwoPointConicalGradient_gpu.h"
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00009
10#include "SkTwoPointConicalGradient.h"
11
commit-bot@chromium.orgef93d292014-04-10 15:37:52 +000012#if SK_SUPPORT_GPU
egdaniel7ea439b2015-12-03 09:20:44 -080013#include "GrCoordTransform.h"
14#include "GrInvariantOutput.h"
joshualitt8ca93e72015-07-08 06:51:43 -070015#include "GrPaint.h"
egdaniel2d721d32015-11-11 13:06:05 -080016#include "glsl/GrGLSLFragmentShaderBuilder.h"
egdaniel018fb622015-10-28 07:26:40 -070017#include "glsl/GrGLSLProgramDataManager.h"
egdaniel7ea439b2015-12-03 09:20:44 -080018#include "glsl/GrGLSLUniformHandler.h"
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000019// For brevity
egdaniel018fb622015-10-28 07:26:40 -070020typedef GrGLSLProgramDataManager::UniformHandle UniformHandle;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000021
commit-bot@chromium.org80894672014-04-22 21:24:22 +000022static const SkScalar kErrorTol = 0.00001f;
egdaniel8405ef92014-06-09 11:57:28 -070023static const SkScalar kEdgeErrorTol = 5.f * kErrorTol;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000024
25/**
26 * We have three general cases for 2pt conical gradients. First we always assume that
27 * the start radius <= end radius. Our first case (kInside_) is when the start circle
28 * is completely enclosed by the end circle. The second case (kOutside_) is the case
29 * when the start circle is either completely outside the end circle or the circles
30 * overlap. The final case (kEdge_) is when the start circle is inside the end one,
31 * but the two are just barely touching at 1 point along their edges.
32 */
33enum ConicalType {
34 kInside_ConicalType,
35 kOutside_ConicalType,
36 kEdge_ConicalType,
37};
38
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000039//////////////////////////////////////////////////////////////////////////////
40
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000041static void set_matrix_edge_conical(const SkTwoPointConicalGradient& shader,
42 SkMatrix* invLMatrix) {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000043 // Inverse of the current local matrix is passed in then,
44 // translate to center1, rotate so center2 is on x axis.
45 const SkPoint& center1 = shader.getStartCenter();
46 const SkPoint& center2 = shader.getEndCenter();
47
48 invLMatrix->postTranslate(-center1.fX, -center1.fY);
49
50 SkPoint diff = center2 - center1;
51 SkScalar diffLen = diff.length();
52 if (0 != diffLen) {
53 SkScalar invDiffLen = SkScalarInvert(diffLen);
54 SkMatrix rot;
55 rot.setSinCos(-SkScalarMul(invDiffLen, diff.fY),
56 SkScalarMul(invDiffLen, diff.fX));
57 invLMatrix->postConcat(rot);
58 }
59}
60
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000061class Edge2PtConicalEffect : public GrGradientEffect {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +000062public:
63
bungeman06ca8ec2016-06-09 08:01:03 -070064 static sk_sp<GrFragmentProcessor> Make(GrContext* ctx,
65 const SkTwoPointConicalGradient& shader,
66 const SkMatrix& matrix,
67 SkShader::TileMode tm) {
68 return sk_sp<GrFragmentProcessor>(new Edge2PtConicalEffect(ctx, shader, matrix, tm));
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000069 }
70
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000071 virtual ~Edge2PtConicalEffect() {}
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000072
mtklein36352bf2015-03-25 18:17:31 -070073 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -080074 return "Two-Point Conical Gradient Edge Touching";
75 }
76
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000077 // The radial gradient parameters can collapse to a linear (instead of quadratic) equation.
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000078 SkScalar center() const { return fCenterX1; }
79 SkScalar diffRadius() const { return fDiffRadius; }
80 SkScalar radius() const { return fRadius0; }
81
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000082private:
egdaniel57d3b032015-11-13 11:57:27 -080083 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -070084
egdaniel57d3b032015-11-13 11:57:27 -080085 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -070086
mtklein36352bf2015-03-25 18:17:31 -070087 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -070088 const Edge2PtConicalEffect& s = sBase.cast<Edge2PtConicalEffect>();
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000089 return (INHERITED::onIsEqual(sBase) &&
90 this->fCenterX1 == s.fCenterX1 &&
91 this->fRadius0 == s.fRadius0 &&
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000092 this->fDiffRadius == s.fDiffRadius);
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +000093 }
94
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +000095 Edge2PtConicalEffect(GrContext* ctx,
96 const SkTwoPointConicalGradient& shader,
97 const SkMatrix& matrix,
98 SkShader::TileMode tm)
bsalomon4a339522015-10-06 08:40:50 -070099 : INHERITED(ctx, shader, matrix, tm),
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +0000100 fCenterX1(shader.getCenterX1()),
101 fRadius0(shader.getStartRadius()),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000102 fDiffRadius(shader.getDiffRadius()){
joshualitteb2a6762014-12-04 11:35:33 -0800103 this->initClassID<Edge2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000104 // We should only be calling this shader if we are degenerate case with touching circles
egdaniel8405ef92014-06-09 11:57:28 -0700105 // When deciding if we are in edge case, we scaled by the end radius for cases when the
joshualitt01258472014-09-22 10:29:30 -0700106 // start radius was close to zero, otherwise we scaled by the start radius. In addition
107 // Our test for the edge case in set_matrix_circle_conical has a higher tolerance so we
108 // need the sqrt value below
109 SkASSERT(SkScalarAbs(SkScalarAbs(fDiffRadius) - fCenterX1) <
110 (fRadius0 < kErrorTol ? shader.getEndRadius() * kEdgeErrorTol :
111 fRadius0 * sqrt(kEdgeErrorTol)));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000112
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +0000113 // We pass the linear part of the quadratic as a varying.
114 // float b = -2.0 * (fCenterX1 * x + fRadius0 * fDiffRadius * z)
115 fBTransform = this->getCoordTransform();
116 SkMatrix& bMatrix = *fBTransform.accessMatrix();
117 SkScalar r0dr = SkScalarMul(fRadius0, fDiffRadius);
118 bMatrix[SkMatrix::kMScaleX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMScaleX]) +
119 SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp0]));
120 bMatrix[SkMatrix::kMSkewX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMSkewX]) +
121 SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp1]));
122 bMatrix[SkMatrix::kMTransX] = -2 * (SkScalarMul(fCenterX1, bMatrix[SkMatrix::kMTransX]) +
123 SkScalarMul(r0dr, bMatrix[SkMatrix::kMPersp2]));
124 this->addCoordTransform(&fBTransform);
125 }
126
joshualittb0a8a372014-09-23 09:50:21 -0700127 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +0000128
129 // @{
130 // Cache of values - these can change arbitrarily, EXCEPT
131 // we shouldn't change between degenerate and non-degenerate?!
132
133 GrCoordTransform fBTransform;
134 SkScalar fCenterX1;
135 SkScalar fRadius0;
136 SkScalar fDiffRadius;
137
138 // @}
139
140 typedef GrGradientEffect INHERITED;
141};
142
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000143class GLEdge2PtConicalEffect : public GrGLGradientEffect {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +0000144public:
joshualitteb2a6762014-12-04 11:35:33 -0800145 GLEdge2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000146 virtual ~GLEdge2PtConicalEffect() { }
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000147
wangyix7c157a92015-07-22 15:08:53 -0700148 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000149
jvanverthcfc18862015-04-28 08:48:20 -0700150 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000151
152protected:
egdaniel018fb622015-10-28 07:26:40 -0700153 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700154
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000155 UniformHandle fParamUni;
156
157 const char* fVSVaryingName;
158 const char* fFSVaryingName;
159
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000160 // @{
161 /// Values last uploaded as uniforms
162
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000163 SkScalar fCachedRadius;
164 SkScalar fCachedDiffRadius;
165
166 // @}
167
168private:
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000169 typedef GrGLGradientEffect INHERITED;
170
171};
172
egdaniel57d3b032015-11-13 11:57:27 -0800173void Edge2PtConicalEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
174 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -0800175 GLEdge2PtConicalEffect::GenKey(*this, caps, b);
176}
177
egdaniel57d3b032015-11-13 11:57:27 -0800178GrGLSLFragmentProcessor* Edge2PtConicalEffect::onCreateGLSLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700179 return new GLEdge2PtConicalEffect(*this);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000180}
skia.committer@gmail.com221b9112014-04-04 03:04:32 +0000181
joshualittb0a8a372014-09-23 09:50:21 -0700182GR_DEFINE_FRAGMENT_PROCESSOR_TEST(Edge2PtConicalEffect);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000183
joshualitt01258472014-09-22 10:29:30 -0700184/*
185 * All Two point conical gradient test create functions may occasionally create edge case shaders
186 */
bungeman06ca8ec2016-06-09 08:01:03 -0700187sk_sp<GrFragmentProcessor> Edge2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700188 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
189 SkScalar radius1 = d->fRandom->nextUScalar1();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000190 SkPoint center2;
191 SkScalar radius2;
192 do {
joshualitt0067ff52015-07-08 14:26:19 -0700193 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000194 // If the circles are identical the factory will give us an empty shader.
195 // This will happen if we pick identical centers
196 } while (center1 == center2);
197
198 // Below makes sure that circle one is contained within circle two
199 // and both circles are touching on an edge
200 SkPoint diff = center2 - center1;
201 SkScalar diffLen = diff.length();
202 radius2 = radius1 + diffLen;
203
204 SkColor colors[kMaxRandomGradientColors];
205 SkScalar stopsArray[kMaxRandomGradientColors];
206 SkScalar* stops = stopsArray;
207 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -0700208 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
reed8a21c9f2016-03-08 18:50:00 -0800209 auto shader = SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
210 colors, stops, colorCount, tm);
bungeman06ca8ec2016-06-09 08:01:03 -0700211 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(d->fContext,
brianosman982eb7f2016-06-06 13:10:58 -0700212 GrTest::TestMatrix(d->fRandom), NULL, kNone_SkFilterQuality,
213 SkSourceGammaTreatment::kRespect);
bsalomonc21b09e2015-08-28 18:46:56 -0700214 GrAlwaysAssert(fp);
joshualittb0a8a372014-09-23 09:50:21 -0700215 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000216}
217
joshualitteb2a6762014-12-04 11:35:33 -0800218GLEdge2PtConicalEffect::GLEdge2PtConicalEffect(const GrProcessor&)
halcanary96fcdcc2015-08-27 07:41:13 -0700219 : fVSVaryingName(nullptr)
220 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000221 , fCachedRadius(-SK_ScalarMax)
222 , fCachedDiffRadius(-SK_ScalarMax) {}
223
wangyix7c157a92015-07-22 15:08:53 -0700224void GLEdge2PtConicalEffect::emitCode(EmitArgs& args) {
225 const Edge2PtConicalEffect& ge = args.fFp.cast<Edge2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -0800226 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
227 this->emitUniforms(uniformHandler, ge);
jvanverthde11ee42016-02-26 13:58:40 -0800228 fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
229 kVec3f_GrSLType, kDefault_GrSLPrecision,
230 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000231
232 SkString cName("c");
233 SkString tName("t");
234 SkString p0; // start radius
235 SkString p1; // start radius squared
236 SkString p2; // difference in radii (r1 - r0)
237
jvanverthde11ee42016-02-26 13:58:40 -0800238
239 p0.appendf("%s.x", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
240 p1.appendf("%s.y", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
241 p2.appendf("%s.z", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000242
243 // We interpolate the linear component in coords[1].
wangyix7c157a92015-07-22 15:08:53 -0700244 SkASSERT(args.fCoords[0].getType() == args.fCoords[1].getType());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000245 const char* coords2D;
246 SkString bVar;
cdalton85285412016-02-18 12:37:07 -0800247 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
wangyix7c157a92015-07-22 15:08:53 -0700248 if (kVec3f_GrSLType == args.fCoords[0].getType()) {
egdaniel4ca2e602015-11-18 08:01:26 -0800249 fragBuilder->codeAppendf("\tvec3 interpolants = vec3(%s.xy / %s.z, %s.x / %s.z);\n",
wangyix7c157a92015-07-22 15:08:53 -0700250 args.fCoords[0].c_str(), args.fCoords[0].c_str(),
251 args.fCoords[1].c_str(), args.fCoords[1].c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000252 coords2D = "interpolants.xy";
253 bVar = "interpolants.z";
254 } else {
wangyix7c157a92015-07-22 15:08:53 -0700255 coords2D = args.fCoords[0].c_str();
256 bVar.printf("%s.x", args.fCoords[1].c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000257 }
258
259 // output will default to transparent black (we simply won't write anything
260 // else to it if invalid, instead of discarding or returning prematurely)
egdaniel4ca2e602015-11-18 08:01:26 -0800261 fragBuilder->codeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", args.fOutputColor);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000262
263 // c = (x^2)+(y^2) - params[1]
egdaniel4ca2e602015-11-18 08:01:26 -0800264 fragBuilder->codeAppendf("\tfloat %s = dot(%s, %s) - %s;\n",
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000265 cName.c_str(), coords2D, coords2D, p1.c_str());
266
267 // linear case: t = -c/b
egdaniel4ca2e602015-11-18 08:01:26 -0800268 fragBuilder->codeAppendf("\tfloat %s = -(%s / %s);\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000269 cName.c_str(), bVar.c_str());
270
271 // if r(t) > 0, then t will be the x coordinate
egdaniel4ca2e602015-11-18 08:01:26 -0800272 fragBuilder->codeAppendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000273 p2.c_str(), p0.c_str());
egdaniel4ca2e602015-11-18 08:01:26 -0800274 fragBuilder->codeAppend("\t");
egdaniel7ea439b2015-12-03 09:20:44 -0800275 this->emitColor(fragBuilder,
276 uniformHandler,
egdaniela2e3e0f2015-11-19 07:23:45 -0800277 args.fGLSLCaps,
egdaniel4ca2e602015-11-18 08:01:26 -0800278 ge,
279 tName.c_str(),
280 args.fOutputColor,
281 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -0700282 args.fTexSamplers);
egdaniel4ca2e602015-11-18 08:01:26 -0800283 fragBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000284}
285
egdaniel018fb622015-10-28 07:26:40 -0700286void GLEdge2PtConicalEffect::onSetData(const GrGLSLProgramDataManager& pdman,
287 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700288 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700289 const Edge2PtConicalEffect& data = processor.cast<Edge2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000290 SkScalar radius0 = data.radius();
291 SkScalar diffRadius = data.diffRadius();
292
293 if (fCachedRadius != radius0 ||
294 fCachedDiffRadius != diffRadius) {
295
halcanary9d524f22016-03-29 09:03:52 -0700296 pdman.set3f(fParamUni, SkScalarToFloat(radius0),
jvanverthde11ee42016-02-26 13:58:40 -0800297 SkScalarToFloat(SkScalarMul(radius0, radius0)), SkScalarToFloat(diffRadius));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000298 fCachedRadius = radius0;
299 fCachedDiffRadius = diffRadius;
300 }
301}
302
joshualittb0a8a372014-09-23 09:50:21 -0700303void GLEdge2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700304 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -0700305 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000306}
307
308//////////////////////////////////////////////////////////////////////////////
309// Focal Conical Gradients
310//////////////////////////////////////////////////////////////////////////////
311
312static ConicalType set_matrix_focal_conical(const SkTwoPointConicalGradient& shader,
313 SkMatrix* invLMatrix, SkScalar* focalX) {
314 // Inverse of the current local matrix is passed in then,
315 // translate, scale, and rotate such that endCircle is unit circle on x-axis,
316 // and focal point is at the origin.
317 ConicalType conicalType;
318 const SkPoint& focal = shader.getStartCenter();
319 const SkPoint& centerEnd = shader.getEndCenter();
320 SkScalar radius = shader.getEndRadius();
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000321 SkScalar invRadius = 1.f / radius;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000322
323 SkMatrix matrix;
324
325 matrix.setTranslate(-centerEnd.fX, -centerEnd.fY);
326 matrix.postScale(invRadius, invRadius);
327
328 SkPoint focalTrans;
329 matrix.mapPoints(&focalTrans, &focal, 1);
330 *focalX = focalTrans.length();
331
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000332 if (0.f != *focalX) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000333 SkScalar invFocalX = SkScalarInvert(*focalX);
334 SkMatrix rot;
335 rot.setSinCos(-SkScalarMul(invFocalX, focalTrans.fY),
336 SkScalarMul(invFocalX, focalTrans.fX));
337 matrix.postConcat(rot);
338 }
339
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000340 matrix.postTranslate(-(*focalX), 0.f);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000341
342 // If the focal point is touching the edge of the circle it will
343 // cause a degenerate case that must be handled separately
egdaniel8405ef92014-06-09 11:57:28 -0700344 // kEdgeErrorTol = 5 * kErrorTol was picked after manual testing the
345 // stability trade off versus the linear approx used in the Edge Shader
346 if (SkScalarAbs(1.f - (*focalX)) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000347 return kEdge_ConicalType;
348 }
349
350 // Scale factor 1 / (1 - focalX * focalX)
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000351 SkScalar oneMinusF2 = 1.f - SkScalarMul(*focalX, *focalX);
reed80ea19c2015-05-12 10:37:34 -0700352 SkScalar s = SkScalarInvert(oneMinusF2);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000353
354
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000355 if (s >= 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000356 conicalType = kInside_ConicalType;
357 matrix.postScale(s, s * SkScalarSqrt(oneMinusF2));
358 } else {
359 conicalType = kOutside_ConicalType;
360 matrix.postScale(s, s);
361 }
362
363 invLMatrix->postConcat(matrix);
364
365 return conicalType;
366}
367
368//////////////////////////////////////////////////////////////////////////////
369
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000370class FocalOutside2PtConicalEffect : public GrGradientEffect {
371public:
372
bungeman06ca8ec2016-06-09 08:01:03 -0700373 static sk_sp<GrFragmentProcessor> Make(GrContext* ctx,
374 const SkTwoPointConicalGradient& shader,
375 const SkMatrix& matrix,
376 SkShader::TileMode tm,
377 SkScalar focalX) {
378 return sk_sp<GrFragmentProcessor>(
379 new FocalOutside2PtConicalEffect(ctx, shader, matrix, tm, focalX));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000380 }
381
382 virtual ~FocalOutside2PtConicalEffect() { }
383
mtklein36352bf2015-03-25 18:17:31 -0700384 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -0800385 return "Two-Point Conical Gradient Focal Outside";
386 }
387
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000388 bool isFlipped() const { return fIsFlipped; }
389 SkScalar focal() const { return fFocalX; }
390
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000391private:
egdaniel57d3b032015-11-13 11:57:27 -0800392 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700393
egdaniel57d3b032015-11-13 11:57:27 -0800394 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700395
mtklein36352bf2015-03-25 18:17:31 -0700396 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700397 const FocalOutside2PtConicalEffect& s = sBase.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000398 return (INHERITED::onIsEqual(sBase) &&
399 this->fFocalX == s.fFocalX &&
400 this->fIsFlipped == s.fIsFlipped);
401 }
402
403 FocalOutside2PtConicalEffect(GrContext* ctx,
404 const SkTwoPointConicalGradient& shader,
405 const SkMatrix& matrix,
406 SkShader::TileMode tm,
407 SkScalar focalX)
bsalomon4a339522015-10-06 08:40:50 -0700408 : INHERITED(ctx, shader, matrix, tm)
joshualittb2456052015-07-08 09:36:59 -0700409 , fFocalX(focalX)
410 , fIsFlipped(shader.isFlippedGrad()) {
joshualitteb2a6762014-12-04 11:35:33 -0800411 this->initClassID<FocalOutside2PtConicalEffect>();
412 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000413
joshualittb0a8a372014-09-23 09:50:21 -0700414 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000415
416 SkScalar fFocalX;
417 bool fIsFlipped;
418
419 typedef GrGradientEffect INHERITED;
420};
421
422class GLFocalOutside2PtConicalEffect : public GrGLGradientEffect {
423public:
joshualitteb2a6762014-12-04 11:35:33 -0800424 GLFocalOutside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000425 virtual ~GLFocalOutside2PtConicalEffect() { }
426
wangyix7c157a92015-07-22 15:08:53 -0700427 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000428
jvanverthcfc18862015-04-28 08:48:20 -0700429 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000430
431protected:
egdaniel018fb622015-10-28 07:26:40 -0700432 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700433
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000434 UniformHandle fParamUni;
435
436 const char* fVSVaryingName;
437 const char* fFSVaryingName;
438
439 bool fIsFlipped;
440
441 // @{
442 /// Values last uploaded as uniforms
443
444 SkScalar fCachedFocal;
445
446 // @}
447
448private:
449 typedef GrGLGradientEffect INHERITED;
450
451};
452
egdaniel57d3b032015-11-13 11:57:27 -0800453void FocalOutside2PtConicalEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
454 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -0800455 GLFocalOutside2PtConicalEffect::GenKey(*this, caps, b);
456}
457
egdaniel57d3b032015-11-13 11:57:27 -0800458GrGLSLFragmentProcessor* FocalOutside2PtConicalEffect::onCreateGLSLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700459 return new GLFocalOutside2PtConicalEffect(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000460}
461
joshualittb0a8a372014-09-23 09:50:21 -0700462GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000463
joshualitt01258472014-09-22 10:29:30 -0700464/*
465 * All Two point conical gradient test create functions may occasionally create edge case shaders
466 */
bungeman06ca8ec2016-06-09 08:01:03 -0700467sk_sp<GrFragmentProcessor> FocalOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700468 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000469 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000470 SkPoint center2;
471 SkScalar radius2;
472 do {
joshualitt0067ff52015-07-08 14:26:19 -0700473 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000474 // Need to make sure the centers are not the same or else focal point will be inside
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000475 } while (center1 == center2);
476 SkPoint diff = center2 - center1;
477 SkScalar diffLen = diff.length();
478 // Below makes sure that the focal point is not contained within circle two
joshualitt0067ff52015-07-08 14:26:19 -0700479 radius2 = d->fRandom->nextRangeF(0.f, diffLen);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000480
481 SkColor colors[kMaxRandomGradientColors];
482 SkScalar stopsArray[kMaxRandomGradientColors];
483 SkScalar* stops = stopsArray;
484 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -0700485 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
reed8a21c9f2016-03-08 18:50:00 -0800486 auto shader = SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
487 colors, stops, colorCount, tm);
bungeman06ca8ec2016-06-09 08:01:03 -0700488 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(d->fContext,
brianosman982eb7f2016-06-06 13:10:58 -0700489 GrTest::TestMatrix(d->fRandom), NULL, kNone_SkFilterQuality,
490 SkSourceGammaTreatment::kRespect);
bsalomonc21b09e2015-08-28 18:46:56 -0700491 GrAlwaysAssert(fp);
492 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000493}
494
joshualitteb2a6762014-12-04 11:35:33 -0800495GLFocalOutside2PtConicalEffect::GLFocalOutside2PtConicalEffect(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -0700496 : fVSVaryingName(nullptr)
497 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000498 , fCachedFocal(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -0700499 const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000500 fIsFlipped = data.isFlipped();
501}
502
wangyix7c157a92015-07-22 15:08:53 -0700503void GLFocalOutside2PtConicalEffect::emitCode(EmitArgs& args) {
504 const FocalOutside2PtConicalEffect& ge = args.fFp.cast<FocalOutside2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -0800505 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
506 this->emitUniforms(uniformHandler, ge);
jvanverthde11ee42016-02-26 13:58:40 -0800507 fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
508 kVec2f_GrSLType, kDefault_GrSLPrecision,
509 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000510 SkString tName("t");
511 SkString p0; // focalX
512 SkString p1; // 1 - focalX * focalX
513
jvanverthde11ee42016-02-26 13:58:40 -0800514 p0.appendf("%s.x", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
515 p1.appendf("%s.y", uniformHandler->getUniformVariable(fParamUni).getName().c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000516
517 // if we have a vec3 from being in perspective, convert it to a vec2 first
cdalton85285412016-02-18 12:37:07 -0800518 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
egdaniel4ca2e602015-11-18 08:01:26 -0800519 SkString coords2DString = fragBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000520 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000521
522 // t = p.x * focal.x +/- sqrt(p.x^2 + (1 - focal.x^2) * p.y^2)
523
524 // output will default to transparent black (we simply won't write anything
525 // else to it if invalid, instead of discarding or returning prematurely)
egdaniel4ca2e602015-11-18 08:01:26 -0800526 fragBuilder->codeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", args.fOutputColor);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000527
egdaniel4ca2e602015-11-18 08:01:26 -0800528 fragBuilder->codeAppendf("\tfloat xs = %s.x * %s.x;\n", coords2D, coords2D);
529 fragBuilder->codeAppendf("\tfloat ys = %s.y * %s.y;\n", coords2D, coords2D);
530 fragBuilder->codeAppendf("\tfloat d = xs + %s * ys;\n", p1.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000531
532 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
533 // If so we must also flip sign on sqrt
534 if (!fIsFlipped) {
egdaniel4ca2e602015-11-18 08:01:26 -0800535 fragBuilder->codeAppendf("\tfloat %s = %s.x * %s + sqrt(d);\n", tName.c_str(),
536 coords2D, p0.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000537 } else {
egdaniel4ca2e602015-11-18 08:01:26 -0800538 fragBuilder->codeAppendf("\tfloat %s = %s.x * %s - sqrt(d);\n", tName.c_str(),
539 coords2D, p0.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000540 }
541
egdaniel4ca2e602015-11-18 08:01:26 -0800542 fragBuilder->codeAppendf("\tif (%s >= 0.0 && d >= 0.0) {\n", tName.c_str());
543 fragBuilder->codeAppend("\t\t");
egdaniel7ea439b2015-12-03 09:20:44 -0800544 this->emitColor(fragBuilder,
545 uniformHandler,
egdaniela2e3e0f2015-11-19 07:23:45 -0800546 args.fGLSLCaps,
egdaniel4ca2e602015-11-18 08:01:26 -0800547 ge,
548 tName.c_str(),
549 args.fOutputColor,
550 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -0700551 args.fTexSamplers);
egdaniel4ca2e602015-11-18 08:01:26 -0800552 fragBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000553}
554
egdaniel018fb622015-10-28 07:26:40 -0700555void GLFocalOutside2PtConicalEffect::onSetData(const GrGLSLProgramDataManager& pdman,
556 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700557 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700558 const FocalOutside2PtConicalEffect& data = processor.cast<FocalOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000559 SkASSERT(data.isFlipped() == fIsFlipped);
560 SkScalar focal = data.focal();
561
562 if (fCachedFocal != focal) {
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000563 SkScalar oneMinus2F = 1.f - SkScalarMul(focal, focal);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000564
jvanverthde11ee42016-02-26 13:58:40 -0800565 pdman.set2f(fParamUni, SkScalarToFloat(focal), SkScalarToFloat(oneMinus2F));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000566 fCachedFocal = focal;
567 }
568}
569
joshualittb0a8a372014-09-23 09:50:21 -0700570void GLFocalOutside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700571 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -0700572 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -0700573 key[0] = GenBaseGradientKey(processor);
574 key[1] = processor.cast<FocalOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000575}
576
577//////////////////////////////////////////////////////////////////////////////
578
579class GLFocalInside2PtConicalEffect;
580
581class FocalInside2PtConicalEffect : public GrGradientEffect {
582public:
583
bungeman06ca8ec2016-06-09 08:01:03 -0700584 static sk_sp<GrFragmentProcessor> Make(GrContext* ctx,
585 const SkTwoPointConicalGradient& shader,
586 const SkMatrix& matrix,
587 SkShader::TileMode tm,
588 SkScalar focalX) {
589 return sk_sp<GrFragmentProcessor>(
590 new FocalInside2PtConicalEffect(ctx, shader, matrix, tm, focalX));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000591 }
592
593 virtual ~FocalInside2PtConicalEffect() {}
594
mtklein36352bf2015-03-25 18:17:31 -0700595 const char* name() const override {
joshualitteb2a6762014-12-04 11:35:33 -0800596 return "Two-Point Conical Gradient Focal Inside";
597 }
598
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000599 SkScalar focal() const { return fFocalX; }
600
egdaniel57d3b032015-11-13 11:57:27 -0800601 typedef GLFocalInside2PtConicalEffect GLSLProcessor;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000602
603private:
egdaniel57d3b032015-11-13 11:57:27 -0800604 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700605
egdaniel57d3b032015-11-13 11:57:27 -0800606 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700607
mtklein36352bf2015-03-25 18:17:31 -0700608 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700609 const FocalInside2PtConicalEffect& s = sBase.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000610 return (INHERITED::onIsEqual(sBase) &&
611 this->fFocalX == s.fFocalX);
612 }
613
614 FocalInside2PtConicalEffect(GrContext* ctx,
615 const SkTwoPointConicalGradient& shader,
616 const SkMatrix& matrix,
617 SkShader::TileMode tm,
618 SkScalar focalX)
bsalomon4a339522015-10-06 08:40:50 -0700619 : INHERITED(ctx, shader, matrix, tm), fFocalX(focalX) {
joshualitteb2a6762014-12-04 11:35:33 -0800620 this->initClassID<FocalInside2PtConicalEffect>();
621 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000622
joshualittb0a8a372014-09-23 09:50:21 -0700623 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000624
625 SkScalar fFocalX;
626
627 typedef GrGradientEffect INHERITED;
628};
629
630class GLFocalInside2PtConicalEffect : public GrGLGradientEffect {
631public:
joshualitteb2a6762014-12-04 11:35:33 -0800632 GLFocalInside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000633 virtual ~GLFocalInside2PtConicalEffect() {}
634
wangyix7c157a92015-07-22 15:08:53 -0700635 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000636
jvanverthcfc18862015-04-28 08:48:20 -0700637 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000638
639protected:
egdaniel018fb622015-10-28 07:26:40 -0700640 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700641
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000642 UniformHandle fFocalUni;
643
644 const char* fVSVaryingName;
645 const char* fFSVaryingName;
646
647 // @{
648 /// Values last uploaded as uniforms
649
650 SkScalar fCachedFocal;
651
652 // @}
653
654private:
655 typedef GrGLGradientEffect INHERITED;
656
657};
658
egdaniel57d3b032015-11-13 11:57:27 -0800659void FocalInside2PtConicalEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
660 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -0800661 GLFocalInside2PtConicalEffect::GenKey(*this, caps, b);
662}
663
egdaniel57d3b032015-11-13 11:57:27 -0800664GrGLSLFragmentProcessor* FocalInside2PtConicalEffect::onCreateGLSLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700665 return new GLFocalInside2PtConicalEffect(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000666}
667
joshualittb0a8a372014-09-23 09:50:21 -0700668GR_DEFINE_FRAGMENT_PROCESSOR_TEST(FocalInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000669
joshualitt01258472014-09-22 10:29:30 -0700670/*
671 * All Two point conical gradient test create functions may occasionally create edge case shaders
672 */
bungeman06ca8ec2016-06-09 08:01:03 -0700673sk_sp<GrFragmentProcessor> FocalInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700674 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000675 SkScalar radius1 = 0.f;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000676 SkPoint center2;
677 SkScalar radius2;
678 do {
joshualitt0067ff52015-07-08 14:26:19 -0700679 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000680 // Below makes sure radius2 is larger enouch such that the focal point
681 // is inside the end circle
joshualitt0067ff52015-07-08 14:26:19 -0700682 SkScalar increase = d->fRandom->nextUScalar1();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000683 SkPoint diff = center2 - center1;
684 SkScalar diffLen = diff.length();
685 radius2 = diffLen + increase;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000686 // If the circles are identical the factory will give us an empty shader.
687 } while (radius1 == radius2 && center1 == center2);
688
689 SkColor colors[kMaxRandomGradientColors];
690 SkScalar stopsArray[kMaxRandomGradientColors];
691 SkScalar* stops = stopsArray;
692 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -0700693 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
reed8a21c9f2016-03-08 18:50:00 -0800694 auto shader = SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
695 colors, stops, colorCount, tm);
bungeman06ca8ec2016-06-09 08:01:03 -0700696 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(d->fContext,
brianosman982eb7f2016-06-06 13:10:58 -0700697 GrTest::TestMatrix(d->fRandom), NULL, kNone_SkFilterQuality,
698 SkSourceGammaTreatment::kRespect);
bsalomonc21b09e2015-08-28 18:46:56 -0700699 GrAlwaysAssert(fp);
joshualittb0a8a372014-09-23 09:50:21 -0700700 return fp;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000701}
702
joshualitteb2a6762014-12-04 11:35:33 -0800703GLFocalInside2PtConicalEffect::GLFocalInside2PtConicalEffect(const GrProcessor&)
halcanary96fcdcc2015-08-27 07:41:13 -0700704 : fVSVaryingName(nullptr)
705 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000706 , fCachedFocal(SK_ScalarMax) {}
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000707
wangyix7c157a92015-07-22 15:08:53 -0700708void GLFocalInside2PtConicalEffect::emitCode(EmitArgs& args) {
709 const FocalInside2PtConicalEffect& ge = args.fFp.cast<FocalInside2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -0800710 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
711 this->emitUniforms(uniformHandler, ge);
cdalton5e58cee2016-02-11 12:49:47 -0800712 fFocalUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800713 kFloat_GrSLType, kDefault_GrSLPrecision,
714 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000715 SkString tName("t");
716
717 // this is the distance along x-axis from the end center to focal point in
718 // transformed coordinates
egdaniel7ea439b2015-12-03 09:20:44 -0800719 GrGLSLShaderVar focal = uniformHandler->getUniformVariable(fFocalUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000720
721 // if we have a vec3 from being in perspective, convert it to a vec2 first
cdalton85285412016-02-18 12:37:07 -0800722 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
egdaniel4ca2e602015-11-18 08:01:26 -0800723 SkString coords2DString = fragBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000724 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000725
726 // t = p.x * focalX + length(p)
egdaniel4ca2e602015-11-18 08:01:26 -0800727 fragBuilder->codeAppendf("\tfloat %s = %s.x * %s + length(%s);\n", tName.c_str(),
egdaniel7ea439b2015-12-03 09:20:44 -0800728 coords2D, focal.c_str(), coords2D);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000729
egdaniel7ea439b2015-12-03 09:20:44 -0800730 this->emitColor(fragBuilder,
731 uniformHandler,
egdaniela2e3e0f2015-11-19 07:23:45 -0800732 args.fGLSLCaps,
egdaniel4ca2e602015-11-18 08:01:26 -0800733 ge,
734 tName.c_str(),
735 args.fOutputColor,
736 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -0700737 args.fTexSamplers);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000738}
739
egdaniel018fb622015-10-28 07:26:40 -0700740void GLFocalInside2PtConicalEffect::onSetData(const GrGLSLProgramDataManager& pdman,
741 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -0700742 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -0700743 const FocalInside2PtConicalEffect& data = processor.cast<FocalInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000744 SkScalar focal = data.focal();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000745
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000746 if (fCachedFocal != focal) {
kkinnunen7510b222014-07-30 00:04:16 -0700747 pdman.set1f(fFocalUni, SkScalarToFloat(focal));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000748 fCachedFocal = focal;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +0000749 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000750}
751
joshualittb0a8a372014-09-23 09:50:21 -0700752void GLFocalInside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -0700753 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -0700754 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000755}
756
757//////////////////////////////////////////////////////////////////////////////
758// Circle Conical Gradients
759//////////////////////////////////////////////////////////////////////////////
760
761struct CircleConicalInfo {
762 SkPoint fCenterEnd;
763 SkScalar fA;
764 SkScalar fB;
765 SkScalar fC;
766};
767
768// Returns focal distance along x-axis in transformed coords
769static ConicalType set_matrix_circle_conical(const SkTwoPointConicalGradient& shader,
770 SkMatrix* invLMatrix, CircleConicalInfo* info) {
771 // Inverse of the current local matrix is passed in then,
772 // translate and scale such that start circle is on the origin and has radius 1
773 const SkPoint& centerStart = shader.getStartCenter();
774 const SkPoint& centerEnd = shader.getEndCenter();
775 SkScalar radiusStart = shader.getStartRadius();
776 SkScalar radiusEnd = shader.getEndRadius();
777
778 SkMatrix matrix;
779
780 matrix.setTranslate(-centerStart.fX, -centerStart.fY);
781
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000782 SkScalar invStartRad = 1.f / radiusStart;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000783 matrix.postScale(invStartRad, invStartRad);
784
785 radiusEnd /= radiusStart;
786
787 SkPoint centerEndTrans;
788 matrix.mapPoints(&centerEndTrans, &centerEnd, 1);
789
790 SkScalar A = centerEndTrans.fX * centerEndTrans.fX + centerEndTrans.fY * centerEndTrans.fY
791 - radiusEnd * radiusEnd + 2 * radiusEnd - 1;
792
793 // Check to see if start circle is inside end circle with edges touching.
794 // If touching we return that it is of kEdge_ConicalType, and leave the matrix setting
egdaniel8405ef92014-06-09 11:57:28 -0700795 // to the edge shader. kEdgeErrorTol = 5 * kErrorTol was picked after manual testing
796 // so that C = 1 / A is stable, and the linear approximation used in the Edge shader is
797 // still accurate.
798 if (SkScalarAbs(A) < kEdgeErrorTol) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000799 return kEdge_ConicalType;
800 }
801
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000802 SkScalar C = 1.f / A;
803 SkScalar B = (radiusEnd - 1.f) * C;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000804
805 matrix.postScale(C, C);
806
807 invLMatrix->postConcat(matrix);
808
809 info->fCenterEnd = centerEndTrans;
810 info->fA = A;
811 info->fB = B;
812 info->fC = C;
813
814 // if A ends up being negative, the start circle is contained completely inside the end cirlce
commit-bot@chromium.org80894672014-04-22 21:24:22 +0000815 if (A < 0.f) {
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000816 return kInside_ConicalType;
817 }
818 return kOutside_ConicalType;
819}
820
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000821class CircleInside2PtConicalEffect : public GrGradientEffect {
822public:
823
bungeman06ca8ec2016-06-09 08:01:03 -0700824 static sk_sp<GrFragmentProcessor> Make(GrContext* ctx,
825 const SkTwoPointConicalGradient& shader,
826 const SkMatrix& matrix,
827 SkShader::TileMode tm,
828 const CircleConicalInfo& info) {
829 return sk_sp<GrFragmentProcessor>(
830 new CircleInside2PtConicalEffect(ctx, shader, matrix, tm, info));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000831 }
832
833 virtual ~CircleInside2PtConicalEffect() {}
834
mtklein36352bf2015-03-25 18:17:31 -0700835 const char* name() const override { return "Two-Point Conical Gradient Inside"; }
joshualitteb2a6762014-12-04 11:35:33 -0800836
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000837 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
838 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
839 SkScalar A() const { return fInfo.fA; }
840 SkScalar B() const { return fInfo.fB; }
841 SkScalar C() const { return fInfo.fC; }
842
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000843private:
egdaniel57d3b032015-11-13 11:57:27 -0800844 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -0700845
egdaniel57d3b032015-11-13 11:57:27 -0800846 virtual void onGetGLSLProcessorKey(const GrGLSLCaps& caps,
847 GrProcessorKeyBuilder* b) const override;
wangyix4b3050b2015-08-04 07:59:37 -0700848
mtklein36352bf2015-03-25 18:17:31 -0700849 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -0700850 const CircleInside2PtConicalEffect& s = sBase.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000851 return (INHERITED::onIsEqual(sBase) &&
852 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
853 this->fInfo.fA == s.fInfo.fA &&
854 this->fInfo.fB == s.fInfo.fB &&
855 this->fInfo.fC == s.fInfo.fC);
856 }
857
858 CircleInside2PtConicalEffect(GrContext* ctx,
859 const SkTwoPointConicalGradient& shader,
860 const SkMatrix& matrix,
861 SkShader::TileMode tm,
862 const CircleConicalInfo& info)
bsalomon4a339522015-10-06 08:40:50 -0700863 : INHERITED(ctx, shader, matrix, tm), fInfo(info) {
joshualitteb2a6762014-12-04 11:35:33 -0800864 this->initClassID<CircleInside2PtConicalEffect>();
865 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000866
joshualittb0a8a372014-09-23 09:50:21 -0700867 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000868
869 const CircleConicalInfo fInfo;
870
871 typedef GrGradientEffect INHERITED;
872};
873
874class GLCircleInside2PtConicalEffect : public GrGLGradientEffect {
875public:
joshualitteb2a6762014-12-04 11:35:33 -0800876 GLCircleInside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000877 virtual ~GLCircleInside2PtConicalEffect() {}
878
wangyix7c157a92015-07-22 15:08:53 -0700879 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000880
jvanverthcfc18862015-04-28 08:48:20 -0700881 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000882
883protected:
egdaniel018fb622015-10-28 07:26:40 -0700884 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -0700885
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000886 UniformHandle fCenterUni;
887 UniformHandle fParamUni;
888
889 const char* fVSVaryingName;
890 const char* fFSVaryingName;
891
892 // @{
893 /// Values last uploaded as uniforms
894
895 SkScalar fCachedCenterX;
896 SkScalar fCachedCenterY;
897 SkScalar fCachedA;
898 SkScalar fCachedB;
899 SkScalar fCachedC;
900
901 // @}
902
903private:
904 typedef GrGLGradientEffect INHERITED;
905
906};
907
egdaniel57d3b032015-11-13 11:57:27 -0800908void CircleInside2PtConicalEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
909 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -0800910 GLCircleInside2PtConicalEffect::GenKey(*this, caps, b);
911}
912
egdaniel57d3b032015-11-13 11:57:27 -0800913GrGLSLFragmentProcessor* CircleInside2PtConicalEffect::onCreateGLSLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -0700914 return new GLCircleInside2PtConicalEffect(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000915}
916
joshualittb0a8a372014-09-23 09:50:21 -0700917GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleInside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000918
joshualitt01258472014-09-22 10:29:30 -0700919/*
920 * All Two point conical gradient test create functions may occasionally create edge case shaders
921 */
bungeman06ca8ec2016-06-09 08:01:03 -0700922sk_sp<GrFragmentProcessor> CircleInside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700923 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
924 SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000925 SkPoint center2;
926 SkScalar radius2;
927 do {
joshualitt0067ff52015-07-08 14:26:19 -0700928 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000929 // Below makes sure that circle one is contained within circle two
joshualitt0067ff52015-07-08 14:26:19 -0700930 SkScalar increase = d->fRandom->nextUScalar1();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000931 SkPoint diff = center2 - center1;
932 SkScalar diffLen = diff.length();
933 radius2 = radius1 + diffLen + increase;
934 // If the circles are identical the factory will give us an empty shader.
935 } while (radius1 == radius2 && center1 == center2);
936
937 SkColor colors[kMaxRandomGradientColors];
938 SkScalar stopsArray[kMaxRandomGradientColors];
939 SkScalar* stops = stopsArray;
940 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -0700941 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
reed8a21c9f2016-03-08 18:50:00 -0800942 auto shader = SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
943 colors, stops, colorCount, tm);
bungeman06ca8ec2016-06-09 08:01:03 -0700944 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(d->fContext,
brianosman982eb7f2016-06-06 13:10:58 -0700945 GrTest::TestMatrix(d->fRandom), NULL, kNone_SkFilterQuality,
946 SkSourceGammaTreatment::kRespect);
bsalomonc21b09e2015-08-28 18:46:56 -0700947 GrAlwaysAssert(fp);
joshualitt8ca93e72015-07-08 06:51:43 -0700948 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000949}
950
joshualitteb2a6762014-12-04 11:35:33 -0800951GLCircleInside2PtConicalEffect::GLCircleInside2PtConicalEffect(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -0700952 : fVSVaryingName(nullptr)
953 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000954 , fCachedCenterX(SK_ScalarMax)
955 , fCachedCenterY(SK_ScalarMax)
956 , fCachedA(SK_ScalarMax)
957 , fCachedB(SK_ScalarMax)
958 , fCachedC(SK_ScalarMax) {}
959
wangyix7c157a92015-07-22 15:08:53 -0700960void GLCircleInside2PtConicalEffect::emitCode(EmitArgs& args) {
961 const CircleInside2PtConicalEffect& ge = args.fFp.cast<CircleInside2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -0800962 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
963 this->emitUniforms(uniformHandler, ge);
cdalton5e58cee2016-02-11 12:49:47 -0800964 fCenterUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800965 kVec2f_GrSLType, kDefault_GrSLPrecision,
966 "Conical2FSCenter");
cdalton5e58cee2016-02-11 12:49:47 -0800967 fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800968 kVec3f_GrSLType, kDefault_GrSLPrecision,
969 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000970 SkString tName("t");
971
egdaniel7ea439b2015-12-03 09:20:44 -0800972 GrGLSLShaderVar center = uniformHandler->getUniformVariable(fCenterUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000973 // params.x = A
974 // params.y = B
975 // params.z = C
egdaniel7ea439b2015-12-03 09:20:44 -0800976 GrGLSLShaderVar params = uniformHandler->getUniformVariable(fParamUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000977
978 // if we have a vec3 from being in perspective, convert it to a vec2 first
cdalton85285412016-02-18 12:37:07 -0800979 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
egdaniel4ca2e602015-11-18 08:01:26 -0800980 SkString coords2DString = fragBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +0000981 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000982
983 // p = coords2D
984 // e = center end
985 // r = radius end
986 // A = dot(e, e) - r^2 + 2 * r - 1
987 // B = (r -1) / A
988 // C = 1 / A
989 // d = dot(e, p) + B
990 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
egdaniel4ca2e602015-11-18 08:01:26 -0800991 fragBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
992 fragBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
993 params.c_str());
994 fragBuilder->codeAppendf("\tfloat %s = d + sqrt(d * d - %s.x * pDotp + %s.z);\n",
995 tName.c_str(), params.c_str(), params.c_str());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +0000996
egdaniel7ea439b2015-12-03 09:20:44 -0800997 this->emitColor(fragBuilder,
998 uniformHandler,
egdaniela2e3e0f2015-11-19 07:23:45 -0800999 args.fGLSLCaps,
egdaniel4ca2e602015-11-18 08:01:26 -08001000 ge,
1001 tName.c_str(),
1002 args.fOutputColor,
1003 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -07001004 args.fTexSamplers);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001005}
1006
egdaniel018fb622015-10-28 07:26:40 -07001007void GLCircleInside2PtConicalEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1008 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001009 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -07001010 const CircleInside2PtConicalEffect& data = processor.cast<CircleInside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001011 SkScalar centerX = data.centerX();
1012 SkScalar centerY = data.centerY();
1013 SkScalar A = data.A();
1014 SkScalar B = data.B();
1015 SkScalar C = data.C();
1016
1017 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1018 fCachedA != A || fCachedB != B || fCachedC != C) {
1019
kkinnunen7510b222014-07-30 00:04:16 -07001020 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1021 pdman.set3f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001022
1023 fCachedCenterX = centerX;
1024 fCachedCenterY = centerY;
1025 fCachedA = A;
1026 fCachedB = B;
1027 fCachedC = C;
1028 }
1029}
1030
joshualittb0a8a372014-09-23 09:50:21 -07001031void GLCircleInside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -07001032 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
joshualittb0a8a372014-09-23 09:50:21 -07001033 b->add32(GenBaseGradientKey(processor));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001034}
1035
1036//////////////////////////////////////////////////////////////////////////////
1037
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001038class CircleOutside2PtConicalEffect : public GrGradientEffect {
1039public:
1040
bungeman06ca8ec2016-06-09 08:01:03 -07001041 static sk_sp<GrFragmentProcessor> Make(GrContext* ctx,
1042 const SkTwoPointConicalGradient& shader,
1043 const SkMatrix& matrix,
1044 SkShader::TileMode tm,
1045 const CircleConicalInfo& info) {
1046 return sk_sp<GrFragmentProcessor>(
1047 new CircleOutside2PtConicalEffect(ctx, shader, matrix, tm, info));
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001048 }
1049
1050 virtual ~CircleOutside2PtConicalEffect() {}
1051
mtklein36352bf2015-03-25 18:17:31 -07001052 const char* name() const override { return "Two-Point Conical Gradient Outside"; }
joshualitteb2a6762014-12-04 11:35:33 -08001053
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001054 SkScalar centerX() const { return fInfo.fCenterEnd.fX; }
1055 SkScalar centerY() const { return fInfo.fCenterEnd.fY; }
1056 SkScalar A() const { return fInfo.fA; }
1057 SkScalar B() const { return fInfo.fB; }
1058 SkScalar C() const { return fInfo.fC; }
1059 SkScalar tLimit() const { return fTLimit; }
1060 bool isFlipped() const { return fIsFlipped; }
1061
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001062private:
egdaniel57d3b032015-11-13 11:57:27 -08001063 GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
wangyixb1daa862015-08-18 11:29:31 -07001064
egdaniel57d3b032015-11-13 11:57:27 -08001065 void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder*) const override;
wangyix4b3050b2015-08-04 07:59:37 -07001066
mtklein36352bf2015-03-25 18:17:31 -07001067 bool onIsEqual(const GrFragmentProcessor& sBase) const override {
joshualitt49586be2014-09-16 08:21:41 -07001068 const CircleOutside2PtConicalEffect& s = sBase.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001069 return (INHERITED::onIsEqual(sBase) &&
1070 this->fInfo.fCenterEnd == s.fInfo.fCenterEnd &&
1071 this->fInfo.fA == s.fInfo.fA &&
1072 this->fInfo.fB == s.fInfo.fB &&
1073 this->fInfo.fC == s.fInfo.fC &&
1074 this->fTLimit == s.fTLimit &&
1075 this->fIsFlipped == s.fIsFlipped);
1076 }
1077
1078 CircleOutside2PtConicalEffect(GrContext* ctx,
1079 const SkTwoPointConicalGradient& shader,
1080 const SkMatrix& matrix,
1081 SkShader::TileMode tm,
1082 const CircleConicalInfo& info)
bsalomon4a339522015-10-06 08:40:50 -07001083 : INHERITED(ctx, shader, matrix, tm), fInfo(info) {
joshualitteb2a6762014-12-04 11:35:33 -08001084 this->initClassID<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001085 if (shader.getStartRadius() != shader.getEndRadius()) {
reed80ea19c2015-05-12 10:37:34 -07001086 fTLimit = shader.getStartRadius() / (shader.getStartRadius() - shader.getEndRadius());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001087 } else {
1088 fTLimit = SK_ScalarMin;
1089 }
1090
1091 fIsFlipped = shader.isFlippedGrad();
1092 }
1093
joshualittb0a8a372014-09-23 09:50:21 -07001094 GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001095
1096 const CircleConicalInfo fInfo;
1097 SkScalar fTLimit;
1098 bool fIsFlipped;
1099
1100 typedef GrGradientEffect INHERITED;
1101};
1102
1103class GLCircleOutside2PtConicalEffect : public GrGLGradientEffect {
1104public:
joshualitteb2a6762014-12-04 11:35:33 -08001105 GLCircleOutside2PtConicalEffect(const GrProcessor&);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001106 virtual ~GLCircleOutside2PtConicalEffect() {}
1107
wangyix7c157a92015-07-22 15:08:53 -07001108 virtual void emitCode(EmitArgs&) override;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001109
jvanverthcfc18862015-04-28 08:48:20 -07001110 static void GenKey(const GrProcessor&, const GrGLSLCaps& caps, GrProcessorKeyBuilder* b);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001111
1112protected:
egdaniel018fb622015-10-28 07:26:40 -07001113 void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
wangyixb1daa862015-08-18 11:29:31 -07001114
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001115 UniformHandle fCenterUni;
1116 UniformHandle fParamUni;
1117
1118 const char* fVSVaryingName;
1119 const char* fFSVaryingName;
1120
1121 bool fIsFlipped;
1122
1123 // @{
1124 /// Values last uploaded as uniforms
1125
1126 SkScalar fCachedCenterX;
1127 SkScalar fCachedCenterY;
1128 SkScalar fCachedA;
1129 SkScalar fCachedB;
1130 SkScalar fCachedC;
1131 SkScalar fCachedTLimit;
1132
1133 // @}
1134
1135private:
1136 typedef GrGLGradientEffect INHERITED;
1137
1138};
1139
egdaniel57d3b032015-11-13 11:57:27 -08001140void CircleOutside2PtConicalEffect::onGetGLSLProcessorKey(const GrGLSLCaps& caps,
1141 GrProcessorKeyBuilder* b) const {
joshualitteb2a6762014-12-04 11:35:33 -08001142 GLCircleOutside2PtConicalEffect::GenKey(*this, caps, b);
1143}
1144
egdaniel57d3b032015-11-13 11:57:27 -08001145GrGLSLFragmentProcessor* CircleOutside2PtConicalEffect::onCreateGLSLInstance() const {
halcanary385fe4d2015-08-26 13:07:48 -07001146 return new GLCircleOutside2PtConicalEffect(*this);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001147}
1148
joshualittb0a8a372014-09-23 09:50:21 -07001149GR_DEFINE_FRAGMENT_PROCESSOR_TEST(CircleOutside2PtConicalEffect);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001150
joshualitt01258472014-09-22 10:29:30 -07001151/*
1152 * All Two point conical gradient test create functions may occasionally create edge case shaders
1153 */
bungeman06ca8ec2016-06-09 08:01:03 -07001154sk_sp<GrFragmentProcessor> CircleOutside2PtConicalEffect::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -07001155 SkPoint center1 = {d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1()};
1156 SkScalar radius1 = d->fRandom->nextUScalar1() + 0.0001f; // make sure radius1 != 0
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001157 SkPoint center2;
1158 SkScalar radius2;
1159 SkScalar diffLen;
1160 do {
joshualitt0067ff52015-07-08 14:26:19 -07001161 center2.set(d->fRandom->nextUScalar1(), d->fRandom->nextUScalar1());
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001162 // If the circles share a center than we can't be in the outside case
1163 } while (center1 == center2);
joshualitt01258472014-09-22 10:29:30 -07001164 SkPoint diff = center2 - center1;
1165 diffLen = diff.length();
1166 // Below makes sure that circle one is not contained within circle two
1167 // and have radius2 >= radius to match sorting on cpu side
joshualitt0067ff52015-07-08 14:26:19 -07001168 radius2 = radius1 + d->fRandom->nextRangeF(0.f, diffLen);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001169
1170 SkColor colors[kMaxRandomGradientColors];
1171 SkScalar stopsArray[kMaxRandomGradientColors];
1172 SkScalar* stops = stopsArray;
1173 SkShader::TileMode tm;
joshualitt0067ff52015-07-08 14:26:19 -07001174 int colorCount = RandomGradientParams(d->fRandom, colors, &stops, &tm);
reed8a21c9f2016-03-08 18:50:00 -08001175 auto shader = SkGradientShader::MakeTwoPointConical(center1, radius1, center2, radius2,
1176 colors, stops, colorCount, tm);
bungeman06ca8ec2016-06-09 08:01:03 -07001177 sk_sp<GrFragmentProcessor> fp = shader->asFragmentProcessor(
brianosman982eb7f2016-06-06 13:10:58 -07001178 d->fContext,GrTest::TestMatrix(d->fRandom), NULL, kNone_SkFilterQuality,
1179 SkSourceGammaTreatment::kRespect);
bsalomonc21b09e2015-08-28 18:46:56 -07001180 GrAlwaysAssert(fp);
joshualitt8ca93e72015-07-08 06:51:43 -07001181 return fp;
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001182}
1183
joshualitteb2a6762014-12-04 11:35:33 -08001184GLCircleOutside2PtConicalEffect::GLCircleOutside2PtConicalEffect(const GrProcessor& processor)
halcanary96fcdcc2015-08-27 07:41:13 -07001185 : fVSVaryingName(nullptr)
1186 , fFSVaryingName(nullptr)
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001187 , fCachedCenterX(SK_ScalarMax)
1188 , fCachedCenterY(SK_ScalarMax)
1189 , fCachedA(SK_ScalarMax)
1190 , fCachedB(SK_ScalarMax)
1191 , fCachedC(SK_ScalarMax)
1192 , fCachedTLimit(SK_ScalarMax) {
joshualittb0a8a372014-09-23 09:50:21 -07001193 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001194 fIsFlipped = data.isFlipped();
1195 }
1196
wangyix7c157a92015-07-22 15:08:53 -07001197void GLCircleOutside2PtConicalEffect::emitCode(EmitArgs& args) {
1198 const CircleOutside2PtConicalEffect& ge = args.fFp.cast<CircleOutside2PtConicalEffect>();
egdaniel7ea439b2015-12-03 09:20:44 -08001199 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
1200 this->emitUniforms(uniformHandler, ge);
cdalton5e58cee2016-02-11 12:49:47 -08001201 fCenterUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001202 kVec2f_GrSLType, kDefault_GrSLPrecision,
1203 "Conical2FSCenter");
cdalton5e58cee2016-02-11 12:49:47 -08001204 fParamUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -08001205 kVec4f_GrSLType, kDefault_GrSLPrecision,
1206 "Conical2FSParams");
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001207 SkString tName("t");
1208
egdaniel7ea439b2015-12-03 09:20:44 -08001209 GrGLSLShaderVar center = uniformHandler->getUniformVariable(fCenterUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001210 // params.x = A
1211 // params.y = B
1212 // params.z = C
egdaniel7ea439b2015-12-03 09:20:44 -08001213 GrGLSLShaderVar params = uniformHandler->getUniformVariable(fParamUni);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001214
1215 // if we have a vec3 from being in perspective, convert it to a vec2 first
cdalton85285412016-02-18 12:37:07 -08001216 GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
egdaniel4ca2e602015-11-18 08:01:26 -08001217 SkString coords2DString = fragBuilder->ensureFSCoords2D(args.fCoords, 0);
skia.committer@gmail.comede0c5c2014-04-23 03:04:11 +00001218 const char* coords2D = coords2DString.c_str();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001219
1220 // output will default to transparent black (we simply won't write anything
1221 // else to it if invalid, instead of discarding or returning prematurely)
egdaniel4ca2e602015-11-18 08:01:26 -08001222 fragBuilder->codeAppendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", args.fOutputColor);
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001223
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001224 // p = coords2D
1225 // e = center end
1226 // r = radius end
1227 // A = dot(e, e) - r^2 + 2 * r - 1
1228 // B = (r -1) / A
1229 // C = 1 / A
1230 // d = dot(e, p) + B
1231 // t = d +/- sqrt(d^2 - A * dot(p, p) + C)
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001232
egdaniel4ca2e602015-11-18 08:01:26 -08001233 fragBuilder->codeAppendf("\tfloat pDotp = dot(%s, %s);\n", coords2D, coords2D);
1234 fragBuilder->codeAppendf("\tfloat d = dot(%s, %s) + %s.y;\n", coords2D, center.c_str(),
1235 params.c_str());
1236 fragBuilder->codeAppendf("\tfloat deter = d * d - %s.x * pDotp + %s.z;\n", params.c_str(),
1237 params.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001238
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001239 // Must check to see if we flipped the circle order (to make sure start radius < end radius)
1240 // If so we must also flip sign on sqrt
1241 if (!fIsFlipped) {
egdaniel4ca2e602015-11-18 08:01:26 -08001242 fragBuilder->codeAppendf("\tfloat %s = d + sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001243 } else {
egdaniel4ca2e602015-11-18 08:01:26 -08001244 fragBuilder->codeAppendf("\tfloat %s = d - sqrt(deter);\n", tName.c_str());
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001245 }
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001246
egdaniel7ea439b2015-12-03 09:20:44 -08001247 fragBuilder->codeAppendf("\tif (%s >= %s.w && deter >= 0.0) {\n",
1248 tName.c_str(), params.c_str());
egdaniel4ca2e602015-11-18 08:01:26 -08001249 fragBuilder->codeAppend("\t\t");
egdaniel7ea439b2015-12-03 09:20:44 -08001250 this->emitColor(fragBuilder,
1251 uniformHandler,
egdaniela2e3e0f2015-11-19 07:23:45 -08001252 args.fGLSLCaps,
egdaniel4ca2e602015-11-18 08:01:26 -08001253 ge,
1254 tName.c_str(),
1255 args.fOutputColor,
1256 args.fInputColor,
cdalton3f6f76f2016-04-11 12:18:09 -07001257 args.fTexSamplers);
egdaniel4ca2e602015-11-18 08:01:26 -08001258 fragBuilder->codeAppend("\t}\n");
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001259}
1260
egdaniel018fb622015-10-28 07:26:40 -07001261void GLCircleOutside2PtConicalEffect::onSetData(const GrGLSLProgramDataManager& pdman,
1262 const GrProcessor& processor) {
wangyixb1daa862015-08-18 11:29:31 -07001263 INHERITED::onSetData(pdman, processor);
joshualittb0a8a372014-09-23 09:50:21 -07001264 const CircleOutside2PtConicalEffect& data = processor.cast<CircleOutside2PtConicalEffect>();
commit-bot@chromium.org44d83c12014-04-21 13:10:25 +00001265 SkASSERT(data.isFlipped() == fIsFlipped);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001266 SkScalar centerX = data.centerX();
1267 SkScalar centerY = data.centerY();
1268 SkScalar A = data.A();
1269 SkScalar B = data.B();
1270 SkScalar C = data.C();
1271 SkScalar tLimit = data.tLimit();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001272
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001273 if (fCachedCenterX != centerX || fCachedCenterY != centerY ||
1274 fCachedA != A || fCachedB != B || fCachedC != C || fCachedTLimit != tLimit) {
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001275
kkinnunen7510b222014-07-30 00:04:16 -07001276 pdman.set2f(fCenterUni, SkScalarToFloat(centerX), SkScalarToFloat(centerY));
1277 pdman.set4f(fParamUni, SkScalarToFloat(A), SkScalarToFloat(B), SkScalarToFloat(C),
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001278 SkScalarToFloat(tLimit));
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001279
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001280 fCachedCenterX = centerX;
1281 fCachedCenterY = centerY;
1282 fCachedA = A;
1283 fCachedB = B;
1284 fCachedC = C;
1285 fCachedTLimit = tLimit;
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001286 }
1287}
1288
joshualittb0a8a372014-09-23 09:50:21 -07001289void GLCircleOutside2PtConicalEffect::GenKey(const GrProcessor& processor,
jvanverthcfc18862015-04-28 08:48:20 -07001290 const GrGLSLCaps&, GrProcessorKeyBuilder* b) {
bsalomon63e99f72014-07-21 08:03:14 -07001291 uint32_t* key = b->add32n(2);
joshualittb0a8a372014-09-23 09:50:21 -07001292 key[0] = GenBaseGradientKey(processor);
1293 key[1] = processor.cast<CircleOutside2PtConicalEffect>().isFlipped();
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001294}
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001295
1296//////////////////////////////////////////////////////////////////////////////
1297
bungeman06ca8ec2016-06-09 08:01:03 -07001298sk_sp<GrFragmentProcessor> Gr2PtConicalGradientEffect::Make(GrContext* ctx,
1299 const SkTwoPointConicalGradient& shader,
1300 SkShader::TileMode tm,
1301 const SkMatrix* localMatrix) {
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001302 SkMatrix matrix;
1303 if (!shader.getLocalMatrix().invert(&matrix)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001304 return nullptr;
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001305 }
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001306 if (localMatrix) {
1307 SkMatrix inv;
1308 if (!localMatrix->invert(&inv)) {
halcanary96fcdcc2015-08-27 07:41:13 -07001309 return nullptr;
commit-bot@chromium.org96fb7482014-05-09 20:28:11 +00001310 }
1311 matrix.postConcat(inv);
1312 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001313
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001314 if (shader.getStartRadius() < kErrorTol) {
1315 SkScalar focalX;
1316 ConicalType type = set_matrix_focal_conical(shader, &matrix, &focalX);
1317 if (type == kInside_ConicalType) {
bungeman06ca8ec2016-06-09 08:01:03 -07001318 return FocalInside2PtConicalEffect::Make(ctx, shader, matrix, tm, focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001319 } else if(type == kEdge_ConicalType) {
1320 set_matrix_edge_conical(shader, &matrix);
bungeman06ca8ec2016-06-09 08:01:03 -07001321 return Edge2PtConicalEffect::Make(ctx, shader, matrix, tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001322 } else {
bungeman06ca8ec2016-06-09 08:01:03 -07001323 return FocalOutside2PtConicalEffect::Make(ctx, shader, matrix, tm, focalX);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001324 }
1325 }
1326
1327 CircleConicalInfo info;
1328 ConicalType type = set_matrix_circle_conical(shader, &matrix, &info);
1329
1330 if (type == kInside_ConicalType) {
bungeman06ca8ec2016-06-09 08:01:03 -07001331 return CircleInside2PtConicalEffect::Make(ctx, shader, matrix, tm, info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001332 } else if (type == kEdge_ConicalType) {
1333 set_matrix_edge_conical(shader, &matrix);
bungeman06ca8ec2016-06-09 08:01:03 -07001334 return Edge2PtConicalEffect::Make(ctx, shader, matrix, tm);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001335 } else {
bungeman06ca8ec2016-06-09 08:01:03 -07001336 return CircleOutside2PtConicalEffect::Make(ctx, shader, matrix, tm, info);
commit-bot@chromium.orgc8379d72014-04-22 20:56:37 +00001337 }
commit-bot@chromium.org2af1a2d2014-04-04 13:50:50 +00001338}
1339
commit-bot@chromium.orgaa64fbf2014-04-03 14:59:19 +00001340#endif