OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "GrOvalRenderer.h" | 8 #include "GrOvalRenderer.h" |
9 | 9 |
10 #include "GrBatchFlushState.h" | 10 #include "GrBatchFlushState.h" |
11 #include "GrBatchTest.h" | 11 #include "GrBatchTest.h" |
12 #include "GrGeometryProcessor.h" | 12 #include "GrGeometryProcessor.h" |
13 #include "GrInvariantOutput.h" | 13 #include "GrInvariantOutput.h" |
14 #include "GrProcessor.h" | 14 #include "GrProcessor.h" |
15 #include "GrResourceProvider.h" | 15 #include "GrResourceProvider.h" |
| 16 #include "GrStyle.h" |
16 #include "SkRRect.h" | 17 #include "SkRRect.h" |
17 #include "SkStrokeRec.h" | 18 #include "SkStrokeRec.h" |
18 #include "batches/GrVertexBatch.h" | 19 #include "batches/GrVertexBatch.h" |
19 #include "glsl/GrGLSLFragmentShaderBuilder.h" | 20 #include "glsl/GrGLSLFragmentShaderBuilder.h" |
20 #include "glsl/GrGLSLGeometryProcessor.h" | 21 #include "glsl/GrGLSLGeometryProcessor.h" |
21 #include "glsl/GrGLSLProgramDataManager.h" | 22 #include "glsl/GrGLSLProgramDataManager.h" |
22 #include "glsl/GrGLSLVarying.h" | 23 #include "glsl/GrGLSLVarying.h" |
23 #include "glsl/GrGLSLVertexShaderBuilder.h" | 24 #include "glsl/GrGLSLVertexShaderBuilder.h" |
24 #include "glsl/GrGLSLUniformHandler.h" | 25 #include "glsl/GrGLSLUniformHandler.h" |
25 #include "glsl/GrGLSLUtil.h" | 26 #include "glsl/GrGLSLUtil.h" |
26 | 27 |
27 // TODO(joshualitt) - Break this file up during GrBatch post implementation clea
nup | 28 // TODO(joshualitt) - Break this file up during GrBatch post implementation clea
nup |
28 | 29 |
29 namespace { | 30 namespace { |
30 | 31 |
31 struct CircleVertex { | |
32 SkPoint fPos; | |
33 GrColor fColor; | |
34 SkPoint fOffset; | |
35 SkScalar fOuterRadius; | |
36 SkScalar fInnerRadius; | |
37 }; | |
38 | |
39 struct EllipseVertex { | 32 struct EllipseVertex { |
40 SkPoint fPos; | 33 SkPoint fPos; |
41 GrColor fColor; | 34 GrColor fColor; |
42 SkPoint fOffset; | 35 SkPoint fOffset; |
43 SkPoint fOuterRadii; | 36 SkPoint fOuterRadii; |
44 SkPoint fInnerRadii; | 37 SkPoint fInnerRadii; |
45 }; | 38 }; |
46 | 39 |
47 struct DIEllipseVertex { | 40 struct DIEllipseVertex { |
48 SkPoint fPos; | 41 SkPoint fPos; |
(...skipping 19 matching lines...) Expand all Loading... |
68 * vec4f : (p.xy, outerRad, innerRad) | 61 * vec4f : (p.xy, outerRad, innerRad) |
69 * p is the position in the normalized space. | 62 * p is the position in the normalized space. |
70 * outerRad is the outerRadius in device space. | 63 * outerRad is the outerRadius in device space. |
71 * innerRad is the innerRadius in normalized space (ignored if not s
troking). | 64 * innerRad is the innerRadius in normalized space (ignored if not s
troking). |
72 * If fUsesDistanceVectorField is set in fragment processors in the same program
, then | 65 * If fUsesDistanceVectorField is set in fragment processors in the same program
, then |
73 * an additional vertex attribute is available via args.fFragBuilder->distanceVe
ctorName(): | 66 * an additional vertex attribute is available via args.fFragBuilder->distanceVe
ctorName(): |
74 * vec4f : (v.xy, outerDistance, innerDistance) | 67 * vec4f : (v.xy, outerDistance, innerDistance) |
75 * v is a normalized vector pointing to the outer edge | 68 * v is a normalized vector pointing to the outer edge |
76 * outerDistance is the distance to the outer edge, < 0 if we are ou
tside of the shape | 69 * outerDistance is the distance to the outer edge, < 0 if we are ou
tside of the shape |
77 * if stroking, innerDistance is the distance to the inner edge, < 0
if outside | 70 * if stroking, innerDistance is the distance to the inner edge, < 0
if outside |
| 71 * Additional clip planes are supported for rendering circular arcs. The additio
nal planes are |
| 72 * either intersected or unioned together. Up to three planes are supported (an
initial plane, |
| 73 * a plane intersected with the initial plane, and a plane unioned with the firs
t two). Only two |
| 74 * are useful for any given arc, but having all three in one instance allows bat
ching different |
| 75 * types of arcs. |
78 */ | 76 */ |
79 | 77 |
80 class CircleGeometryProcessor : public GrGeometryProcessor { | 78 class CircleGeometryProcessor : public GrGeometryProcessor { |
81 public: | 79 public: |
82 CircleGeometryProcessor(bool stroke, const SkMatrix& localMatrix) : fLocalMa
trix(localMatrix){ | 80 CircleGeometryProcessor(bool stroke, bool clipPlane, bool isectPlane, bool u
nionPlane, |
| 81 const SkMatrix& localMatrix) |
| 82 : fLocalMatrix(localMatrix) { |
83 this->initClassID<CircleGeometryProcessor>(); | 83 this->initClassID<CircleGeometryProcessor>(); |
84 fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttrib
Type, | 84 fInPosition = &this->addVertexAttrib("inPosition", kVec2f_GrVertexAttrib
Type, |
85 kHigh_GrSLPrecision); | 85 kHigh_GrSLPrecision); |
86 fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType)
; | 86 fInColor = &this->addVertexAttrib("inColor", kVec4ub_GrVertexAttribType)
; |
87 fInCircleEdge = &this->addVertexAttrib("inCircleEdge", kVec4f_GrVertexAt
tribType); | 87 fInCircleEdge = &this->addVertexAttrib("inCircleEdge", kVec4f_GrVertexAt
tribType); |
| 88 if (clipPlane) { |
| 89 fInClipPlane = &this->addVertexAttrib("inClipPlane", kVec3f_GrVertex
AttribType); |
| 90 } else { |
| 91 fInClipPlane = nullptr; |
| 92 } |
| 93 if (isectPlane) { |
| 94 fInIsectPlane = &this->addVertexAttrib("inIsectPlane", kVec3f_GrVert
exAttribType); |
| 95 } else { |
| 96 fInIsectPlane = nullptr; |
| 97 } |
| 98 if (unionPlane) { |
| 99 fInUnionPlane = &this->addVertexAttrib("inUnionPlane", kVec3f_GrVert
exAttribType); |
| 100 } else { |
| 101 fInUnionPlane = nullptr; |
| 102 } |
88 fStroke = stroke; | 103 fStroke = stroke; |
89 } | 104 } |
90 | 105 |
91 bool implementsDistanceVector() const override { return true; }; | 106 bool implementsDistanceVector() const override { return !fInClipPlane; }; |
92 | 107 |
93 virtual ~CircleGeometryProcessor() {} | 108 virtual ~CircleGeometryProcessor() {} |
94 | 109 |
95 const char* name() const override { return "CircleEdge"; } | 110 const char* name() const override { return "CircleEdge"; } |
96 | 111 |
97 void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) c
onst override { | 112 void getGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) c
onst override { |
98 GLSLProcessor::GenKey(*this, caps, b); | 113 GLSLProcessor::GenKey(*this, caps, b); |
99 } | 114 } |
100 | 115 |
101 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const overri
de { | 116 GrGLSLPrimitiveProcessor* createGLSLInstance(const GrGLSLCaps&) const overri
de { |
102 return new GLSLProcessor(); | 117 return new GLSLProcessor(); |
103 } | 118 } |
104 | 119 |
105 private: | 120 private: |
106 class GLSLProcessor : public GrGLSLGeometryProcessor { | 121 class GLSLProcessor : public GrGLSLGeometryProcessor { |
107 public: | 122 public: |
108 GLSLProcessor() {} | 123 GLSLProcessor() {} |
109 | 124 |
110 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ | 125 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ |
111 const CircleGeometryProcessor& cgp = args.fGP.cast<CircleGeometryPro
cessor>(); | 126 const CircleGeometryProcessor& cgp = args.fGP.cast<CircleGeometryPro
cessor>(); |
112 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; | 127 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder; |
113 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; | 128 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler; |
114 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; | 129 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler; |
| 130 GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; |
115 | 131 |
116 // emit attributes | 132 // emit attributes |
117 varyingHandler->emitAttributes(cgp); | 133 varyingHandler->emitAttributes(cgp); |
| 134 fragBuilder->codeAppend("vec4 circleEdge;"); |
| 135 varyingHandler->addPassThroughAttribute(cgp.fInCircleEdge, "circleEd
ge"); |
| 136 if (cgp.fInClipPlane) { |
| 137 fragBuilder->codeAppend("vec3 clipPlane;"); |
| 138 varyingHandler->addPassThroughAttribute(cgp.fInClipPlane, "clipP
lane"); |
| 139 } |
| 140 if (cgp.fInIsectPlane) { |
| 141 SkASSERT(cgp.fInClipPlane); |
| 142 fragBuilder->codeAppend("vec3 isectPlane;"); |
| 143 varyingHandler->addPassThroughAttribute(cgp.fInIsectPlane, "isec
tPlane"); |
| 144 } |
| 145 if (cgp.fInUnionPlane) { |
| 146 SkASSERT(cgp.fInClipPlane); |
| 147 fragBuilder->codeAppend("vec3 unionPlane;"); |
| 148 varyingHandler->addPassThroughAttribute(cgp.fInUnionPlane, "unio
nPlane"); |
| 149 } |
118 | 150 |
119 GrGLSLVertToFrag v(kVec4f_GrSLType); | |
120 varyingHandler->addVarying("CircleEdge", &v); | |
121 vertBuilder->codeAppendf("%s = %s;", v.vsOut(), cgp.fInCircleEdge->f
Name); | |
122 | |
123 GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder; | |
124 // setup pass through color | 151 // setup pass through color |
125 varyingHandler->addPassThroughAttribute(cgp.fInColor, args.fOutputCo
lor); | 152 varyingHandler->addPassThroughAttribute(cgp.fInColor, args.fOutputCo
lor); |
126 | 153 |
127 // Setup position | 154 // Setup position |
128 this->setupPosition(vertBuilder, gpArgs, cgp.fInPosition->fName); | 155 this->setupPosition(vertBuilder, gpArgs, cgp.fInPosition->fName); |
129 | 156 |
130 // emit transforms | 157 // emit transforms |
131 this->emitTransforms(vertBuilder, | 158 this->emitTransforms(vertBuilder, |
132 varyingHandler, | 159 varyingHandler, |
133 uniformHandler, | 160 uniformHandler, |
134 gpArgs->fPositionVar, | 161 gpArgs->fPositionVar, |
135 cgp.fInPosition->fName, | 162 cgp.fInPosition->fName, |
136 cgp.fLocalMatrix, | 163 cgp.fLocalMatrix, |
137 args.fTransformsIn, | 164 args.fTransformsIn, |
138 args.fTransformsOut); | 165 args.fTransformsOut); |
139 | 166 |
140 fragBuilder->codeAppendf("float d = length(%s.xy);", v.fsIn()); | 167 fragBuilder->codeAppend("float d = length(circleEdge.xy);"); |
141 fragBuilder->codeAppendf("float distanceToOuterEdge = %s.z * (1.0 -
d);", v.fsIn()); | 168 fragBuilder->codeAppend("float distanceToOuterEdge = circleEdge.z *
(1.0 - d);"); |
142 fragBuilder->codeAppendf("float edgeAlpha = clamp(distanceToOuterEdg
e, 0.0, 1.0);"); | 169 fragBuilder->codeAppend("float edgeAlpha = clamp(distanceToOuterEdge
, 0.0, 1.0);"); |
143 if (cgp.fStroke) { | 170 if (cgp.fStroke) { |
144 fragBuilder->codeAppendf("float distanceToInnerEdge = %s.z * (d
- %s.w);", | 171 fragBuilder->codeAppend("float distanceToInnerEdge = circleEdge.
z * (d - circleEdge.w);"); |
145 v.fsIn(), v.fsIn()); | |
146 fragBuilder->codeAppend("float innerAlpha = clamp(distanceToInne
rEdge, 0.0, 1.0);"); | 172 fragBuilder->codeAppend("float innerAlpha = clamp(distanceToInne
rEdge, 0.0, 1.0);"); |
147 fragBuilder->codeAppend("edgeAlpha *= innerAlpha;"); | 173 fragBuilder->codeAppend("edgeAlpha *= innerAlpha;"); |
148 } | 174 } |
149 | 175 |
150 if (args.fDistanceVectorName) { | 176 if (args.fDistanceVectorName) { |
151 const char* innerEdgeDistance = cgp.fStroke ? "distanceToInnerEd
ge" : "0.0"; | 177 const char* innerEdgeDistance = cgp.fStroke ? "distanceToInnerEd
ge" : "0.0"; |
152 fragBuilder->codeAppend ("if (d == 0.0) {"); // if on the center
of the circle | 178 fragBuilder->codeAppend ("if (d == 0.0) {"); // if on the center
of the circle |
153 fragBuilder->codeAppendf(" %s = vec4(1.0, 0.0, distanceToOute
rEdge, " | 179 fragBuilder->codeAppendf(" %s = vec4(1.0, 0.0, distanceToOute
rEdge, " |
154 "%s);", // no normalize | 180 "%s);", // no normalize |
155 args.fDistanceVectorName, innerEdgeDist
ance); | 181 args.fDistanceVectorName, innerEdgeDist
ance); |
156 fragBuilder->codeAppend ("} else {"); | 182 fragBuilder->codeAppend ("} else {"); |
157 fragBuilder->codeAppendf(" %s = vec4(normalize(%s.xy), distan
ceToOuterEdge, " | 183 fragBuilder->codeAppendf(" %s = vec4(normalize(circleEdge.xy)
, distanceToOuterEdge, %s);", |
158 "%s);", | 184 args.fDistanceVectorName, innerEdgeDist
ance); |
159 args.fDistanceVectorName, v.fsIn(), inn
erEdgeDistance); | |
160 fragBuilder->codeAppend ("}"); | 185 fragBuilder->codeAppend ("}"); |
161 } | 186 } |
162 | 187 if (cgp.fInClipPlane) { |
| 188 fragBuilder->codeAppend("float clip = clamp(circleEdge.z * dot(c
ircleEdge.xy, clipPlane.xy) + clipPlane.z, 0.0, 1.0);"); |
| 189 if (cgp.fInIsectPlane) { |
| 190 fragBuilder->codeAppend("clip *= clamp(circleEdge.z * dot(ci
rcleEdge.xy, isectPlane.xy) + isectPlane.z, 0.0, 1.0);"); |
| 191 } |
| 192 if (cgp.fInUnionPlane) { |
| 193 fragBuilder->codeAppend("clip += (1-clip)*clamp(circleEdge.z
* dot(circleEdge.xy, unionPlane.xy) + unionPlane.z, 0.0, 1.0);"); |
| 194 } |
| 195 fragBuilder->codeAppend("edgeAlpha *= clip;"); |
| 196 } |
163 fragBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCovera
ge); | 197 fragBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCovera
ge); |
164 } | 198 } |
165 | 199 |
166 static void GenKey(const GrGeometryProcessor& gp, | 200 static void GenKey(const GrGeometryProcessor& gp, |
167 const GrGLSLCaps&, | 201 const GrGLSLCaps&, |
168 GrProcessorKeyBuilder* b) { | 202 GrProcessorKeyBuilder* b) { |
169 const CircleGeometryProcessor& cgp = gp.cast<CircleGeometryProcessor
>(); | 203 const CircleGeometryProcessor& cgp = gp.cast<CircleGeometryProcessor
>(); |
170 uint16_t key = cgp.fStroke ? 0x1 : 0x0; | 204 uint16_t key; |
171 key |= cgp.fLocalMatrix.hasPerspective() ? 0x2 : 0x0; | 205 key = cgp.fStroke ? 0x01 : 0x0; |
| 206 key |= cgp.fLocalMatrix.hasPerspective() ? 0x02 : 0x0; |
| 207 key |= cgp.fInClipPlane ? 0x04 : 0x0; |
| 208 key |= cgp.fInIsectPlane ? 0x08 : 0x0; |
| 209 key |= cgp.fInUnionPlane ? 0x10 : 0x0; |
172 b->add32(key); | 210 b->add32(key); |
173 } | 211 } |
174 | 212 |
175 void setData(const GrGLSLProgramDataManager& pdman, | 213 void setData(const GrGLSLProgramDataManager&, const GrPrimitiveProcessor
&) override {} |
176 const GrPrimitiveProcessor& gp) override { | |
177 } | |
178 | 214 |
179 void setTransformData(const GrPrimitiveProcessor& primProc, | 215 void setTransformData(const GrPrimitiveProcessor& primProc, |
180 const GrGLSLProgramDataManager& pdman, | 216 const GrGLSLProgramDataManager& pdman, |
181 int index, | 217 int index, |
182 const SkTArray<const GrCoordTransform*, true>& tra
nsforms) override { | 218 const SkTArray<const GrCoordTransform*, true>& tra
nsforms) override { |
183 this->setTransformDataHelper(primProc.cast<CircleGeometryProcessor>(
).fLocalMatrix, | 219 this->setTransformDataHelper(primProc.cast<CircleGeometryProcessor>(
).fLocalMatrix, |
184 pdman, index, transforms); | 220 pdman, index, transforms); |
185 } | 221 } |
186 | 222 |
187 private: | 223 private: |
188 typedef GrGLSLGeometryProcessor INHERITED; | 224 typedef GrGLSLGeometryProcessor INHERITED; |
189 }; | 225 }; |
190 | 226 |
191 SkMatrix fLocalMatrix; | 227 SkMatrix fLocalMatrix; |
192 const Attribute* fInPosition; | 228 const Attribute* fInPosition; |
193 const Attribute* fInColor; | 229 const Attribute* fInColor; |
194 const Attribute* fInCircleEdge; | 230 const Attribute* fInCircleEdge; |
| 231 const Attribute* fInClipPlane; |
| 232 const Attribute* fInIsectPlane; |
| 233 const Attribute* fInUnionPlane; |
195 bool fStroke; | 234 bool fStroke; |
196 | 235 |
197 GR_DECLARE_GEOMETRY_PROCESSOR_TEST; | 236 GR_DECLARE_GEOMETRY_PROCESSOR_TEST; |
198 | 237 |
199 typedef GrGeometryProcessor INHERITED; | 238 typedef GrGeometryProcessor INHERITED; |
200 }; | 239 }; |
201 | 240 |
202 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(CircleGeometryProcessor); | 241 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(CircleGeometryProcessor); |
203 | 242 |
204 sk_sp<GrGeometryProcessor> CircleGeometryProcessor::TestCreate(GrProcessorTestDa
ta* d) { | 243 sk_sp<GrGeometryProcessor> CircleGeometryProcessor::TestCreate(GrProcessorTestDa
ta* d) { |
205 return sk_sp<GrGeometryProcessor>( | 244 return sk_sp<GrGeometryProcessor>( |
206 new CircleGeometryProcessor(d->fRandom->nextBool(), GrTest::TestMatrix(d
->fRandom))); | 245 new CircleGeometryProcessor(d->fRandom->nextBool(), d->fRandom->nextBool
(), |
| 246 d->fRandom->nextBool(), d->fRandom->nextBool
(), |
| 247 GrTest::TestMatrix(d->fRandom))); |
207 } | 248 } |
208 | 249 |
209 /////////////////////////////////////////////////////////////////////////////// | 250 /////////////////////////////////////////////////////////////////////////////// |
210 | 251 |
211 /** | 252 /** |
212 * The output of this effect is a modulation of the input color and coverage for
an axis-aligned | 253 * The output of this effect is a modulation of the input color and coverage for
an axis-aligned |
213 * ellipse, specified as a 2D offset from center, and the reciprocals of the out
er and inner radii, | 254 * ellipse, specified as a 2D offset from center, and the reciprocals of the out
er and inner radii, |
214 * in both x and y directions. | 255 * in both x and y directions. |
215 * | 256 * |
216 * We are using an implicit function of x^2/a^2 + y^2/b^2 - 1 = 0. | 257 * We are using an implicit function of x^2/a^2 + y^2/b^2 - 1 = 0. |
(...skipping 305 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
522 new DIEllipseGeometryProcessor(GrTest::TestMatrix(d->fRandom), | 563 new DIEllipseGeometryProcessor(GrTest::TestMatrix(d->fRandom), |
523 (DIEllipseStyle)(d->fRandom->nextRangeU(0
,2)))); | 564 (DIEllipseStyle)(d->fRandom->nextRangeU(0
,2)))); |
524 } | 565 } |
525 | 566 |
526 /////////////////////////////////////////////////////////////////////////////// | 567 /////////////////////////////////////////////////////////////////////////////// |
527 | 568 |
528 class CircleBatch : public GrVertexBatch { | 569 class CircleBatch : public GrVertexBatch { |
529 public: | 570 public: |
530 DEFINE_BATCH_CLASS_ID | 571 DEFINE_BATCH_CLASS_ID |
531 | 572 |
532 CircleBatch(GrColor color, const SkMatrix& viewMatrix, const SkRect& circle, | 573 /** Optional extra params to render a partial arc rather than a full circle.
*/ |
533 const SkStrokeRec& stroke) | 574 struct ArcParams { |
534 : INHERITED(ClassID()) | 575 SkScalar fStartAngleRadians; |
535 , fViewMatrixIfUsingLocalCoords(viewMatrix) { | 576 SkScalar fSweepAngleRadians; |
536 SkPoint center = SkPoint::Make(circle.centerX(), circle.centerY()); | 577 bool fUseCenter; |
| 578 }; |
| 579 static GrDrawBatch* Create(GrColor color, const SkMatrix& viewMatrix, SkPoin
t center, |
| 580 SkScalar radius, const GrStyle& style, |
| 581 const ArcParams* arcParams = nullptr) { |
| 582 SkASSERT(circle_stays_circle(viewMatrix)); |
| 583 const SkStrokeRec& stroke = style.strokeRec(); |
| 584 if (style.hasPathEffect()) { |
| 585 return nullptr; |
| 586 } |
| 587 SkStrokeRec::Style recStyle = stroke.getStyle(); |
| 588 if (arcParams) { |
| 589 // Arc support depends on the style. |
| 590 switch (recStyle) { |
| 591 case SkStrokeRec::kStrokeAndFill_Style: |
| 592 // This produces a strange result that this batch doesn't im
plement. |
| 593 return nullptr; |
| 594 case SkStrokeRec::kFill_Style: |
| 595 // This supports all fills. |
| 596 break; |
| 597 case SkStrokeRec::kStroke_Style: // fall through |
| 598 case SkStrokeRec::kHairline_Style: |
| 599 // Strokes that don't use the center point are supported wit
h butt cap. |
| 600 if (arcParams->fUseCenter || stroke.getCap() != SkPaint::kBu
tt_Cap) { |
| 601 return nullptr; |
| 602 } |
| 603 break; |
| 604 } |
| 605 } |
| 606 |
537 viewMatrix.mapPoints(¢er, 1); | 607 viewMatrix.mapPoints(¢er, 1); |
538 SkScalar radius = viewMatrix.mapRadius(SkScalarHalf(circle.width())); | 608 radius = viewMatrix.mapRadius(radius); |
539 SkScalar strokeWidth = viewMatrix.mapRadius(stroke.getWidth()); | 609 SkScalar strokeWidth = viewMatrix.mapRadius(stroke.getWidth()); |
540 | 610 |
541 SkStrokeRec::Style style = stroke.getStyle(); | 611 bool isStrokeOnly = SkStrokeRec::kStroke_Style == recStyle || |
542 bool isStrokeOnly = SkStrokeRec::kStroke_Style == style || | 612 SkStrokeRec::kHairline_Style == recStyle; |
543 SkStrokeRec::kHairline_Style == style; | 613 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == re
cStyle; |
544 bool hasStroke = isStrokeOnly || SkStrokeRec::kStrokeAndFill_Style == st
yle; | |
545 | 614 |
546 SkScalar innerRadius = 0.0f; | 615 SkScalar innerRadius = 0.0f; |
547 SkScalar outerRadius = radius; | 616 SkScalar outerRadius = radius; |
548 SkScalar halfWidth = 0; | 617 SkScalar halfWidth = 0; |
549 if (hasStroke) { | 618 if (hasStroke) { |
550 if (SkScalarNearlyZero(strokeWidth)) { | 619 if (SkScalarNearlyZero(strokeWidth)) { |
551 halfWidth = SK_ScalarHalf; | 620 halfWidth = SK_ScalarHalf; |
552 } else { | 621 } else { |
553 halfWidth = SkScalarHalf(strokeWidth); | 622 halfWidth = SkScalarHalf(strokeWidth); |
554 } | 623 } |
555 | 624 |
556 outerRadius += halfWidth; | 625 outerRadius += halfWidth; |
557 if (isStrokeOnly) { | 626 if (isStrokeOnly) { |
558 innerRadius = radius - halfWidth; | 627 innerRadius = radius - halfWidth; |
559 } | 628 } |
560 } | 629 } |
561 | 630 |
562 // The radii are outset for two reasons. First, it allows the shader to
simply perform | 631 // The radii are outset for two reasons. First, it allows the shader to
simply perform |
563 // simpler computation because the computed alpha is zero, rather than 5
0%, at the radius. | 632 // simpler computation because the computed alpha is zero, rather than 5
0%, at the radius. |
564 // Second, the outer radius is used to compute the verts of the bounding
box that is | 633 // Second, the outer radius is used to compute the verts of the bounding
box that is |
565 // rendered and the outset ensures the box will cover all partially cove
red by the circle. | 634 // rendered and the outset ensures the box will cover all partially cove
red by the circle. |
566 outerRadius += SK_ScalarHalf; | 635 outerRadius += SK_ScalarHalf; |
567 innerRadius -= SK_ScalarHalf; | 636 innerRadius -= SK_ScalarHalf; |
| 637 CircleBatch* batch = new CircleBatch(); |
| 638 batch->fViewMatrixIfUsingLocalCoords = viewMatrix; |
568 | 639 |
569 fGeoData.emplace_back(Geometry { | 640 // This makes every point fully inside the intersection plane. |
570 color, | 641 static constexpr SkScalar kUnusedIsectPlane[] = {0.f, 0.f, 1.f}; |
571 innerRadius, | 642 // This makes every point fully outside the union plane. |
572 outerRadius, | 643 static constexpr SkScalar kUnusedUnionPlane[] = {0.f, 0.f, 0.f}; |
573 SkRect::MakeLTRB(center.fX - outerRadius, center.fY - outerRadius, | 644 SkRect devBounds = SkRect::MakeLTRB(center.fX - outerRadius, center.fY -
outerRadius, |
574 center.fX + outerRadius, center.fY + outerRadius) | 645 center.fX + outerRadius, center.fY +
outerRadius); |
575 }); | 646 |
| 647 if (arcParams) { |
| 648 // The shader operates in a space where the circle is translated to
be centered at the |
| 649 // origin. Here we compute points on the unit circle at the starting
and ending angles. |
| 650 SkPoint startPoint, stopPoint; |
| 651 startPoint.fY = SkScalarSinCos(arcParams->fStartAngleRadians, &start
Point.fX); |
| 652 SkScalar endAngle = arcParams->fStartAngleRadians + arcParams->fSwee
pAngleRadians; |
| 653 stopPoint.fY = SkScalarSinCos(endAngle, &stopPoint.fX); |
| 654 // Like a fill without useCenter, butt-cap stroke can be implemented
by clipping against |
| 655 // radial lines. However, in both cases we have to be careful about
the half-circle. |
| 656 // case. In that case the two radial lines are equal and so that edg
e gets clipped |
| 657 // twice. Since the shared edge goes through the center we fall back
on the useCenter |
| 658 // case. |
| 659 bool useCenter = (arcParams->fUseCenter || isStrokeOnly) && |
| 660 !SkScalarNearlyEqual(SkScalarAbs(arcParams->fSweepA
ngleRadians), |
| 661 SK_ScalarPI); |
| 662 if (useCenter) { |
| 663 SkVector norm0 = {startPoint.fY, -startPoint.fX}; |
| 664 SkVector norm1 = {stopPoint.fY, -stopPoint.fX}; |
| 665 if (arcParams->fSweepAngleRadians > 0) { |
| 666 norm0.negate(); |
| 667 } else { |
| 668 norm1.negate(); |
| 669 } |
| 670 batch->fClipPlane = true; |
| 671 if (SkScalarAbs(arcParams->fSweepAngleRadians) > SK_ScalarPI) { |
| 672 batch->fGeoData.emplace_back(Geometry { |
| 673 color, |
| 674 innerRadius, |
| 675 outerRadius, |
| 676 {norm0.fX, norm0.fY, 0.5f}, |
| 677 {kUnusedIsectPlane[0], kUnusedIsectPlane[1], kUnused
IsectPlane[2]}, |
| 678 {norm1.fX, norm1.fY, 0.5f}, |
| 679 devBounds |
| 680 }); |
| 681 batch->fClipPlaneIsect = false; |
| 682 batch->fClipPlaneUnion = true; |
| 683 } else { |
| 684 batch->fGeoData.emplace_back(Geometry { |
| 685 color, |
| 686 innerRadius, |
| 687 outerRadius, |
| 688 {norm0.fX, norm0.fY, 0.5f}, |
| 689 {norm1.fX, norm1.fY, 0.5f}, |
| 690 {kUnusedUnionPlane[0], kUnusedUnionPlane[1], kUnused
UnionPlane[2]}, |
| 691 devBounds |
| 692 }); |
| 693 batch->fClipPlaneIsect = true; |
| 694 batch->fClipPlaneUnion = false; |
| 695 } |
| 696 } else { |
| 697 // We clip to a secant of the original circle. |
| 698 startPoint.scale(radius); |
| 699 stopPoint.scale(radius); |
| 700 SkVector norm = {startPoint.fY - stopPoint.fY, stopPoint.fX - st
artPoint.fX}; |
| 701 norm.normalize(); |
| 702 if (arcParams->fSweepAngleRadians > 0) { |
| 703 norm.negate(); |
| 704 } |
| 705 SkScalar d = -norm.dot(startPoint) + 0.5f; |
| 706 |
| 707 batch->fGeoData.emplace_back(Geometry { |
| 708 color, |
| 709 innerRadius, |
| 710 outerRadius, |
| 711 {norm.fX, norm.fY, d}, |
| 712 {kUnusedIsectPlane[0], kUnusedIsectPlane[1], kUnusedIsec
tPlane[2]}, |
| 713 {kUnusedUnionPlane[0], kUnusedUnionPlane[1], kUnusedUnio
nPlane[2]}, |
| 714 devBounds |
| 715 }); |
| 716 batch->fClipPlane = true; |
| 717 batch->fClipPlaneIsect = false; |
| 718 batch->fClipPlaneUnion = false; |
| 719 } |
| 720 } else { |
| 721 batch->fGeoData.emplace_back(Geometry { |
| 722 color, |
| 723 innerRadius, |
| 724 outerRadius, |
| 725 {kUnusedIsectPlane[0], kUnusedIsectPlane[1], kUnusedIsectPlane[2
]}, |
| 726 {kUnusedIsectPlane[0], kUnusedIsectPlane[1], kUnusedIsectPlane[2
]}, |
| 727 {kUnusedUnionPlane[0], kUnusedUnionPlane[1], kUnusedUnionPlane[2
]}, |
| 728 devBounds |
| 729 }); |
| 730 batch->fClipPlane = false; |
| 731 batch->fClipPlaneIsect = false; |
| 732 batch->fClipPlaneUnion = false; |
| 733 } |
576 // Use the original radius and stroke radius for the bounds so that it d
oes not include the | 734 // Use the original radius and stroke radius for the bounds so that it d
oes not include the |
577 // AA bloat. | 735 // AA bloat. |
578 radius += halfWidth; | 736 radius += halfWidth; |
579 this->setBounds({center.fX - radius, center.fY - radius, | 737 batch->setBounds({center.fX - radius, center.fY - radius, |
580 center.fX + radius, center.fY + radius}, | 738 center.fX + radius, center.fY + radius}, |
581 HasAABloat::kYes, IsZeroArea::kNo); | 739 HasAABloat::kYes, IsZeroArea::kNo); |
582 fStroked = isStrokeOnly && innerRadius > 0; | 740 batch->fStroked = isStrokeOnly && innerRadius > 0; |
| 741 return batch; |
583 } | 742 } |
584 | 743 |
585 const char* name() const override { return "CircleBatch"; } | 744 const char* name() const override { return "CircleBatch"; } |
586 | 745 |
587 SkString dumpInfo() const override { | 746 SkString dumpInfo() const override { |
588 SkString string; | 747 SkString string; |
589 for (int i = 0; i < fGeoData.count(); ++i) { | 748 for (int i = 0; i < fGeoData.count(); ++i) { |
590 string.appendf("Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.
2f]," | 749 string.appendf("Color: 0x%08x Rect [L: %.2f, T: %.2f, R: %.2f, B: %.
2f]," |
591 "InnerRad: %.2f, OuterRad: %.2f\n", | 750 "InnerRad: %.2f, OuterRad: %.2f\n", |
592 fGeoData[i].fColor, | 751 fGeoData[i].fColor, |
593 fGeoData[i].fDevBounds.fLeft, fGeoData[i].fDevBounds.
fTop, | 752 fGeoData[i].fDevBounds.fLeft, fGeoData[i].fDevBounds.
fTop, |
594 fGeoData[i].fDevBounds.fRight, fGeoData[i].fDevBounds
.fBottom, | 753 fGeoData[i].fDevBounds.fRight, fGeoData[i].fDevBounds
.fBottom, |
595 fGeoData[i].fInnerRadius, | 754 fGeoData[i].fInnerRadius, |
596 fGeoData[i].fOuterRadius); | 755 fGeoData[i].fOuterRadius); |
597 } | 756 } |
598 string.append(INHERITED::dumpInfo()); | 757 string.append(INHERITED::dumpInfo()); |
599 return string; | 758 return string; |
600 } | 759 } |
601 | 760 |
602 void computePipelineOptimizations(GrInitInvariantOutput* color, | 761 void computePipelineOptimizations(GrInitInvariantOutput* color, |
603 GrInitInvariantOutput* coverage, | 762 GrInitInvariantOutput* coverage, |
604 GrBatchToXPOverrides* overrides) const ove
rride { | 763 GrBatchToXPOverrides* overrides) const ove
rride { |
605 // When this is called on a batch, there is only one geometry bundle | 764 // When this is called on a batch, there is only one geometry bundle |
606 color->setKnownFourComponents(fGeoData[0].fColor); | 765 color->setKnownFourComponents(fGeoData[0].fColor); |
607 coverage->setUnknownSingleComponent(); | 766 coverage->setUnknownSingleComponent(); |
608 } | 767 } |
609 | 768 |
610 private: | 769 private: |
| 770 CircleBatch() : INHERITED(ClassID()) {} |
611 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { | 771 void initBatchTracker(const GrXPOverridesForBatch& overrides) override { |
612 // Handle any overrides that affect our GP. | 772 // Handle any overrides that affect our GP. |
613 overrides.getOverrideColorIfSet(&fGeoData[0].fColor); | 773 overrides.getOverrideColorIfSet(&fGeoData[0].fColor); |
614 if (!overrides.readsLocalCoords()) { | 774 if (!overrides.readsLocalCoords()) { |
615 fViewMatrixIfUsingLocalCoords.reset(); | 775 fViewMatrixIfUsingLocalCoords.reset(); |
616 } | 776 } |
617 } | 777 } |
618 | 778 |
619 void onPrepareDraws(Target* target) const override { | 779 void onPrepareDraws(Target* target) const override { |
620 SkMatrix localMatrix; | 780 SkMatrix localMatrix; |
621 if (!fViewMatrixIfUsingLocalCoords.invert(&localMatrix)) { | 781 if (!fViewMatrixIfUsingLocalCoords.invert(&localMatrix)) { |
622 return; | 782 return; |
623 } | 783 } |
624 | 784 |
625 // Setup geometry processor | 785 // Setup geometry processor |
626 SkAutoTUnref<GrGeometryProcessor> gp(new CircleGeometryProcessor(fStroke
d, localMatrix)); | 786 SkAutoTUnref<GrGeometryProcessor> gp(new CircleGeometryProcessor(fStroke
d, fClipPlane, |
| 787 fClipPl
aneIsect, |
| 788 fClipPl
aneUnion, |
| 789 localMa
trix)); |
| 790 |
| 791 struct CircleVertex { |
| 792 SkPoint fPos; |
| 793 GrColor fColor; |
| 794 SkPoint fOffset; |
| 795 SkScalar fOuterRadius; |
| 796 SkScalar fInnerRadius; |
| 797 // These planes may or may not be present in the vertex buffer. |
| 798 SkScalar fHalfPlanes[3][3]; |
| 799 }; |
627 | 800 |
628 int instanceCount = fGeoData.count(); | 801 int instanceCount = fGeoData.count(); |
629 size_t vertexStride = gp->getVertexStride(); | 802 size_t vertexStride = gp->getVertexStride(); |
630 SkASSERT(vertexStride == sizeof(CircleVertex)); | 803 SkASSERT(vertexStride == sizeof(CircleVertex) - (fClipPlane ? 0 : 3 * si
zeof(SkScalar)) |
| 804 - (fClipPlaneIsect? 0 : 3
* sizeof(SkScalar)) |
| 805 - (fClipPlaneUnion? 0 : 3
* sizeof(SkScalar))); |
631 QuadHelper helper; | 806 QuadHelper helper; |
632 CircleVertex* verts = reinterpret_cast<CircleVertex*>(helper.init(target
, vertexStride, | 807 char* vertices = reinterpret_cast<char*>(helper.init(target, vertexStrid
e, instanceCount)); |
633 instan
ceCount)); | 808 if (!vertices) { |
634 if (!verts) { | |
635 return; | 809 return; |
636 } | 810 } |
637 | 811 |
638 for (int i = 0; i < instanceCount; i++) { | 812 for (int i = 0; i < instanceCount; i++) { |
639 const Geometry& geom = fGeoData[i]; | 813 const Geometry& geom = fGeoData[i]; |
640 | 814 |
641 GrColor color = geom.fColor; | 815 GrColor color = geom.fColor; |
642 SkScalar innerRadius = geom.fInnerRadius; | 816 SkScalar innerRadius = geom.fInnerRadius; |
643 SkScalar outerRadius = geom.fOuterRadius; | 817 SkScalar outerRadius = geom.fOuterRadius; |
644 | 818 |
645 const SkRect& bounds = geom.fDevBounds; | 819 const SkRect& bounds = geom.fDevBounds; |
| 820 CircleVertex* v0 = reinterpret_cast<CircleVertex*>(vertices + (4 * i
+ 0)*vertexStride); |
| 821 CircleVertex* v1 = reinterpret_cast<CircleVertex*>(vertices + (4 * i
+ 1)*vertexStride); |
| 822 CircleVertex* v2 = reinterpret_cast<CircleVertex*>(vertices + (4 * i
+ 2)*vertexStride); |
| 823 CircleVertex* v3 = reinterpret_cast<CircleVertex*>(vertices + (4 * i
+ 3)*vertexStride); |
646 | 824 |
647 // The inner radius in the vertex data must be specified in normaliz
ed space. | 825 // The inner radius in the vertex data must be specified in normaliz
ed space. |
648 innerRadius = innerRadius / outerRadius; | 826 innerRadius = innerRadius / outerRadius; |
649 verts[0].fPos = SkPoint::Make(bounds.fLeft, bounds.fTop); | 827 v0->fPos = SkPoint::Make(bounds.fLeft, bounds.fTop); |
650 verts[0].fColor = color; | 828 v0->fColor = color; |
651 verts[0].fOffset = SkPoint::Make(-1, -1); | 829 v0->fOffset = SkPoint::Make(-1, -1); |
652 verts[0].fOuterRadius = outerRadius; | 830 v0->fOuterRadius = outerRadius; |
653 verts[0].fInnerRadius = innerRadius; | 831 v0->fInnerRadius = innerRadius; |
654 | 832 |
655 verts[1].fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom); | 833 v1->fPos = SkPoint::Make(bounds.fLeft, bounds.fBottom); |
656 verts[1].fColor = color; | 834 v1->fColor = color; |
657 verts[1].fOffset = SkPoint::Make(-1, 1); | 835 v1->fOffset = SkPoint::Make(-1, 1); |
658 verts[1].fOuterRadius = outerRadius; | 836 v1->fOuterRadius = outerRadius; |
659 verts[1].fInnerRadius = innerRadius; | 837 v1->fInnerRadius = innerRadius; |
660 | 838 |
661 verts[2].fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); | 839 v2->fPos = SkPoint::Make(bounds.fRight, bounds.fBottom); |
662 verts[2].fColor = color; | 840 v2->fColor = color; |
663 verts[2].fOffset = SkPoint::Make(1, 1); | 841 v2->fOffset = SkPoint::Make(1, 1); |
664 verts[2].fOuterRadius = outerRadius; | 842 v2->fOuterRadius = outerRadius; |
665 verts[2].fInnerRadius = innerRadius; | 843 v2->fInnerRadius = innerRadius; |
666 | 844 |
667 verts[3].fPos = SkPoint::Make(bounds.fRight, bounds.fTop); | 845 v3->fPos = SkPoint::Make(bounds.fRight, bounds.fTop); |
668 verts[3].fColor = color; | 846 v3->fColor = color; |
669 verts[3].fOffset = SkPoint::Make(1, -1); | 847 v3->fOffset = SkPoint::Make(1, -1); |
670 verts[3].fOuterRadius = outerRadius; | 848 v3->fOuterRadius = outerRadius; |
671 verts[3].fInnerRadius = innerRadius; | 849 v3->fInnerRadius = innerRadius; |
672 | 850 |
673 verts += kVerticesPerQuad; | 851 if (fClipPlane) { |
| 852 memcpy(v0->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar)
); |
| 853 memcpy(v1->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar)
); |
| 854 memcpy(v2->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar)
); |
| 855 memcpy(v3->fHalfPlanes[0], geom.fClipPlane, 3 * sizeof(SkScalar)
); |
| 856 } |
| 857 int unionIdx = 1; |
| 858 if (fClipPlaneIsect) { |
| 859 memcpy(v0->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar
)); |
| 860 memcpy(v1->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar
)); |
| 861 memcpy(v2->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar
)); |
| 862 memcpy(v3->fHalfPlanes[1], geom.fIsectPlane, 3 * sizeof(SkScalar
)); |
| 863 unionIdx = 2; |
| 864 } |
| 865 if (fClipPlaneUnion) { |
| 866 memcpy(v0->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(S
kScalar)); |
| 867 memcpy(v1->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(S
kScalar)); |
| 868 memcpy(v2->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(S
kScalar)); |
| 869 memcpy(v3->fHalfPlanes[unionIdx], geom.fUnionPlane, 3 * sizeof(S
kScalar)); |
| 870 } |
674 } | 871 } |
675 helper.recordDraw(target, gp); | 872 helper.recordDraw(target, gp); |
676 } | 873 } |
677 | 874 |
678 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { | 875 bool onCombineIfPossible(GrBatch* t, const GrCaps& caps) override { |
679 CircleBatch* that = t->cast<CircleBatch>(); | 876 CircleBatch* that = t->cast<CircleBatch>(); |
680 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pi
peline(), | 877 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pi
peline(), |
681 that->bounds(), caps)) { | 878 that->bounds(), caps)) { |
682 return false; | 879 return false; |
683 } | 880 } |
684 | 881 |
685 if (this->fStroked != that->fStroked) { | 882 if (this->fStroked != that->fStroked) { |
686 return false; | 883 return false; |
687 } | 884 } |
688 | 885 |
| 886 // Because we've set up the batches that don't use the planes with noop
values |
| 887 // we can just accumulate used planes by later batches. |
| 888 fClipPlane |= that->fClipPlane; |
| 889 fClipPlaneIsect |= that->fClipPlaneIsect; |
| 890 fClipPlaneUnion |= that->fClipPlaneUnion; |
| 891 |
689 if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsing
LocalCoords)) { | 892 if (!fViewMatrixIfUsingLocalCoords.cheapEqualTo(that->fViewMatrixIfUsing
LocalCoords)) { |
690 return false; | 893 return false; |
691 } | 894 } |
692 | 895 |
693 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); | 896 fGeoData.push_back_n(that->fGeoData.count(), that->fGeoData.begin()); |
694 this->joinBounds(*that); | 897 this->joinBounds(*that); |
695 return true; | 898 return true; |
696 } | 899 } |
697 | 900 |
698 struct Geometry { | 901 struct Geometry { |
699 GrColor fColor; | 902 GrColor fColor; |
700 SkScalar fInnerRadius; | 903 SkScalar fInnerRadius; |
701 SkScalar fOuterRadius; | 904 SkScalar fOuterRadius; |
702 SkRect fDevBounds; | 905 SkScalar fClipPlane[3]; |
| 906 SkScalar fIsectPlane[3]; |
| 907 SkScalar fUnionPlane[3]; |
| 908 SkRect fDevBounds; |
703 }; | 909 }; |
704 | 910 |
705 bool fStroked; | 911 bool fStroked; |
| 912 bool fClipPlane; |
| 913 bool fClipPlaneIsect; |
| 914 bool fClipPlaneUnion; |
706 SkMatrix fViewMatrixIfUsingLocalCoords; | 915 SkMatrix fViewMatrixIfUsingLocalCoords; |
707 SkSTArray<1, Geometry, true> fGeoData; | 916 SkSTArray<1, Geometry, true> fGeoData; |
708 | 917 |
709 typedef GrVertexBatch INHERITED; | 918 typedef GrVertexBatch INHERITED; |
710 }; | 919 }; |
711 | 920 |
712 /////////////////////////////////////////////////////////////////////////////// | 921 /////////////////////////////////////////////////////////////////////////////// |
713 | 922 |
714 class EllipseBatch : public GrVertexBatch { | 923 class EllipseBatch : public GrVertexBatch { |
715 public: | 924 public: |
(...skipping 520 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1236 } | 1445 } |
1237 | 1446 |
1238 void onPrepareDraws(Target* target) const override { | 1447 void onPrepareDraws(Target* target) const override { |
1239 // Invert the view matrix as a local matrix (if any other processors req
uire coords). | 1448 // Invert the view matrix as a local matrix (if any other processors req
uire coords). |
1240 SkMatrix localMatrix; | 1449 SkMatrix localMatrix; |
1241 if (!fViewMatrixIfUsingLocalCoords.invert(&localMatrix)) { | 1450 if (!fViewMatrixIfUsingLocalCoords.invert(&localMatrix)) { |
1242 return; | 1451 return; |
1243 } | 1452 } |
1244 | 1453 |
1245 // Setup geometry processor | 1454 // Setup geometry processor |
1246 SkAutoTUnref<GrGeometryProcessor> gp(new CircleGeometryProcessor(fStroke
d, localMatrix)); | 1455 SkAutoTUnref<GrGeometryProcessor> gp(new CircleGeometryProcessor(fStroke
d, false, false, |
| 1456 false,
localMatrix)); |
| 1457 |
| 1458 struct CircleVertex { |
| 1459 SkPoint fPos; |
| 1460 GrColor fColor; |
| 1461 SkPoint fOffset; |
| 1462 SkScalar fOuterRadius; |
| 1463 SkScalar fInnerRadius; |
| 1464 // No half plane, we don't use it here. |
| 1465 }; |
1247 | 1466 |
1248 int instanceCount = fGeoData.count(); | 1467 int instanceCount = fGeoData.count(); |
1249 size_t vertexStride = gp->getVertexStride(); | 1468 size_t vertexStride = gp->getVertexStride(); |
1250 SkASSERT(vertexStride == sizeof(CircleVertex)); | 1469 SkASSERT(vertexStride == sizeof(CircleVertex)); |
1251 | 1470 |
1252 // drop out the middle quad if we're stroked | 1471 // drop out the middle quad if we're stroked |
1253 int indicesPerInstance = fStroked ? kIndicesPerStrokeRRect : kIndicesPer
RRect; | 1472 int indicesPerInstance = fStroked ? kIndicesPerStrokeRRect : kIndicesPer
RRect; |
1254 SkAutoTUnref<const GrBuffer> indexBuffer( | 1473 SkAutoTUnref<const GrBuffer> indexBuffer( |
1255 ref_rrect_index_buffer(fStroked, target->resourceProvider())); | 1474 ref_rrect_index_buffer(fStroked, target->resourceProvider())); |
1256 | 1475 |
(...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1624 return RRectEllipseRendererBatch::Create(color, viewMatrix, bounds, xRad
ius, yRadius, | 1843 return RRectEllipseRendererBatch::Create(color, viewMatrix, bounds, xRad
ius, yRadius, |
1625 scaledStroke, isStrokeOnly); | 1844 scaledStroke, isStrokeOnly); |
1626 | 1845 |
1627 } | 1846 } |
1628 } | 1847 } |
1629 | 1848 |
1630 GrDrawBatch* GrOvalRenderer::CreateRRectBatch(GrColor color, | 1849 GrDrawBatch* GrOvalRenderer::CreateRRectBatch(GrColor color, |
1631 const SkMatrix& viewMatrix, | 1850 const SkMatrix& viewMatrix, |
1632 const SkRRect& rrect, | 1851 const SkRRect& rrect, |
1633 const SkStrokeRec& stroke, | 1852 const SkStrokeRec& stroke, |
1634 GrShaderCaps* shaderCaps) { | 1853 const GrShaderCaps* shaderCaps) { |
1635 if (rrect.isOval()) { | 1854 if (rrect.isOval()) { |
1636 return CreateOvalBatch(color, viewMatrix, rrect.getBounds(), stroke, sha
derCaps); | 1855 return CreateOvalBatch(color, viewMatrix, rrect.getBounds(), stroke, sha
derCaps); |
1637 } | 1856 } |
1638 | 1857 |
1639 if (!viewMatrix.rectStaysRect() || !rrect.isSimple()) { | 1858 if (!viewMatrix.rectStaysRect() || !rrect.isSimple()) { |
1640 return nullptr; | 1859 return nullptr; |
1641 } | 1860 } |
1642 | 1861 |
1643 return create_rrect_batch(color, viewMatrix, rrect, stroke); | 1862 return create_rrect_batch(color, viewMatrix, rrect, stroke); |
1644 } | 1863 } |
1645 | 1864 |
1646 /////////////////////////////////////////////////////////////////////////////// | 1865 /////////////////////////////////////////////////////////////////////////////// |
1647 | 1866 |
1648 GrDrawBatch* GrOvalRenderer::CreateOvalBatch(GrColor color, | 1867 GrDrawBatch* GrOvalRenderer::CreateOvalBatch(GrColor color, |
1649 const SkMatrix& viewMatrix, | 1868 const SkMatrix& viewMatrix, |
1650 const SkRect& oval, | 1869 const SkRect& oval, |
1651 const SkStrokeRec& stroke, | 1870 const SkStrokeRec& stroke, |
1652 GrShaderCaps* shaderCaps) { | 1871 const GrShaderCaps* shaderCaps) { |
1653 // we can draw circles | 1872 // we can draw circles |
1654 if (SkScalarNearlyEqual(oval.width(), oval.height()) && circle_stays_circle(
viewMatrix)) { | 1873 SkScalar width = oval.width(); |
1655 return new CircleBatch(color, viewMatrix, oval, stroke); | 1874 if (SkScalarNearlyEqual(width, oval.height()) && circle_stays_circle(viewMat
rix)) { |
| 1875 SkPoint center = {oval.centerX(), oval.centerY()}; |
| 1876 return CircleBatch::Create(color, viewMatrix, center, width / 2.f, |
| 1877 GrStyle(stroke, nullptr)); |
1656 } | 1878 } |
1657 | 1879 |
1658 // if we have shader derivative support, render as device-independent | 1880 // if we have shader derivative support, render as device-independent |
1659 if (shaderCaps->shaderDerivativeSupport()) { | 1881 if (shaderCaps->shaderDerivativeSupport()) { |
1660 return DIEllipseBatch::Create(color, viewMatrix, oval, stroke); | 1882 return DIEllipseBatch::Create(color, viewMatrix, oval, stroke); |
1661 } | 1883 } |
1662 | 1884 |
1663 // otherwise axis-aligned ellipses only | 1885 // otherwise axis-aligned ellipses only |
1664 if (viewMatrix.rectStaysRect()) { | 1886 if (viewMatrix.rectStaysRect()) { |
1665 return EllipseBatch::Create(color, viewMatrix, oval, stroke); | 1887 return EllipseBatch::Create(color, viewMatrix, oval, stroke); |
1666 } | 1888 } |
1667 | 1889 |
1668 return nullptr; | 1890 return nullptr; |
1669 } | 1891 } |
1670 | 1892 |
1671 /////////////////////////////////////////////////////////////////////////////// | 1893 /////////////////////////////////////////////////////////////////////////////// |
1672 | 1894 |
| 1895 GrDrawBatch* GrOvalRenderer::CreateArcBatch(GrColor color, |
| 1896 const SkMatrix& viewMatrix, |
| 1897 const SkRect& oval, |
| 1898 SkScalar startAngle, SkScalar sweepA
ngle, |
| 1899 bool useCenter, |
| 1900 const GrStyle& style, |
| 1901 const GrShaderCaps* shaderCaps) { |
| 1902 SkScalar width = oval.width(); |
| 1903 if (!SkScalarNearlyEqual(width, oval.height()) || !circle_stays_circle(viewM
atrix)) { |
| 1904 return nullptr; |
| 1905 } |
| 1906 SkPoint center = {oval.centerX(), oval.centerY()}; |
| 1907 CircleBatch::ArcParams arcParams = { |
| 1908 SkDegreesToRadians(startAngle), |
| 1909 SkDegreesToRadians(sweepAngle), |
| 1910 useCenter |
| 1911 }; |
| 1912 return CircleBatch::Create(color, viewMatrix, center, width/2.f, style, &arc
Params); |
| 1913 } |
| 1914 |
| 1915 /////////////////////////////////////////////////////////////////////////////// |
| 1916 |
1673 #ifdef GR_TEST_UTILS | 1917 #ifdef GR_TEST_UTILS |
1674 | 1918 |
1675 DRAW_BATCH_TEST_DEFINE(CircleBatch) { | 1919 DRAW_BATCH_TEST_DEFINE(CircleBatch) { |
1676 SkMatrix viewMatrix = GrTest::TestMatrix(random); | 1920 do { |
1677 GrColor color = GrRandomColor(random); | 1921 SkMatrix viewMatrix = GrTest::TestMatrix(random); |
1678 SkRect circle = GrTest::TestSquare(random); | 1922 GrColor color = GrRandomColor(random); |
1679 return new CircleBatch(color, viewMatrix, circle, GrTest::TestStrokeRec(rand
om)); | 1923 SkRect circle = GrTest::TestSquare(random); |
| 1924 SkPoint center = {circle.centerX(), circle.centerY()}; |
| 1925 SkScalar radius = circle.width() / 2.f; |
| 1926 SkStrokeRec stroke = GrTest::TestStrokeRec(random); |
| 1927 CircleBatch::ArcParams arcParamsTmp; |
| 1928 const CircleBatch::ArcParams* arcParams = nullptr; |
| 1929 if (random->nextBool()) { |
| 1930 arcParamsTmp.fStartAngleRadians = random->nextSScalar1() * SK_Scalar
PI * 2; |
| 1931 arcParamsTmp.fStartAngleRadians = random->nextSScalar1() * SK_Scalar
PI * 2 - .01f; |
| 1932 arcParams = &arcParamsTmp; |
| 1933 } |
| 1934 GrDrawBatch* batch = CircleBatch::Create(color, viewMatrix, center, radi
us, |
| 1935 GrStyle(stroke, nullptr), arcPa
rams); |
| 1936 if (batch) { |
| 1937 return batch; |
| 1938 } |
| 1939 } while (true); |
1680 } | 1940 } |
1681 | 1941 |
1682 DRAW_BATCH_TEST_DEFINE(EllipseBatch) { | 1942 DRAW_BATCH_TEST_DEFINE(EllipseBatch) { |
1683 SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random); | 1943 SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random); |
1684 GrColor color = GrRandomColor(random); | 1944 GrColor color = GrRandomColor(random); |
1685 SkRect ellipse = GrTest::TestSquare(random); | 1945 SkRect ellipse = GrTest::TestSquare(random); |
1686 return EllipseBatch::Create(color, viewMatrix, ellipse, GrTest::TestStrokeRe
c(random)); | 1946 return EllipseBatch::Create(color, viewMatrix, ellipse, GrTest::TestStrokeRe
c(random)); |
1687 } | 1947 } |
1688 | 1948 |
1689 DRAW_BATCH_TEST_DEFINE(DIEllipseBatch) { | 1949 DRAW_BATCH_TEST_DEFINE(DIEllipseBatch) { |
1690 SkMatrix viewMatrix = GrTest::TestMatrix(random); | 1950 SkMatrix viewMatrix = GrTest::TestMatrix(random); |
1691 GrColor color = GrRandomColor(random); | 1951 GrColor color = GrRandomColor(random); |
1692 SkRect ellipse = GrTest::TestSquare(random); | 1952 SkRect ellipse = GrTest::TestSquare(random); |
1693 return DIEllipseBatch::Create(color, viewMatrix, ellipse, GrTest::TestStroke
Rec(random)); | 1953 return DIEllipseBatch::Create(color, viewMatrix, ellipse, GrTest::TestStroke
Rec(random)); |
1694 } | 1954 } |
1695 | 1955 |
1696 DRAW_BATCH_TEST_DEFINE(RRectBatch) { | 1956 DRAW_BATCH_TEST_DEFINE(RRectBatch) { |
1697 SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random); | 1957 SkMatrix viewMatrix = GrTest::TestMatrixRectStaysRect(random); |
1698 GrColor color = GrRandomColor(random); | 1958 GrColor color = GrRandomColor(random); |
1699 const SkRRect& rrect = GrTest::TestRRectSimple(random); | 1959 const SkRRect& rrect = GrTest::TestRRectSimple(random); |
1700 return create_rrect_batch(color, viewMatrix, rrect, GrTest::TestStrokeRec(ra
ndom)); | 1960 return create_rrect_batch(color, viewMatrix, rrect, GrTest::TestStrokeRec(ra
ndom)); |
1701 } | 1961 } |
1702 | 1962 |
1703 #endif | 1963 #endif |
OLD | NEW |