blob: 3108b0472e96bfdd757a1301ff5eebe293445622 [file] [log] [blame]
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +00001
2/*
3 * Copyright 2012 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include "GrAAConvexPathRenderer.h"
10
11#include "GrContext.h"
12#include "GrDrawState.h"
bsalomon@google.comc26d94f2013-03-25 18:19:00 +000013#include "GrDrawTargetCaps.h"
egdaniel605dd0f2014-11-12 08:35:25 -080014#include "GrInvariantOutput.h"
joshualittb0a8a372014-09-23 09:50:21 -070015#include "GrProcessor.h"
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000016#include "GrPathUtils.h"
joshualittb0a8a372014-09-23 09:50:21 -070017#include "GrTBackendProcessorFactory.h"
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000018#include "SkString.h"
sugoi@google.com5f74cf82012-12-17 21:16:45 +000019#include "SkStrokeRec.h"
commit-bot@chromium.org933e65d2014-03-20 20:00:24 +000020#include "SkTraceEvent.h"
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000021
joshualitt47bb3822014-10-07 16:43:25 -070022#include "gl/builders/GrGLProgramBuilder.h"
joshualittb0a8a372014-09-23 09:50:21 -070023#include "gl/GrGLProcessor.h"
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +000024#include "gl/GrGLSL.h"
joshualitt249af152014-09-15 11:41:13 -070025#include "gl/GrGLGeometryProcessor.h"
bsalomon@google.com4647f902013-03-26 14:45:27 +000026
joshualittb0a8a372014-09-23 09:50:21 -070027#include "GrGeometryProcessor.h"
commit-bot@chromium.org234d4fb2013-09-30 19:55:49 +000028
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000029GrAAConvexPathRenderer::GrAAConvexPathRenderer() {
30}
31
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000032struct Segment {
33 enum {
bsalomon@google.com9b1517e2012-03-05 17:58:34 +000034 // These enum values are assumed in member functions below.
35 kLine = 0,
36 kQuad = 1,
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000037 } fType;
bsalomon@google.com9b1517e2012-03-05 17:58:34 +000038
bsalomon@google.com9aed1142012-01-30 14:28:39 +000039 // line uses one pt, quad uses 2 pts
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000040 SkPoint fPts[2];
bsalomon@google.com9aed1142012-01-30 14:28:39 +000041 // normal to edge ending at each pt
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000042 SkVector fNorms[2];
bsalomon@google.com9aed1142012-01-30 14:28:39 +000043 // is the corner where the previous segment meets this segment
44 // sharp. If so, fMid is a normalized bisector facing outward.
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000045 SkVector fMid;
bsalomon@google.com9aed1142012-01-30 14:28:39 +000046
47 int countPoints() {
bsalomon@google.com9b1517e2012-03-05 17:58:34 +000048 GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
49 return fType + 1;
bsalomon@google.com9aed1142012-01-30 14:28:39 +000050 }
51 const SkPoint& endPt() const {
bsalomon@google.com9b1517e2012-03-05 17:58:34 +000052 GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
53 return fPts[fType];
bsalomon@google.com9aed1142012-01-30 14:28:39 +000054 };
55 const SkPoint& endNorm() const {
bsalomon@google.com9b1517e2012-03-05 17:58:34 +000056 GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
57 return fNorms[fType];
bsalomon@google.com9aed1142012-01-30 14:28:39 +000058 };
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +000059};
60
61typedef SkTArray<Segment, true> SegmentArray;
62
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +000063static void center_of_mass(const SegmentArray& segments, SkPoint* c) {
bsalomon@google.com81712882012-11-01 17:12:34 +000064 SkScalar area = 0;
vandebo@chromium.org6390c722012-03-28 21:03:22 +000065 SkPoint center = {0, 0};
bsalomon@google.com9aed1142012-01-30 14:28:39 +000066 int count = segments.count();
vandebo@chromium.org6390c722012-03-28 21:03:22 +000067 SkPoint p0 = {0, 0};
bsalomon@google.com5b56d9e2012-02-23 19:18:37 +000068 if (count > 2) {
69 // We translate the polygon so that the first point is at the origin.
70 // This avoids some precision issues with small area polygons far away
71 // from the origin.
72 p0 = segments[0].endPt();
73 SkPoint pi;
74 SkPoint pj;
bsalomon@google.coma51ab842012-07-10 19:53:34 +000075 // the first and last iteration of the below loop would compute
bsalomon@google.com5b56d9e2012-02-23 19:18:37 +000076 // zeros since the starting / ending point is (0,0). So instead we start
77 // at i=1 and make the last iteration i=count-2.
78 pj = segments[1].endPt() - p0;
79 for (int i = 1; i < count - 1; ++i) {
80 pi = pj;
81 const SkPoint pj = segments[i + 1].endPt() - p0;
82
bsalomon@google.com81712882012-11-01 17:12:34 +000083 SkScalar t = SkScalarMul(pi.fX, pj.fY) - SkScalarMul(pj.fX, pi.fY);
bsalomon@google.com5b56d9e2012-02-23 19:18:37 +000084 area += t;
85 center.fX += (pi.fX + pj.fX) * t;
86 center.fY += (pi.fY + pj.fY) * t;
87
88 }
bsalomon@google.com9aed1142012-01-30 14:28:39 +000089 }
bsalomon@google.com278dc692012-02-15 16:52:51 +000090 // If the poly has no area then we instead return the average of
91 // its points.
bsalomon@google.com5b56d9e2012-02-23 19:18:37 +000092 if (SkScalarNearlyZero(area)) {
bsalomon@google.com278dc692012-02-15 16:52:51 +000093 SkPoint avg;
94 avg.set(0, 0);
95 for (int i = 0; i < count; ++i) {
96 const SkPoint& pt = segments[i].endPt();
97 avg.fX += pt.fX;
98 avg.fY += pt.fY;
99 }
100 SkScalar denom = SK_Scalar1 / count;
101 avg.scale(denom);
102 *c = avg;
103 } else {
104 area *= 3;
bsalomon@google.com81712882012-11-01 17:12:34 +0000105 area = SkScalarDiv(SK_Scalar1, area);
106 center.fX = SkScalarMul(center.fX, area);
107 center.fY = SkScalarMul(center.fY, area);
bsalomon@google.com5b56d9e2012-02-23 19:18:37 +0000108 // undo the translate of p0 to the origin.
109 *c = center + p0;
bsalomon@google.com278dc692012-02-15 16:52:51 +0000110 }
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000111 SkASSERT(!SkScalarIsNaN(c->fX) && !SkScalarIsNaN(c->fY));
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000112}
113
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +0000114static void compute_vectors(SegmentArray* segments,
115 SkPoint* fanPt,
116 SkPath::Direction dir,
117 int* vCount,
118 int* iCount) {
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000119 center_of_mass(*segments, fanPt);
120 int count = segments->count();
121
bsalomon@google.com278dc692012-02-15 16:52:51 +0000122 // Make the normals point towards the outside
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000123 SkPoint::Side normSide;
bsalomon@google.com278dc692012-02-15 16:52:51 +0000124 if (dir == SkPath::kCCW_Direction) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000125 normSide = SkPoint::kRight_Side;
bsalomon@google.com278dc692012-02-15 16:52:51 +0000126 } else {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000127 normSide = SkPoint::kLeft_Side;
bsalomon@google.com278dc692012-02-15 16:52:51 +0000128 }
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000129
130 *vCount = 0;
131 *iCount = 0;
132 // compute normals at all points
133 for (int a = 0; a < count; ++a) {
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000134 Segment& sega = (*segments)[a];
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000135 int b = (a + 1) % count;
136 Segment& segb = (*segments)[b];
137
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000138 const SkPoint* prevPt = &sega.endPt();
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000139 int n = segb.countPoints();
140 for (int p = 0; p < n; ++p) {
141 segb.fNorms[p] = segb.fPts[p] - *prevPt;
142 segb.fNorms[p].normalize();
143 segb.fNorms[p].setOrthog(segb.fNorms[p], normSide);
144 prevPt = &segb.fPts[p];
145 }
146 if (Segment::kLine == segb.fType) {
147 *vCount += 5;
148 *iCount += 9;
149 } else {
150 *vCount += 6;
151 *iCount += 12;
152 }
153 }
154
155 // compute mid-vectors where segments meet. TODO: Detect shallow corners
156 // and leave out the wedges and close gaps by stitching segments together.
157 for (int a = 0; a < count; ++a) {
158 const Segment& sega = (*segments)[a];
159 int b = (a + 1) % count;
160 Segment& segb = (*segments)[b];
161 segb.fMid = segb.fNorms[0] + sega.endNorm();
162 segb.fMid.normalize();
163 // corner wedges
164 *vCount += 4;
165 *iCount += 6;
166 }
167}
168
bsalomon@google.com9732f622012-01-31 15:19:21 +0000169struct DegenerateTestData {
170 DegenerateTestData() { fStage = kInitial; }
171 bool isDegenerate() const { return kNonDegenerate != fStage; }
172 enum {
173 kInitial,
174 kPoint,
175 kLine,
176 kNonDegenerate
177 } fStage;
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000178 SkPoint fFirstPoint;
179 SkVector fLineNormal;
bsalomon@google.com81712882012-11-01 17:12:34 +0000180 SkScalar fLineC;
bsalomon@google.com9732f622012-01-31 15:19:21 +0000181};
182
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +0000183static const SkScalar kClose = (SK_Scalar1 / 16);
184static const SkScalar kCloseSqd = SkScalarMul(kClose, kClose);
bsalomon@google.com9732f622012-01-31 15:19:21 +0000185
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000186static void update_degenerate_test(DegenerateTestData* data, const SkPoint& pt) {
bsalomon@google.com9732f622012-01-31 15:19:21 +0000187 switch (data->fStage) {
188 case DegenerateTestData::kInitial:
189 data->fFirstPoint = pt;
190 data->fStage = DegenerateTestData::kPoint;
191 break;
192 case DegenerateTestData::kPoint:
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +0000193 if (pt.distanceToSqd(data->fFirstPoint) > kCloseSqd) {
bsalomon@google.com9732f622012-01-31 15:19:21 +0000194 data->fLineNormal = pt - data->fFirstPoint;
195 data->fLineNormal.normalize();
196 data->fLineNormal.setOrthog(data->fLineNormal);
197 data->fLineC = -data->fLineNormal.dot(data->fFirstPoint);
198 data->fStage = DegenerateTestData::kLine;
199 }
200 break;
201 case DegenerateTestData::kLine:
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +0000202 if (SkScalarAbs(data->fLineNormal.dot(pt) + data->fLineC) > kClose) {
bsalomon@google.com9732f622012-01-31 15:19:21 +0000203 data->fStage = DegenerateTestData::kNonDegenerate;
204 }
205 case DegenerateTestData::kNonDegenerate:
206 break;
207 default:
commit-bot@chromium.org88cb22b2014-04-30 14:17:00 +0000208 SkFAIL("Unexpected degenerate test stage.");
bsalomon@google.com9732f622012-01-31 15:19:21 +0000209 }
210}
211
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +0000212static inline bool get_direction(const SkPath& path, const SkMatrix& m, SkPath::Direction* dir) {
bsalomon@google.coma51ab842012-07-10 19:53:34 +0000213 if (!path.cheapComputeDirection(dir)) {
214 return false;
215 }
bsalomon@google.comaf90f7f2012-03-05 20:50:10 +0000216 // check whether m reverses the orientation
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000217 SkASSERT(!m.hasPerspective());
bsalomon@google.com81712882012-11-01 17:12:34 +0000218 SkScalar det2x2 = SkScalarMul(m.get(SkMatrix::kMScaleX), m.get(SkMatrix::kMScaleY)) -
219 SkScalarMul(m.get(SkMatrix::kMSkewX), m.get(SkMatrix::kMSkewY));
bsalomon@google.comaf90f7f2012-03-05 20:50:10 +0000220 if (det2x2 < 0) {
bsalomon@google.com30c174b2012-11-13 14:36:42 +0000221 *dir = SkPath::OppositeDirection(*dir);
bsalomon@google.comaf90f7f2012-03-05 20:50:10 +0000222 }
bsalomon@google.coma51ab842012-07-10 19:53:34 +0000223 return true;
bsalomon@google.comaf90f7f2012-03-05 20:50:10 +0000224}
225
commit-bot@chromium.org106655e2013-09-03 21:28:55 +0000226static inline void add_line_to_segment(const SkPoint& pt,
227 SegmentArray* segments,
228 SkRect* devBounds) {
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +0000229 segments->push_back();
230 segments->back().fType = Segment::kLine;
231 segments->back().fPts[0] = pt;
commit-bot@chromium.org106655e2013-09-03 21:28:55 +0000232 devBounds->growToInclude(pt.fX, pt.fY);
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +0000233}
234
commit-bot@chromium.org4b7d6732013-10-21 16:41:00 +0000235#ifdef SK_DEBUG
commit-bot@chromium.org106655e2013-09-03 21:28:55 +0000236static inline bool contains_inclusive(const SkRect& rect, const SkPoint& p) {
237 return p.fX >= rect.fLeft && p.fX <= rect.fRight && p.fY >= rect.fTop && p.fY <= rect.fBottom;
238}
commit-bot@chromium.org4b7d6732013-10-21 16:41:00 +0000239#endif
240
commit-bot@chromium.org106655e2013-09-03 21:28:55 +0000241static inline void add_quad_segment(const SkPoint pts[3],
242 SegmentArray* segments,
243 SkRect* devBounds) {
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +0000244 if (pts[0].distanceToSqd(pts[1]) < kCloseSqd || pts[1].distanceToSqd(pts[2]) < kCloseSqd) {
245 if (pts[0] != pts[2]) {
commit-bot@chromium.org106655e2013-09-03 21:28:55 +0000246 add_line_to_segment(pts[2], segments, devBounds);
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +0000247 }
248 } else {
249 segments->push_back();
250 segments->back().fType = Segment::kQuad;
251 segments->back().fPts[0] = pts[1];
252 segments->back().fPts[1] = pts[2];
commit-bot@chromium.org106655e2013-09-03 21:28:55 +0000253 SkASSERT(contains_inclusive(*devBounds, pts[0]));
254 devBounds->growToInclude(pts + 1, 2);
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +0000255 }
256}
257
258static inline void add_cubic_segments(const SkPoint pts[4],
259 SkPath::Direction dir,
commit-bot@chromium.org106655e2013-09-03 21:28:55 +0000260 SegmentArray* segments,
261 SkRect* devBounds) {
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +0000262 SkSTArray<15, SkPoint, true> quads;
263 GrPathUtils::convertCubicToQuads(pts, SK_Scalar1, true, dir, &quads);
264 int count = quads.count();
265 for (int q = 0; q < count; q += 3) {
commit-bot@chromium.org106655e2013-09-03 21:28:55 +0000266 add_quad_segment(&quads[q], segments, devBounds);
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +0000267 }
268}
269
270static bool get_segments(const SkPath& path,
271 const SkMatrix& m,
272 SegmentArray* segments,
273 SkPoint* fanPt,
274 int* vCount,
commit-bot@chromium.org106655e2013-09-03 21:28:55 +0000275 int* iCount,
276 SkRect* devBounds) {
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000277 SkPath::Iter iter(path, true);
bsalomon@google.com30c174b2012-11-13 14:36:42 +0000278 // This renderer over-emphasizes very thin path regions. We use the distance
bsalomon@google.com5cc90d12012-01-17 16:28:34 +0000279 // to the path from the sample to compute coverage. Every pixel intersected
280 // by the path will be hit and the maximum distance is sqrt(2)/2. We don't
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000281 // notice that the sample may be close to a very thin area of the path and
bsalomon@google.com5cc90d12012-01-17 16:28:34 +0000282 // thus should be very light. This is particularly egregious for degenerate
283 // line paths. We detect paths that are very close to a line (zero area) and
284 // draw nothing.
bsalomon@google.com9732f622012-01-31 15:19:21 +0000285 DegenerateTestData degenerateData;
bsalomon@google.coma51ab842012-07-10 19:53:34 +0000286 SkPath::Direction dir;
287 // get_direction can fail for some degenerate paths.
288 if (!get_direction(path, m, &dir)) {
289 return false;
290 }
bsalomon@google.com9732f622012-01-31 15:19:21 +0000291
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000292 for (;;) {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000293 SkPoint pts[4];
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000294 SkPath::Verb verb = iter.next(pts);
295 switch (verb) {
296 case SkPath::kMove_Verb:
bsalomon@google.com1a38d552012-03-15 14:40:46 +0000297 m.mapPoints(pts, 1);
bsalomon@google.com9732f622012-01-31 15:19:21 +0000298 update_degenerate_test(&degenerateData, pts[0]);
commit-bot@chromium.org106655e2013-09-03 21:28:55 +0000299 devBounds->set(pts->fX, pts->fY, pts->fX, pts->fY);
bsalomon@google.com9732f622012-01-31 15:19:21 +0000300 break;
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000301 case SkPath::kLine_Verb: {
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +0000302 m.mapPoints(&pts[1], 1);
bsalomon@google.com1a38d552012-03-15 14:40:46 +0000303 update_degenerate_test(&degenerateData, pts[1]);
commit-bot@chromium.org106655e2013-09-03 21:28:55 +0000304 add_line_to_segment(pts[1], segments, devBounds);
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000305 break;
306 }
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000307 case SkPath::kQuad_Verb:
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +0000308 m.mapPoints(pts, 3);
bsalomon@google.com9732f622012-01-31 15:19:21 +0000309 update_degenerate_test(&degenerateData, pts[1]);
310 update_degenerate_test(&degenerateData, pts[2]);
commit-bot@chromium.org106655e2013-09-03 21:28:55 +0000311 add_quad_segment(pts, segments, devBounds);
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000312 break;
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000313 case SkPath::kCubic_Verb: {
bsalomon@google.com1a38d552012-03-15 14:40:46 +0000314 m.mapPoints(pts, 4);
bsalomon@google.com9732f622012-01-31 15:19:21 +0000315 update_degenerate_test(&degenerateData, pts[1]);
316 update_degenerate_test(&degenerateData, pts[2]);
317 update_degenerate_test(&degenerateData, pts[3]);
commit-bot@chromium.org106655e2013-09-03 21:28:55 +0000318 add_cubic_segments(pts, dir, segments, devBounds);
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000319 break;
320 };
bsalomon@google.com94b284d2013-05-10 17:14:06 +0000321 case SkPath::kDone_Verb:
bsalomon@google.com9732f622012-01-31 15:19:21 +0000322 if (degenerateData.isDegenerate()) {
323 return false;
324 } else {
bsalomon@google.com278dc692012-02-15 16:52:51 +0000325 compute_vectors(segments, fanPt, dir, vCount, iCount);
bsalomon@google.com9732f622012-01-31 15:19:21 +0000326 return true;
327 }
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000328 default:
329 break;
330 }
331 }
332}
333
334struct QuadVertex {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000335 SkPoint fPos;
336 SkPoint fUV;
bsalomon@google.com81712882012-11-01 17:12:34 +0000337 SkScalar fD0;
338 SkScalar fD1;
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000339};
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000340
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000341struct Draw {
342 Draw() : fVertexCnt(0), fIndexCnt(0) {}
343 int fVertexCnt;
344 int fIndexCnt;
345};
346
347typedef SkTArray<Draw, true> DrawArray;
348
commit-bot@chromium.orgfdfbb9d2013-08-15 18:16:27 +0000349static void create_vertices(const SegmentArray& segments,
350 const SkPoint& fanPt,
351 DrawArray* draws,
352 QuadVertex* verts,
353 uint16_t* idxs) {
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000354 Draw* draw = &draws->push_back();
355 // alias just to make vert/index assignments easier to read.
356 int* v = &draw->fVertexCnt;
357 int* i = &draw->fIndexCnt;
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000358
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000359 int count = segments.count();
360 for (int a = 0; a < count; ++a) {
361 const Segment& sega = segments[a];
362 int b = (a + 1) % count;
363 const Segment& segb = segments[b];
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000364
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000365 // Check whether adding the verts for this segment to the current draw would cause index
366 // values to overflow.
367 int vCount = 4;
368 if (Segment::kLine == segb.fType) {
369 vCount += 5;
370 } else {
371 vCount += 6;
372 }
373 if (draw->fVertexCnt + vCount > (1 << 16)) {
374 verts += *v;
375 idxs += *i;
376 draw = &draws->push_back();
377 v = &draw->fVertexCnt;
378 i = &draw->fIndexCnt;
379 }
380
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000381 // FIXME: These tris are inset in the 1 unit arc around the corner
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000382 verts[*v + 0].fPos = sega.endPt();
383 verts[*v + 1].fPos = verts[*v + 0].fPos + sega.endNorm();
384 verts[*v + 2].fPos = verts[*v + 0].fPos + segb.fMid;
385 verts[*v + 3].fPos = verts[*v + 0].fPos + segb.fNorms[0];
386 verts[*v + 0].fUV.set(0,0);
387 verts[*v + 1].fUV.set(0,-SK_Scalar1);
388 verts[*v + 2].fUV.set(0,-SK_Scalar1);
389 verts[*v + 3].fUV.set(0,-SK_Scalar1);
390 verts[*v + 0].fD0 = verts[*v + 0].fD1 = -SK_Scalar1;
391 verts[*v + 1].fD0 = verts[*v + 1].fD1 = -SK_Scalar1;
392 verts[*v + 2].fD0 = verts[*v + 2].fD1 = -SK_Scalar1;
393 verts[*v + 3].fD0 = verts[*v + 3].fD1 = -SK_Scalar1;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000394
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000395 idxs[*i + 0] = *v + 0;
396 idxs[*i + 1] = *v + 2;
397 idxs[*i + 2] = *v + 1;
398 idxs[*i + 3] = *v + 0;
399 idxs[*i + 4] = *v + 3;
400 idxs[*i + 5] = *v + 2;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000401
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000402 *v += 4;
403 *i += 6;
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000404
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000405 if (Segment::kLine == segb.fType) {
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000406 verts[*v + 0].fPos = fanPt;
407 verts[*v + 1].fPos = sega.endPt();
408 verts[*v + 2].fPos = segb.fPts[0];
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000409
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000410 verts[*v + 3].fPos = verts[*v + 1].fPos + segb.fNorms[0];
411 verts[*v + 4].fPos = verts[*v + 2].fPos + segb.fNorms[0];
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000412
413 // we draw the line edge as a degenerate quad (u is 0, v is the
414 // signed distance to the edge)
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000415 SkScalar dist = fanPt.distanceToLineBetween(verts[*v + 1].fPos,
416 verts[*v + 2].fPos);
417 verts[*v + 0].fUV.set(0, dist);
418 verts[*v + 1].fUV.set(0, 0);
419 verts[*v + 2].fUV.set(0, 0);
420 verts[*v + 3].fUV.set(0, -SK_Scalar1);
421 verts[*v + 4].fUV.set(0, -SK_Scalar1);
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000422
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000423 verts[*v + 0].fD0 = verts[*v + 0].fD1 = -SK_Scalar1;
424 verts[*v + 1].fD0 = verts[*v + 1].fD1 = -SK_Scalar1;
425 verts[*v + 2].fD0 = verts[*v + 2].fD1 = -SK_Scalar1;
426 verts[*v + 3].fD0 = verts[*v + 3].fD1 = -SK_Scalar1;
427 verts[*v + 4].fD0 = verts[*v + 4].fD1 = -SK_Scalar1;
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000428
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000429 idxs[*i + 0] = *v + 0;
430 idxs[*i + 1] = *v + 2;
431 idxs[*i + 2] = *v + 1;
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000432
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000433 idxs[*i + 3] = *v + 3;
434 idxs[*i + 4] = *v + 1;
435 idxs[*i + 5] = *v + 2;
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000436
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000437 idxs[*i + 6] = *v + 4;
438 idxs[*i + 7] = *v + 3;
439 idxs[*i + 8] = *v + 2;
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000440
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000441 *v += 5;
442 *i += 9;
bsalomon@google.com06809612012-01-21 15:03:39 +0000443 } else {
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000444 SkPoint qpts[] = {sega.endPt(), segb.fPts[0], segb.fPts[1]};
bsalomon@google.com495e2102012-01-21 14:48:36 +0000445
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000446 SkVector midVec = segb.fNorms[0] + segb.fNorms[1];
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000447 midVec.normalize();
bsalomon@google.com06809612012-01-21 15:03:39 +0000448
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000449 verts[*v + 0].fPos = fanPt;
450 verts[*v + 1].fPos = qpts[0];
451 verts[*v + 2].fPos = qpts[2];
452 verts[*v + 3].fPos = qpts[0] + segb.fNorms[0];
453 verts[*v + 4].fPos = qpts[2] + segb.fNorms[1];
454 verts[*v + 5].fPos = qpts[1] + midVec;
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000455
bsalomon@google.com81712882012-11-01 17:12:34 +0000456 SkScalar c = segb.fNorms[0].dot(qpts[0]);
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000457 verts[*v + 0].fD0 = -segb.fNorms[0].dot(fanPt) + c;
458 verts[*v + 1].fD0 = 0.f;
459 verts[*v + 2].fD0 = -segb.fNorms[0].dot(qpts[2]) + c;
460 verts[*v + 3].fD0 = -SK_ScalarMax/100;
461 verts[*v + 4].fD0 = -SK_ScalarMax/100;
462 verts[*v + 5].fD0 = -SK_ScalarMax/100;
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000463
464 c = segb.fNorms[1].dot(qpts[2]);
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000465 verts[*v + 0].fD1 = -segb.fNorms[1].dot(fanPt) + c;
466 verts[*v + 1].fD1 = -segb.fNorms[1].dot(qpts[0]) + c;
467 verts[*v + 2].fD1 = 0.f;
468 verts[*v + 3].fD1 = -SK_ScalarMax/100;
469 verts[*v + 4].fD1 = -SK_ScalarMax/100;
470 verts[*v + 5].fD1 = -SK_ScalarMax/100;
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000471
bsalomon@google.com19713172012-03-15 13:51:08 +0000472 GrPathUtils::QuadUVMatrix toUV(qpts);
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000473 toUV.apply<6, sizeof(QuadVertex), sizeof(SkPoint)>(verts + *v);
bsalomon@google.com06809612012-01-21 15:03:39 +0000474
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000475 idxs[*i + 0] = *v + 3;
476 idxs[*i + 1] = *v + 1;
477 idxs[*i + 2] = *v + 2;
478 idxs[*i + 3] = *v + 4;
479 idxs[*i + 4] = *v + 3;
480 idxs[*i + 5] = *v + 2;
bsalomon@google.com06809612012-01-21 15:03:39 +0000481
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000482 idxs[*i + 6] = *v + 5;
483 idxs[*i + 7] = *v + 3;
484 idxs[*i + 8] = *v + 4;
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000485
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000486 idxs[*i + 9] = *v + 0;
487 idxs[*i + 10] = *v + 2;
488 idxs[*i + 11] = *v + 1;
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000489
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000490 *v += 6;
491 *i += 12;
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000492 }
493 }
494}
495
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000496///////////////////////////////////////////////////////////////////////////////
497
498/*
499 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first
500 * two components of the vertex attribute. Coverage is based on signed
501 * distance with negative being inside, positive outside. The edge is specified in
502 * window space (y-down). If either the third or fourth component of the interpolated
503 * vertex coord is > 0 then the pixel is considered outside the edge. This is used to
skia.committer@gmail.com041e2db2013-04-03 07:01:14 +0000504 * attempt to trim to a portion of the infinite quad.
505 * Requires shader derivative instruction support.
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000506 */
507
joshualitt249af152014-09-15 11:41:13 -0700508class QuadEdgeEffect : public GrGeometryProcessor {
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000509public:
510
joshualittb0a8a372014-09-23 09:50:21 -0700511 static GrGeometryProcessor* Create() {
bsalomon98b33eb2014-10-15 11:05:26 -0700512 GR_CREATE_STATIC_PROCESSOR(gQuadEdgeEffect, QuadEdgeEffect, ());
bsalomon@google.comd42aca32013-04-23 15:37:27 +0000513 gQuadEdgeEffect->ref();
514 return gQuadEdgeEffect;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000515 }
516
517 virtual ~QuadEdgeEffect() {}
518
519 static const char* Name() { return "QuadEdge"; }
520
joshualitt2dd1ae02014-12-03 06:24:10 -0800521 const GrAttribute* inPosition() const { return fInPosition; }
522 const GrAttribute* inQuadEdge() const { return fInQuadEdge; }
joshualitt249af152014-09-15 11:41:13 -0700523
joshualittb0a8a372014-09-23 09:50:21 -0700524 virtual const GrBackendGeometryProcessorFactory& getFactory() const SK_OVERRIDE {
525 return GrTBackendGeometryProcessorFactory<QuadEdgeEffect>::getInstance();
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000526 }
527
joshualittb0a8a372014-09-23 09:50:21 -0700528 class GLProcessor : public GrGLGeometryProcessor {
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000529 public:
joshualitt87f48d92014-12-04 10:41:40 -0800530 GLProcessor(const GrBackendProcessorFactory& factory,
531 const GrGeometryProcessor&,
532 const GrBatchTracker&)
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000533 : INHERITED (factory) {}
534
joshualittc369e7c2014-10-22 10:56:26 -0700535 virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
joshualitt2dd1ae02014-12-03 06:24:10 -0800536 const QuadEdgeEffect& qe = args.fGP.cast<QuadEdgeEffect>();
537 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
538
joshualitt74077b92014-10-24 11:26:03 -0700539 GrGLVertToFrag v(kVec4f_GrSLType);
540 args.fPB->addVarying("QuadEdge", &v);
joshualitt2dd1ae02014-12-03 06:24:10 -0800541 vsBuilder->codeAppendf("%s = %s;", v.vsOut(), qe.inQuadEdge()->fName);
542
543 // setup coord outputs
544 vsBuilder->codeAppendf("%s = %s;", vsBuilder->positionCoords(), qe.inPosition()->fName);
545 vsBuilder->codeAppendf("%s = %s;", vsBuilder->localCoords(), qe.inPosition()->fName);
546
547 // setup position varying
548 vsBuilder->codeAppendf("%s = %s * vec3(%s, 1);", vsBuilder->glPosition(),
549 vsBuilder->uViewM(), qe.inPosition()->fName);
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000550
joshualittc369e7c2014-10-22 10:56:26 -0700551 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -0700552
553 SkAssertResult(fsBuilder->enableFeature(
554 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
joshualitt74077b92014-10-24 11:26:03 -0700555 fsBuilder->codeAppendf("float edgeAlpha;");
joshualitt30ba4362014-08-21 20:18:45 -0700556
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000557 // keep the derivative instructions outside the conditional
joshualitt74077b92014-10-24 11:26:03 -0700558 fsBuilder->codeAppendf("vec2 duvdx = dFdx(%s.xy);", v.fsIn());
559 fsBuilder->codeAppendf("vec2 duvdy = dFdy(%s.xy);", v.fsIn());
560 fsBuilder->codeAppendf("if (%s.z > 0.0 && %s.w > 0.0) {", v.fsIn(), v.fsIn());
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000561 // today we know z and w are in device space. We could use derivatives
joshualitt74077b92014-10-24 11:26:03 -0700562 fsBuilder->codeAppendf("edgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);", v.fsIn(),
563 v.fsIn());
564 fsBuilder->codeAppendf ("} else {");
565 fsBuilder->codeAppendf("vec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.y,"
566 " 2.0*%s.x*duvdy.x - duvdy.y);",
567 v.fsIn(), v.fsIn());
568 fsBuilder->codeAppendf("edgeAlpha = (%s.x*%s.x - %s.y);", v.fsIn(), v.fsIn(),
569 v.fsIn());
570 fsBuilder->codeAppendf("edgeAlpha = "
571 "clamp(0.5 - edgeAlpha / length(gF), 0.0, 1.0);}");
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000572
joshualitt2dd1ae02014-12-03 06:24:10 -0800573 fsBuilder->codeAppendf("%s = vec4(edgeAlpha);", args.fOutputCoverage);
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000574 }
575
joshualitt87f48d92014-12-04 10:41:40 -0800576 static inline void GenKey(const GrGeometryProcessor&,
577 const GrBatchTracker&,
578 const GrGLCaps&,
579 GrProcessorKeyBuilder*) {}
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000580
joshualitt87f48d92014-12-04 10:41:40 -0800581 virtual void setData(const GrGLProgramDataManager&,
582 const GrGeometryProcessor&,
583 const GrBatchTracker&) SK_OVERRIDE {}
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000584
585 private:
joshualitt249af152014-09-15 11:41:13 -0700586 typedef GrGLGeometryProcessor INHERITED;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000587 };
skia.committer@gmail.com041e2db2013-04-03 07:01:14 +0000588
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000589private:
joshualitt2dd1ae02014-12-03 06:24:10 -0800590 QuadEdgeEffect() {
591 fInPosition = &this->addVertexAttrib(GrAttribute("inPosition", kVec2f_GrVertexAttribType));
592 fInQuadEdge = &this->addVertexAttrib(GrAttribute("inQuadEdge", kVec4f_GrVertexAttribType));
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000593 }
594
bsalomon0e08fc12014-10-15 08:19:04 -0700595 virtual bool onIsEqual(const GrGeometryProcessor& other) const SK_OVERRIDE {
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000596 return true;
597 }
598
egdaniel605dd0f2014-11-12 08:35:25 -0800599 virtual void onComputeInvariantOutput(GrInvariantOutput* inout) const SK_OVERRIDE {
egdanielccb2e382014-10-13 12:53:46 -0700600 inout->mulByUnknownAlpha();
egdaniel1a8ecdf2014-10-03 06:24:12 -0700601 }
602
joshualitt2dd1ae02014-12-03 06:24:10 -0800603 const GrAttribute* fInPosition;
604 const GrAttribute* fInQuadEdge;
joshualitt249af152014-09-15 11:41:13 -0700605
joshualittb0a8a372014-09-23 09:50:21 -0700606 GR_DECLARE_GEOMETRY_PROCESSOR_TEST;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000607
joshualittb0a8a372014-09-23 09:50:21 -0700608 typedef GrFragmentProcessor INHERITED;
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000609};
610
joshualittb0a8a372014-09-23 09:50:21 -0700611GR_DEFINE_GEOMETRY_PROCESSOR_TEST(QuadEdgeEffect);
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000612
joshualittb0a8a372014-09-23 09:50:21 -0700613GrGeometryProcessor* QuadEdgeEffect::TestCreate(SkRandom* random,
614 GrContext*,
615 const GrDrawTargetCaps& caps,
616 GrTexture*[]) {
commit-bot@chromium.org90c240a2013-04-02 17:57:21 +0000617 // Doesn't work without derivative instructions.
618 return caps.shaderDerivativeSupport() ? QuadEdgeEffect::Create() : NULL;
619}
620
621///////////////////////////////////////////////////////////////////////////////
622
joshualitt9853cce2014-11-17 14:22:48 -0800623bool GrAAConvexPathRenderer::canDrawPath(const GrDrawTarget* target,
624 const GrDrawState*,
625 const SkPath& path,
robertphillips@google.come79f3202014-02-11 16:30:21 +0000626 const SkStrokeRec& stroke,
robertphillips@google.comfa662942012-05-17 12:20:22 +0000627 bool antiAlias) const {
bsalomon@google.combcce8922013-03-25 15:38:39 +0000628 return (target->caps()->shaderDerivativeSupport() && antiAlias &&
robertphillips@google.come79f3202014-02-11 16:30:21 +0000629 stroke.isFillStyle() && !path.isInverseFillType() && path.isConvex());
robertphillips@google.comfa662942012-05-17 12:20:22 +0000630}
631
joshualitt9853cce2014-11-17 14:22:48 -0800632bool GrAAConvexPathRenderer::onDrawPath(GrDrawTarget* target,
633 GrDrawState* drawState,
634 const SkPath& origPath,
robertphillips@google.come79f3202014-02-11 16:30:21 +0000635 const SkStrokeRec&,
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000636 bool antiAlias) {
637
robertphillips@google.come79f3202014-02-11 16:30:21 +0000638 const SkPath* path = &origPath;
bsalomon@google.comaf90f7f2012-03-05 20:50:10 +0000639 if (path->isEmpty()) {
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000640 return true;
641 }
bsalomon@google.com4647f902013-03-26 14:45:27 +0000642
joshualitt9853cce2014-11-17 14:22:48 -0800643 SkMatrix viewMatrix = drawState->getViewMatrix();
644 GrDrawState::AutoViewMatrixRestore avmr;
645 if (!avmr.setIdentity(drawState)) {
bsalomon@google.come3d32162012-07-20 13:37:06 +0000646 return false;
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000647 }
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000648
bsalomon@google.comaf90f7f2012-03-05 20:50:10 +0000649 // We use the fact that SkPath::transform path does subdivision based on
650 // perspective. Otherwise, we apply the view matrix when copying to the
651 // segment representation.
652 SkPath tmpPath;
bsalomon@google.com137f1342013-05-29 21:27:53 +0000653 if (viewMatrix.hasPerspective()) {
robertphillips@google.come79f3202014-02-11 16:30:21 +0000654 origPath.transform(viewMatrix, &tmpPath);
bsalomon@google.comaf90f7f2012-03-05 20:50:10 +0000655 path = &tmpPath;
bsalomon@google.com137f1342013-05-29 21:27:53 +0000656 viewMatrix = SkMatrix::I();
bsalomon@google.comaf90f7f2012-03-05 20:50:10 +0000657 }
658
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000659 QuadVertex *verts;
660 uint16_t* idxs;
661
bsalomon@google.com06809612012-01-21 15:03:39 +0000662 int vCount;
663 int iCount;
bsalomon@google.com68a5b262012-03-05 18:24:07 +0000664 enum {
665 kPreallocSegmentCnt = 512 / sizeof(Segment),
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000666 kPreallocDrawCnt = 4,
bsalomon@google.com68a5b262012-03-05 18:24:07 +0000667 };
668 SkSTArray<kPreallocSegmentCnt, Segment, true> segments;
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000669 SkPoint fanPt;
bsalomon@google.comaf90f7f2012-03-05 20:50:10 +0000670
commit-bot@chromium.org106655e2013-09-03 21:28:55 +0000671 // We can't simply use the path bounds because we may degenerate cubics to quads which produces
672 // new control points outside the original convex hull.
673 SkRect devBounds;
674 if (!get_segments(*path, viewMatrix, &segments, &fanPt, &vCount, &iCount, &devBounds)) {
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000675 return false;
bsalomon@google.com9aed1142012-01-30 14:28:39 +0000676 }
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000677
commit-bot@chromium.org106655e2013-09-03 21:28:55 +0000678 // Our computed verts should all be within one pixel of the segment control points.
679 devBounds.outset(SK_Scalar1, SK_Scalar1);
680
joshualittb0a8a372014-09-23 09:50:21 -0700681 GrGeometryProcessor* quadProcessor = QuadEdgeEffect::Create();
682 drawState->setGeometryProcessor(quadProcessor)->unref();
bsalomon@google.com4647f902013-03-26 14:45:27 +0000683
joshualitt2dd1ae02014-12-03 06:24:10 -0800684 GrDrawTarget::AutoReleaseGeometry arg(target, vCount, quadProcessor->getVertexStride(), iCount);
685 SkASSERT(quadProcessor->getVertexStride() == sizeof(QuadVertex));
bsalomon@google.comb3729422012-03-07 19:13:28 +0000686 if (!arg.succeeded()) {
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000687 return false;
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000688 }
bsalomon@google.comb3729422012-03-07 19:13:28 +0000689 verts = reinterpret_cast<QuadVertex*>(arg.vertices());
690 idxs = reinterpret_cast<uint16_t*>(arg.indices());
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000691
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000692 SkSTArray<kPreallocDrawCnt, Draw, true> draws;
693 create_vertices(segments, fanPt, &draws, verts, idxs);
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000694
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000695 // Check devBounds
commit-bot@chromium.org515dcd32013-08-28 14:17:03 +0000696#ifdef SK_DEBUG
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000697 SkRect tolDevBounds = devBounds;
698 tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000);
699 SkRect actualBounds;
700 actualBounds.set(verts[0].fPos, verts[1].fPos);
701 for (int i = 2; i < vCount; ++i) {
702 actualBounds.growToInclude(verts[i].fPos.fX, verts[i].fPos.fY);
703 }
tfarina@chromium.orgf6de4752013-08-17 00:02:59 +0000704 SkASSERT(tolDevBounds.contains(actualBounds));
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000705#endif
706
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000707 int vOffset = 0;
708 for (int i = 0; i < draws.count(); ++i) {
709 const Draw& draw = draws[i];
joshualitt9853cce2014-11-17 14:22:48 -0800710 target->drawIndexed(drawState,
711 kTriangles_GrPrimitiveType,
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000712 vOffset, // start vertex
713 0, // start index
714 draw.fVertexCnt,
bsalomon@google.com1dd9baa2013-05-20 16:49:06 +0000715 draw.fIndexCnt,
716 &devBounds);
bsalomon@google.com7d9ffc82013-05-14 14:20:28 +0000717 vOffset += draw.fVertexCnt;
718 }
bsalomon@google.coma8347462012-10-08 18:59:39 +0000719
bsalomon@google.comc2099d22012-03-02 21:26:50 +0000720 return true;
bsalomon@google.com69cc6ad2012-01-17 14:25:10 +0000721}