| OLD | NEW |
| 1 | 1 |
| 2 /* | 2 /* |
| 3 * Copyright 2012 Google Inc. | 3 * Copyright 2012 Google Inc. |
| 4 * | 4 * |
| 5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
| 6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 #include "GrAAConvexPathRenderer.h" | 9 #include "GrAAConvexPathRenderer.h" |
| 10 | 10 |
| 11 #include "GrContext.h" | 11 #include "GrContext.h" |
| 12 #include "GrDrawState.h" | 12 #include "GrDrawState.h" |
| 13 #include "GrDrawTargetCaps.h" | 13 #include "GrDrawTargetCaps.h" |
| 14 #include "GrEffect.h" | 14 #include "GrEffect.h" |
| 15 #include "GrPathUtils.h" | 15 #include "GrPathUtils.h" |
| 16 #include "GrTBackendEffectFactory.h" | 16 #include "GrTBackendEffectFactory.h" |
| 17 #include "SkString.h" | 17 #include "SkString.h" |
| 18 #include "SkStrokeRec.h" | 18 #include "SkStrokeRec.h" |
| 19 #include "SkTrace.h" | 19 #include "SkTrace.h" |
| 20 | 20 |
| 21 #include "gl/GrGLEffect.h" | 21 #include "gl/GrGLEffect.h" |
| 22 #include "gl/GrGLSL.h" | 22 #include "gl/GrGLSL.h" |
| 23 | 23 |
| 24 GrAAConvexPathRenderer::GrAAConvexPathRenderer() { | 24 GrAAConvexPathRenderer::GrAAConvexPathRenderer() { |
| 25 } | 25 } |
| 26 | 26 |
| 27 namespace { | |
| 28 | |
| 29 struct Segment { | 27 struct Segment { |
| 30 enum { | 28 enum { |
| 31 // These enum values are assumed in member functions below. | 29 // These enum values are assumed in member functions below. |
| 32 kLine = 0, | 30 kLine = 0, |
| 33 kQuad = 1, | 31 kQuad = 1, |
| 34 } fType; | 32 } fType; |
| 35 | 33 |
| 36 // line uses one pt, quad uses 2 pts | 34 // line uses one pt, quad uses 2 pts |
| 37 GrPoint fPts[2]; | 35 GrPoint fPts[2]; |
| 38 // normal to edge ending at each pt | 36 // normal to edge ending at each pt |
| (...skipping 11 matching lines...) Expand all Loading... |
| 50 return fPts[fType]; | 48 return fPts[fType]; |
| 51 }; | 49 }; |
| 52 const SkPoint& endNorm() const { | 50 const SkPoint& endNorm() const { |
| 53 GR_STATIC_ASSERT(0 == kLine && 1 == kQuad); | 51 GR_STATIC_ASSERT(0 == kLine && 1 == kQuad); |
| 54 return fNorms[fType]; | 52 return fNorms[fType]; |
| 55 }; | 53 }; |
| 56 }; | 54 }; |
| 57 | 55 |
| 58 typedef SkTArray<Segment, true> SegmentArray; | 56 typedef SkTArray<Segment, true> SegmentArray; |
| 59 | 57 |
| 60 void center_of_mass(const SegmentArray& segments, SkPoint* c) { | 58 static void center_of_mass(const SegmentArray& segments, SkPoint* c) { |
| 61 SkScalar area = 0; | 59 SkScalar area = 0; |
| 62 SkPoint center = {0, 0}; | 60 SkPoint center = {0, 0}; |
| 63 int count = segments.count(); | 61 int count = segments.count(); |
| 64 SkPoint p0 = {0, 0}; | 62 SkPoint p0 = {0, 0}; |
| 65 if (count > 2) { | 63 if (count > 2) { |
| 66 // We translate the polygon so that the first point is at the origin. | 64 // We translate the polygon so that the first point is at the origin. |
| 67 // This avoids some precision issues with small area polygons far away | 65 // This avoids some precision issues with small area polygons far away |
| 68 // from the origin. | 66 // from the origin. |
| 69 p0 = segments[0].endPt(); | 67 p0 = segments[0].endPt(); |
| 70 SkPoint pi; | 68 SkPoint pi; |
| (...skipping 30 matching lines...) Expand all Loading... |
| 101 area *= 3; | 99 area *= 3; |
| 102 area = SkScalarDiv(SK_Scalar1, area); | 100 area = SkScalarDiv(SK_Scalar1, area); |
| 103 center.fX = SkScalarMul(center.fX, area); | 101 center.fX = SkScalarMul(center.fX, area); |
| 104 center.fY = SkScalarMul(center.fY, area); | 102 center.fY = SkScalarMul(center.fY, area); |
| 105 // undo the translate of p0 to the origin. | 103 // undo the translate of p0 to the origin. |
| 106 *c = center + p0; | 104 *c = center + p0; |
| 107 } | 105 } |
| 108 GrAssert(!SkScalarIsNaN(c->fX) && !SkScalarIsNaN(c->fY)); | 106 GrAssert(!SkScalarIsNaN(c->fX) && !SkScalarIsNaN(c->fY)); |
| 109 } | 107 } |
| 110 | 108 |
| 111 void compute_vectors(SegmentArray* segments, | 109 static void compute_vectors(SegmentArray* segments, |
| 112 SkPoint* fanPt, | 110 SkPoint* fanPt, |
| 113 SkPath::Direction dir, | 111 SkPath::Direction dir, |
| 114 int* vCount, | 112 int* vCount, |
| 115 int* iCount) { | 113 int* iCount) { |
| 116 center_of_mass(*segments, fanPt); | 114 center_of_mass(*segments, fanPt); |
| 117 int count = segments->count(); | 115 int count = segments->count(); |
| 118 | 116 |
| 119 // Make the normals point towards the outside | 117 // Make the normals point towards the outside |
| 120 GrPoint::Side normSide; | 118 GrPoint::Side normSide; |
| 121 if (dir == SkPath::kCCW_Direction) { | 119 if (dir == SkPath::kCCW_Direction) { |
| 122 normSide = GrPoint::kRight_Side; | 120 normSide = GrPoint::kRight_Side; |
| 123 } else { | 121 } else { |
| 124 normSide = GrPoint::kLeft_Side; | 122 normSide = GrPoint::kLeft_Side; |
| 125 } | 123 } |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 kInitial, | 168 kInitial, |
| 171 kPoint, | 169 kPoint, |
| 172 kLine, | 170 kLine, |
| 173 kNonDegenerate | 171 kNonDegenerate |
| 174 } fStage; | 172 } fStage; |
| 175 GrPoint fFirstPoint; | 173 GrPoint fFirstPoint; |
| 176 GrVec fLineNormal; | 174 GrVec fLineNormal; |
| 177 SkScalar fLineC; | 175 SkScalar fLineC; |
| 178 }; | 176 }; |
| 179 | 177 |
| 180 void update_degenerate_test(DegenerateTestData* data, const GrPoint& pt) { | 178 static const SkScalar kClose = (SK_Scalar1 / 16); |
| 181 static const SkScalar TOL = (SK_Scalar1 / 16); | 179 static const SkScalar kCloseSqd = SkScalarMul(kClose, kClose); |
| 182 static const SkScalar TOL_SQD = SkScalarMul(TOL, TOL); | |
| 183 | 180 |
| 181 static void update_degenerate_test(DegenerateTestData* data, const GrPoint& pt)
{ |
| 184 switch (data->fStage) { | 182 switch (data->fStage) { |
| 185 case DegenerateTestData::kInitial: | 183 case DegenerateTestData::kInitial: |
| 186 data->fFirstPoint = pt; | 184 data->fFirstPoint = pt; |
| 187 data->fStage = DegenerateTestData::kPoint; | 185 data->fStage = DegenerateTestData::kPoint; |
| 188 break; | 186 break; |
| 189 case DegenerateTestData::kPoint: | 187 case DegenerateTestData::kPoint: |
| 190 if (pt.distanceToSqd(data->fFirstPoint) > TOL_SQD) { | 188 if (pt.distanceToSqd(data->fFirstPoint) > kCloseSqd) { |
| 191 data->fLineNormal = pt - data->fFirstPoint; | 189 data->fLineNormal = pt - data->fFirstPoint; |
| 192 data->fLineNormal.normalize(); | 190 data->fLineNormal.normalize(); |
| 193 data->fLineNormal.setOrthog(data->fLineNormal); | 191 data->fLineNormal.setOrthog(data->fLineNormal); |
| 194 data->fLineC = -data->fLineNormal.dot(data->fFirstPoint); | 192 data->fLineC = -data->fLineNormal.dot(data->fFirstPoint); |
| 195 data->fStage = DegenerateTestData::kLine; | 193 data->fStage = DegenerateTestData::kLine; |
| 196 } | 194 } |
| 197 break; | 195 break; |
| 198 case DegenerateTestData::kLine: | 196 case DegenerateTestData::kLine: |
| 199 if (SkScalarAbs(data->fLineNormal.dot(pt) + data->fLineC) > TOL) { | 197 if (SkScalarAbs(data->fLineNormal.dot(pt) + data->fLineC) > kClose)
{ |
| 200 data->fStage = DegenerateTestData::kNonDegenerate; | 198 data->fStage = DegenerateTestData::kNonDegenerate; |
| 201 } | 199 } |
| 202 case DegenerateTestData::kNonDegenerate: | 200 case DegenerateTestData::kNonDegenerate: |
| 203 break; | 201 break; |
| 204 default: | 202 default: |
| 205 GrCrash("Unexpected degenerate test stage."); | 203 GrCrash("Unexpected degenerate test stage."); |
| 206 } | 204 } |
| 207 } | 205 } |
| 208 | 206 |
| 209 inline bool get_direction(const SkPath& path, const SkMatrix& m, SkPath::Directi
on* dir) { | 207 static inline bool get_direction(const SkPath& path, const SkMatrix& m, SkPath::
Direction* dir) { |
| 210 if (!path.cheapComputeDirection(dir)) { | 208 if (!path.cheapComputeDirection(dir)) { |
| 211 return false; | 209 return false; |
| 212 } | 210 } |
| 213 // check whether m reverses the orientation | 211 // check whether m reverses the orientation |
| 214 GrAssert(!m.hasPerspective()); | 212 GrAssert(!m.hasPerspective()); |
| 215 SkScalar det2x2 = SkScalarMul(m.get(SkMatrix::kMScaleX), m.get(SkMatrix::kMS
caleY)) - | 213 SkScalar det2x2 = SkScalarMul(m.get(SkMatrix::kMScaleX), m.get(SkMatrix::kMS
caleY)) - |
| 216 SkScalarMul(m.get(SkMatrix::kMSkewX), m.get(SkMatrix::kMSk
ewY)); | 214 SkScalarMul(m.get(SkMatrix::kMSkewX), m.get(SkMatrix::kMSk
ewY)); |
| 217 if (det2x2 < 0) { | 215 if (det2x2 < 0) { |
| 218 *dir = SkPath::OppositeDirection(*dir); | 216 *dir = SkPath::OppositeDirection(*dir); |
| 219 } | 217 } |
| 220 return true; | 218 return true; |
| 221 } | 219 } |
| 222 | 220 |
| 223 bool get_segments(const SkPath& path, | 221 static inline void add_line_segment(const SkPoint pts[2], |
| 224 const SkMatrix& m, | 222 SegmentArray* segments, |
| 225 SegmentArray* segments, | 223 DegenerateTestData* degenerateTestData) { |
| 226 SkPoint* fanPt, | 224 segments->push_back(); |
| 227 int* vCount, | 225 segments->back().fType = Segment::kLine; |
| 228 int* iCount) { | 226 segments->back().fPts[0] = pts[1]; |
| 227 } |
| 228 |
| 229 static inline void add_quad_segment(const SkPoint pts[3], |
| 230 SegmentArray* segments, |
| 231 DegenerateTestData* degenerateTestData) { |
| 232 if (pts[0].distanceToSqd(pts[1]) < kCloseSqd || pts[1].distanceToSqd(pts[2])
< kCloseSqd) { |
| 233 SkPoint linePts[2] = {pts[0], pts[2]}; |
| 234 add_line_segment(linePts, segments, degenerateTestData); |
| 235 } else { |
| 236 segments->push_back(); |
| 237 segments->back().fType = Segment::kQuad; |
| 238 segments->back().fPts[0] = pts[1]; |
| 239 segments->back().fPts[1] = pts[2]; |
| 240 } |
| 241 } |
| 242 |
| 243 static inline void add_cubic_segments(const SkPoint pts[4], |
| 244 SkPath::Direction dir, |
| 245 SegmentArray* segments, |
| 246 DegenerateTestData* degenerateTestData) { |
| 247 SkSTArray<15, SkPoint, true> quads; |
| 248 GrPathUtils::convertCubicToQuads(pts, SK_Scalar1, true, dir, &quads); |
| 249 int count = quads.count(); |
| 250 for (int q = 0; q < count; q += 3) { |
| 251 add_quad_segment(&quads[q], segments, degenerateTestData); |
| 252 } |
| 253 } |
| 254 |
| 255 static bool get_segments(const SkPath& path, |
| 256 const SkMatrix& m, |
| 257 SegmentArray* segments, |
| 258 SkPoint* fanPt, |
| 259 int* vCount, |
| 260 int* iCount) { |
| 229 SkPath::Iter iter(path, true); | 261 SkPath::Iter iter(path, true); |
| 230 // This renderer over-emphasizes very thin path regions. We use the distance | 262 // This renderer over-emphasizes very thin path regions. We use the distance |
| 231 // to the path from the sample to compute coverage. Every pixel intersected | 263 // to the path from the sample to compute coverage. Every pixel intersected |
| 232 // by the path will be hit and the maximum distance is sqrt(2)/2. We don't | 264 // by the path will be hit and the maximum distance is sqrt(2)/2. We don't |
| 233 // notice that the sample may be close to a very thin area of the path and | 265 // notice that the sample may be close to a very thin area of the path and |
| 234 // thus should be very light. This is particularly egregious for degenerate | 266 // thus should be very light. This is particularly egregious for degenerate |
| 235 // line paths. We detect paths that are very close to a line (zero area) and | 267 // line paths. We detect paths that are very close to a line (zero area) and |
| 236 // draw nothing. | 268 // draw nothing. |
| 237 DegenerateTestData degenerateData; | 269 DegenerateTestData degenerateData; |
| 238 SkPath::Direction dir; | 270 SkPath::Direction dir; |
| 239 // get_direction can fail for some degenerate paths. | 271 // get_direction can fail for some degenerate paths. |
| 240 if (!get_direction(path, m, &dir)) { | 272 if (!get_direction(path, m, &dir)) { |
| 241 return false; | 273 return false; |
| 242 } | 274 } |
| 243 | 275 |
| 244 for (;;) { | 276 for (;;) { |
| 245 GrPoint pts[4]; | 277 GrPoint pts[4]; |
| 246 SkPath::Verb verb = iter.next(pts); | 278 SkPath::Verb verb = iter.next(pts); |
| 247 switch (verb) { | 279 switch (verb) { |
| 248 case SkPath::kMove_Verb: | 280 case SkPath::kMove_Verb: |
| 249 m.mapPoints(pts, 1); | 281 m.mapPoints(pts, 1); |
| 250 update_degenerate_test(°enerateData, pts[0]); | 282 update_degenerate_test(°enerateData, pts[0]); |
| 251 break; | 283 break; |
| 252 case SkPath::kLine_Verb: { | 284 case SkPath::kLine_Verb: { |
| 253 m.mapPoints(pts + 1, 1); | 285 m.mapPoints(pts, 2); |
| 254 update_degenerate_test(°enerateData, pts[1]); | 286 update_degenerate_test(°enerateData, pts[1]); |
| 255 segments->push_back(); | 287 add_line_segment(pts, segments, °enerateData); |
| 256 segments->back().fType = Segment::kLine; | |
| 257 segments->back().fPts[0] = pts[1]; | |
| 258 break; | 288 break; |
| 259 } | 289 } |
| 260 case SkPath::kQuad_Verb: | 290 case SkPath::kQuad_Verb: |
| 261 m.mapPoints(pts + 1, 2); | 291 m.mapPoints(pts, 3); |
| 262 update_degenerate_test(°enerateData, pts[1]); | 292 update_degenerate_test(°enerateData, pts[1]); |
| 263 update_degenerate_test(°enerateData, pts[2]); | 293 update_degenerate_test(°enerateData, pts[2]); |
| 264 segments->push_back(); | 294 add_quad_segment(pts, segments, °enerateData); |
| 265 segments->back().fType = Segment::kQuad; | |
| 266 segments->back().fPts[0] = pts[1]; | |
| 267 segments->back().fPts[1] = pts[2]; | |
| 268 break; | 295 break; |
| 269 case SkPath::kCubic_Verb: { | 296 case SkPath::kCubic_Verb: { |
| 297 // unlike quads and lines, the pts[0] will also be read (since w
e convert the cubic |
| 298 // to quads). |
| 270 m.mapPoints(pts, 4); | 299 m.mapPoints(pts, 4); |
| 271 update_degenerate_test(°enerateData, pts[1]); | 300 update_degenerate_test(°enerateData, pts[1]); |
| 272 update_degenerate_test(°enerateData, pts[2]); | 301 update_degenerate_test(°enerateData, pts[2]); |
| 273 update_degenerate_test(°enerateData, pts[3]); | 302 update_degenerate_test(°enerateData, pts[3]); |
| 274 // unlike quads and lines, the pts[0] will also be read (in | 303 add_cubic_segments(pts, dir, segments, °enerateData); |
| 275 // convertCubicToQuads). | |
| 276 SkSTArray<15, SkPoint, true> quads; | |
| 277 GrPathUtils::convertCubicToQuads(pts, SK_Scalar1, true, dir, &qu
ads); | |
| 278 int count = quads.count(); | |
| 279 for (int q = 0; q < count; q += 3) { | |
| 280 segments->push_back(); | |
| 281 segments->back().fType = Segment::kQuad; | |
| 282 segments->back().fPts[0] = quads[q + 1]; | |
| 283 segments->back().fPts[1] = quads[q + 2]; | |
| 284 } | |
| 285 break; | 304 break; |
| 286 }; | 305 }; |
| 287 case SkPath::kDone_Verb: | 306 case SkPath::kDone_Verb: |
| 288 if (degenerateData.isDegenerate()) { | 307 if (degenerateData.isDegenerate()) { |
| 289 return false; | 308 return false; |
| 290 } else { | 309 } else { |
| 291 compute_vectors(segments, fanPt, dir, vCount, iCount); | 310 compute_vectors(segments, fanPt, dir, vCount, iCount); |
| 292 return true; | 311 return true; |
| 293 } | 312 } |
| 294 default: | 313 default: |
| (...skipping 10 matching lines...) Expand all Loading... |
| 305 }; | 324 }; |
| 306 | 325 |
| 307 struct Draw { | 326 struct Draw { |
| 308 Draw() : fVertexCnt(0), fIndexCnt(0) {} | 327 Draw() : fVertexCnt(0), fIndexCnt(0) {} |
| 309 int fVertexCnt; | 328 int fVertexCnt; |
| 310 int fIndexCnt; | 329 int fIndexCnt; |
| 311 }; | 330 }; |
| 312 | 331 |
| 313 typedef SkTArray<Draw, true> DrawArray; | 332 typedef SkTArray<Draw, true> DrawArray; |
| 314 | 333 |
| 315 void create_vertices(const SegmentArray& segments, | 334 static void create_vertices(const SegmentArray& segments, |
| 316 const SkPoint& fanPt, | 335 const SkPoint& fanPt, |
| 317 DrawArray* draws, | 336 DrawArray* draws, |
| 318 QuadVertex* verts, | 337 QuadVertex* verts, |
| 319 uint16_t* idxs) { | 338 uint16_t* idxs) { |
| 320 Draw* draw = &draws->push_back(); | 339 Draw* draw = &draws->push_back(); |
| 321 // alias just to make vert/index assignments easier to read. | 340 // alias just to make vert/index assignments easier to read. |
| 322 int* v = &draw->fVertexCnt; | 341 int* v = &draw->fVertexCnt; |
| 323 int* i = &draw->fIndexCnt; | 342 int* i = &draw->fIndexCnt; |
| 324 | 343 |
| 325 int count = segments.count(); | 344 int count = segments.count(); |
| 326 for (int a = 0; a < count; ++a) { | 345 for (int a = 0; a < count; ++a) { |
| 327 const Segment& sega = segments[a]; | 346 const Segment& sega = segments[a]; |
| 328 int b = (a + 1) % count; | 347 int b = (a + 1) % count; |
| 329 const Segment& segb = segments[b]; | 348 const Segment& segb = segments[b]; |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 452 idxs[*i + 9] = *v + 0; | 471 idxs[*i + 9] = *v + 0; |
| 453 idxs[*i + 10] = *v + 2; | 472 idxs[*i + 10] = *v + 2; |
| 454 idxs[*i + 11] = *v + 1; | 473 idxs[*i + 11] = *v + 1; |
| 455 | 474 |
| 456 *v += 6; | 475 *v += 6; |
| 457 *i += 12; | 476 *i += 12; |
| 458 } | 477 } |
| 459 } | 478 } |
| 460 } | 479 } |
| 461 | 480 |
| 462 } | |
| 463 | |
| 464 /////////////////////////////////////////////////////////////////////////////// | 481 /////////////////////////////////////////////////////////////////////////////// |
| 465 | 482 |
| 466 /* | 483 /* |
| 467 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first | 484 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first |
| 468 * two components of the vertex attribute. Coverage is based on signed | 485 * two components of the vertex attribute. Coverage is based on signed |
| 469 * distance with negative being inside, positive outside. The edge is specified
in | 486 * distance with negative being inside, positive outside. The edge is specified
in |
| 470 * window space (y-down). If either the third or fourth component of the interpo
lated | 487 * window space (y-down). If either the third or fourth component of the interpo
lated |
| 471 * vertex coord is > 0 then the pixel is considered outside the edge. This is us
ed to | 488 * vertex coord is > 0 then the pixel is considered outside the edge. This is us
ed to |
| 472 * attempt to trim to a portion of the infinite quad. | 489 * attempt to trim to a portion of the infinite quad. |
| 473 * Requires shader derivative instruction support. | 490 * Requires shader derivative instruction support. |
| (...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 677 vOffset, // start vertex | 694 vOffset, // start vertex |
| 678 0, // start index | 695 0, // start index |
| 679 draw.fVertexCnt, | 696 draw.fVertexCnt, |
| 680 draw.fIndexCnt, | 697 draw.fIndexCnt, |
| 681 &devBounds); | 698 &devBounds); |
| 682 vOffset += draw.fVertexCnt; | 699 vOffset += draw.fVertexCnt; |
| 683 } | 700 } |
| 684 | 701 |
| 685 return true; | 702 return true; |
| 686 } | 703 } |
| OLD | NEW |