| OLD | NEW |
| 1 | 1 |
| 2 /* | 2 /* |
| 3 * Copyright 2011 Google Inc. | 3 * Copyright 2011 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 "GrAAHairLinePathRenderer.h" | 9 #include "GrAAHairLinePathRenderer.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 "GrGpu.h" | 15 #include "GrGpu.h" |
| 16 #include "GrIndexBuffer.h" | 16 #include "GrIndexBuffer.h" |
| 17 #include "GrPathUtils.h" | 17 #include "GrPathUtils.h" |
| 18 #include "GrTBackendEffectFactory.h" | 18 #include "GrTBackendEffectFactory.h" |
| 19 #include "SkGeometry.h" | 19 #include "SkGeometry.h" |
| 20 #include "SkStroke.h" | 20 #include "SkStroke.h" |
| 21 #include "SkTemplates.h" | 21 #include "SkTemplates.h" |
| 22 | 22 |
| 23 #include "gl/GrGLEffect.h" | 23 #include "gl/GrGLEffect.h" |
| 24 #include "gl/GrGLSL.h" | 24 #include "gl/GrGLSL.h" |
| 25 | 25 |
| 26 namespace { | 26 namespace { |
| 27 // quadratics are rendered as 5-sided polys in order to bound the | 27 // quadratics are rendered as 5-sided polys in order to bound the |
| 28 // AA stroke around the center-curve. See comments in push_quad_index_buffer and | 28 // AA stroke around the center-curve. See comments in push_quad_index_buffer and |
| 29 // bloat_quad. | 29 // bloat_quad. Quadratics and conics share an index buffer |
| 30 static const int kVertsPerQuad = 5; | 30 static const int kVertsPerQuad = 5; |
| 31 static const int kIdxsPerQuad = 9; | 31 static const int kIdxsPerQuad = 9; |
| 32 | 32 |
| 33 static const int kVertsPerLineSeg = 4; | 33 static const int kVertsPerLineSeg = 4; |
| 34 static const int kIdxsPerLineSeg = 6; | 34 static const int kIdxsPerLineSeg = 6; |
| 35 | 35 |
| 36 static const int kNumQuadsInIdxBuffer = 256; | 36 static const int kNumQuadsInIdxBuffer = 256; |
| 37 static const size_t kQuadIdxSBufize = kIdxsPerQuad * | 37 static const size_t kQuadIdxSBufize = kIdxsPerQuad * |
| 38 sizeof(uint16_t) * | 38 sizeof(uint16_t) * |
| 39 kNumQuadsInIdxBuffer; | 39 kNumQuadsInIdxBuffer; |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 110 GrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() { | 110 GrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() { |
| 111 fLinesIndexBuffer->unref(); | 111 fLinesIndexBuffer->unref(); |
| 112 fQuadsIndexBuffer->unref(); | 112 fQuadsIndexBuffer->unref(); |
| 113 } | 113 } |
| 114 | 114 |
| 115 namespace { | 115 namespace { |
| 116 | 116 |
| 117 typedef SkTArray<SkPoint, true> PtArray; | 117 typedef SkTArray<SkPoint, true> PtArray; |
| 118 #define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> | 118 #define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> |
| 119 typedef SkTArray<int, true> IntArray; | 119 typedef SkTArray<int, true> IntArray; |
| 120 typedef SkTArray<float, true> FloatArray; |
| 120 | 121 |
| 121 // Takes 178th time of logf on Z600 / VC2010 | 122 // Takes 178th time of logf on Z600 / VC2010 |
| 122 int get_float_exp(float x) { | 123 int get_float_exp(float x) { |
| 123 GR_STATIC_ASSERT(sizeof(int) == sizeof(float)); | 124 GR_STATIC_ASSERT(sizeof(int) == sizeof(float)); |
| 124 #if GR_DEBUG | 125 #if GR_DEBUG |
| 125 static bool tested; | 126 static bool tested; |
| 126 if (!tested) { | 127 if (!tested) { |
| 127 tested = true; | 128 tested = true; |
| 128 GrAssert(get_float_exp(0.25f) == -2); | 129 GrAssert(get_float_exp(0.25f) == -2); |
| 129 GrAssert(get_float_exp(0.3f) == -2); | 130 GrAssert(get_float_exp(0.3f) == -2); |
| 130 GrAssert(get_float_exp(0.5f) == -1); | 131 GrAssert(get_float_exp(0.5f) == -1); |
| 131 GrAssert(get_float_exp(1.f) == 0); | 132 GrAssert(get_float_exp(1.f) == 0); |
| 132 GrAssert(get_float_exp(2.f) == 1); | 133 GrAssert(get_float_exp(2.f) == 1); |
| 133 GrAssert(get_float_exp(2.5f) == 1); | 134 GrAssert(get_float_exp(2.5f) == 1); |
| 134 GrAssert(get_float_exp(8.f) == 3); | 135 GrAssert(get_float_exp(8.f) == 3); |
| 135 GrAssert(get_float_exp(100.f) == 6); | 136 GrAssert(get_float_exp(100.f) == 6); |
| 136 GrAssert(get_float_exp(1000.f) == 9); | 137 GrAssert(get_float_exp(1000.f) == 9); |
| 137 GrAssert(get_float_exp(1024.f) == 10); | 138 GrAssert(get_float_exp(1024.f) == 10); |
| 138 GrAssert(get_float_exp(3000000.f) == 21); | 139 GrAssert(get_float_exp(3000000.f) == 21); |
| 139 } | 140 } |
| 140 #endif | 141 #endif |
| 141 const int* iptr = (const int*)&x; | 142 const int* iptr = (const int*)&x; |
| 142 return (((*iptr) & 0x7f800000) >> 23) - 127; | 143 return (((*iptr) & 0x7f800000) >> 23) - 127; |
| 143 } | 144 } |
| 144 | 145 |
| 146 // Uses the max curvature function for quads to estimate |
| 147 // where to chop the conic. If the max curvature is not |
| 148 // found along the curve segment it will return 1 and |
| 149 // dst[0] is the orginal conic. If it returns 2 the dst[0] |
| 150 // and dst[1] are the two new conics. |
| 151 int chop_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) { |
| 152 SkScalar t = SkFindQuadMaxCurvature(src); |
| 153 if (t == 0) { |
| 154 if (dst) { |
| 155 dst[0].set(src, weight); |
| 156 } |
| 157 return 1; |
| 158 } else { |
| 159 if (dst) { |
| 160 SkConic conic; |
| 161 conic.set(src, weight); |
| 162 conic.chopAt(t, dst); |
| 163 } |
| 164 return 2; |
| 165 } |
| 166 } |
| 167 |
| 168 // returns 0 if quad/conic is degen or close to it |
| 169 // in this case approx the path with lines |
| 170 // otherwise returns 1 |
| 171 int is_degen_quad_or_conic(const SkPoint p[3]) { |
| 172 static const SkScalar gDegenerateToLineTol = SK_Scalar1; |
| 173 static const SkScalar gDegenerateToLineTolSqd = |
| 174 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); |
| 175 |
| 176 if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || |
| 177 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { |
| 178 return 1; |
| 179 } |
| 180 |
| 181 SkScalar dsqd = p[1].distanceToLineBetweenSqd(p[0], p[2]); |
| 182 if (dsqd < gDegenerateToLineTolSqd) { |
| 183 return 1; |
| 184 } |
| 185 |
| 186 if (p[2].distanceToLineBetweenSqd(p[1], p[0]) < gDegenerateToLineTolSqd) { |
| 187 return 1; |
| 188 } |
| 189 return 0; |
| 190 } |
| 191 |
| 145 // we subdivide the quads to avoid huge overfill | 192 // we subdivide the quads to avoid huge overfill |
| 146 // if it returns -1 then should be drawn as lines | 193 // if it returns -1 then should be drawn as lines |
| 147 int num_quad_subdivs(const SkPoint p[3]) { | 194 int num_quad_subdivs(const SkPoint p[3]) { |
| 148 static const SkScalar gDegenerateToLineTol = SK_Scalar1; | 195 static const SkScalar gDegenerateToLineTol = SK_Scalar1; |
| 149 static const SkScalar gDegenerateToLineTolSqd = | 196 static const SkScalar gDegenerateToLineTolSqd = |
| 150 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); | 197 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); |
| 151 | 198 |
| 152 if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || | 199 if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || |
| 153 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { | 200 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { |
| 154 return -1; | 201 return -1; |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 200 * Quads are recorded in device space unless m contains | 247 * Quads are recorded in device space unless m contains |
| 201 * perspective, then in they are in src space. We do this because we will | 248 * perspective, then in they are in src space. We do this because we will |
| 202 * subdivide large quads to reduce over-fill. This subdivision has to be | 249 * subdivide large quads to reduce over-fill. This subdivision has to be |
| 203 * performed before applying the perspective matrix. | 250 * performed before applying the perspective matrix. |
| 204 */ | 251 */ |
| 205 int generate_lines_and_quads(const SkPath& path, | 252 int generate_lines_and_quads(const SkPath& path, |
| 206 const SkMatrix& m, | 253 const SkMatrix& m, |
| 207 const GrIRect& devClipBounds, | 254 const GrIRect& devClipBounds, |
| 208 PtArray* lines, | 255 PtArray* lines, |
| 209 PtArray* quads, | 256 PtArray* quads, |
| 210 IntArray* quadSubdivCnts) { | 257 PtArray* conics, |
| 258 IntArray* quadSubdivCnts, |
| 259 FloatArray* conicWeights) { |
| 211 SkPath::Iter iter(path, false); | 260 SkPath::Iter iter(path, false); |
| 212 | 261 |
| 213 int totalQuadCount = 0; | 262 int totalQuadCount = 0; |
| 214 GrRect bounds; | 263 GrRect bounds; |
| 215 GrIRect ibounds; | 264 GrIRect ibounds; |
| 216 | 265 |
| 217 bool persp = m.hasPerspective(); | 266 bool persp = m.hasPerspective(); |
| 218 | 267 |
| 219 for (;;) { | 268 for (;;) { |
| 220 GrPoint pathPts[4]; | 269 GrPoint pathPts[4]; |
| 221 GrPoint devPts[4]; | 270 GrPoint devPts[4]; |
| 222 SkPath::Verb verb = iter.next(pathPts); | 271 SkPath::Verb verb = iter.next(pathPts); |
| 223 switch (verb) { | 272 switch (verb) { |
| 224 case SkPath::kConic_Verb: | 273 case SkPath::kConic_Verb: { |
| 225 SkASSERT(0); | 274 SkConic dst[2]; |
| 275 int conicCnt = chop_conic(pathPts, dst, iter.conicWeight()); |
| 276 for (int i = 0; i < conicCnt; ++i) { |
| 277 SkPoint* chopPnts = dst[i].fPts; |
| 278 m.mapPoints(devPts, chopPnts, 3); |
| 279 bounds.setBounds(devPts, 3); |
| 280 bounds.outset(SK_Scalar1, SK_Scalar1); |
| 281 bounds.roundOut(&ibounds); |
| 282 if (SkIRect::Intersects(devClipBounds, ibounds)) { |
| 283 if (is_degen_quad_or_conic(devPts)) { |
| 284 SkPoint* pts = lines->push_back_n(4); |
| 285 pts[0] = devPts[0]; |
| 286 pts[1] = devPts[1]; |
| 287 pts[2] = devPts[1]; |
| 288 pts[3] = devPts[2]; |
| 289 } else { |
| 290 // when in perspective keep conics in src space |
| 291 SkPoint* cPts = persp ? chopPnts : devPts; |
| 292 SkPoint* pts = conics->push_back_n(3); |
| 293 pts[0] = cPts[0]; |
| 294 pts[1] = cPts[1]; |
| 295 pts[2] = cPts[2]; |
| 296 conicWeights->push_back() = dst[i].fW; |
| 297 } |
| 298 } |
| 299 } |
| 226 break; | 300 break; |
| 227 case SkPath::kMove_Verb: | 301 } |
| 302 case SkPath::kMove_Verb: |
| 228 break; | 303 break; |
| 229 case SkPath::kLine_Verb: | 304 case SkPath::kLine_Verb: |
| 230 m.mapPoints(devPts, pathPts, 2); | 305 m.mapPoints(devPts, pathPts, 2); |
| 231 bounds.setBounds(devPts, 2); | 306 bounds.setBounds(devPts, 2); |
| 232 bounds.outset(SK_Scalar1, SK_Scalar1); | 307 bounds.outset(SK_Scalar1, SK_Scalar1); |
| 233 bounds.roundOut(&ibounds); | 308 bounds.roundOut(&ibounds); |
| 234 if (SkIRect::Intersects(devClipBounds, ibounds)) { | 309 if (SkIRect::Intersects(devClipBounds, ibounds)) { |
| 235 SkPoint* pts = lines->push_back_n(2); | 310 SkPoint* pts = lines->push_back_n(2); |
| 236 pts[0] = devPts[0]; | 311 pts[0] = devPts[0]; |
| 237 pts[1] = devPts[1]; | 312 pts[1] = devPts[1]; |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 341 } | 416 } |
| 342 | 417 |
| 343 struct Vertex { | 418 struct Vertex { |
| 344 GrPoint fPos; | 419 GrPoint fPos; |
| 345 union { | 420 union { |
| 346 struct { | 421 struct { |
| 347 SkScalar fA; | 422 SkScalar fA; |
| 348 SkScalar fB; | 423 SkScalar fB; |
| 349 SkScalar fC; | 424 SkScalar fC; |
| 350 } fLine; | 425 } fLine; |
| 426 struct { |
| 427 SkScalar fA; |
| 428 SkScalar fB; |
| 429 SkScalar fC; |
| 430 SkScalar fD; |
| 431 SkScalar fE; |
| 432 SkScalar fF; |
| 433 } fConic; |
| 351 GrVec fQuadCoord; | 434 GrVec fQuadCoord; |
| 352 struct { | 435 struct { |
| 353 SkScalar fBogus[4]; | 436 SkScalar fBogus[6]; |
| 354 }; | 437 }; |
| 355 }; | 438 }; |
| 356 }; | 439 }; |
| 357 GR_STATIC_ASSERT(sizeof(Vertex) == 3 * sizeof(GrPoint)); | 440 |
| 441 GR_STATIC_ASSERT(sizeof(Vertex) == 4 * sizeof(GrPoint)); |
| 358 | 442 |
| 359 void intersect_lines(const SkPoint& ptA, const SkVector& normA, | 443 void intersect_lines(const SkPoint& ptA, const SkVector& normA, |
| 360 const SkPoint& ptB, const SkVector& normB, | 444 const SkPoint& ptB, const SkVector& normB, |
| 361 SkPoint* result) { | 445 SkPoint* result) { |
| 362 | 446 |
| 363 SkScalar lineAW = -normA.dot(ptA); | 447 SkScalar lineAW = -normA.dot(ptA); |
| 364 SkScalar lineBW = -normB.dot(ptB); | 448 SkScalar lineBW = -normB.dot(ptB); |
| 365 | 449 |
| 366 SkScalar wInv = SkScalarMul(normA.fX, normB.fY) - | 450 SkScalar wInv = SkScalarMul(normA.fX, normB.fY) - |
| 367 SkScalarMul(normA.fY, normB.fX); | 451 SkScalarMul(normA.fY, normB.fX); |
| 368 wInv = SkScalarInvert(wInv); | 452 wInv = SkScalarInvert(wInv); |
| 369 | 453 |
| 370 result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY); | 454 result->fX = SkScalarMul(normA.fY, lineBW) - SkScalarMul(lineAW, normB.fY); |
| 371 result->fX = SkScalarMul(result->fX, wInv); | 455 result->fX = SkScalarMul(result->fX, wInv); |
| 372 | 456 |
| 373 result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW); | 457 result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW); |
| 374 result->fY = SkScalarMul(result->fY, wInv); | 458 result->fY = SkScalarMul(result->fY, wInv); |
| 375 } | 459 } |
| 376 | 460 |
| 377 void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, | 461 void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 447 // include it. | 531 // include it. |
| 448 intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos); | 532 intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos); |
| 449 devBounds->growToInclude(b0.fPos.fX, b0.fPos.fY); | 533 devBounds->growToInclude(b0.fPos.fX, b0.fPos.fY); |
| 450 | 534 |
| 451 if (toSrc) { | 535 if (toSrc) { |
| 452 toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(Vertex), kVertsPerQuad
); | 536 toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(Vertex), kVertsPerQuad
); |
| 453 } | 537 } |
| 454 DevToUV.apply<kVertsPerQuad, sizeof(Vertex), sizeof(GrPoint)>(verts); | 538 DevToUV.apply<kVertsPerQuad, sizeof(Vertex), sizeof(GrPoint)>(verts); |
| 455 } | 539 } |
| 456 | 540 |
| 541 |
| 542 // Input Parametric: |
| 543 // P(t) = (P0*(1-t)^2 + 2*w*P1*t*(1-t) + P2*t^2) / (1-t)^2 + 2*w*t*(1-t) + t^2) |
| 544 // Output Implicit: |
| 545 // Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0 |
| 546 // A = 4w^2*(y0-y1)(y1-y2)-(y0-y2)^2 |
| 547 // B = 4w^2*((x0-x1)(y2-y1)+(x1-x2)(y1-y0)) + 2(x0-x2)(y0-y2) |
| 548 // C = 4w^2(x0-x1)(x1-x2) - (x0-x2)^2 |
| 549 // D = 4w^2((x0y1-x1y0)(y1-y2)+(x1y2-x2y1)(y0-y1)) + 2(y2-y0)(x0y2-x2y0) |
| 550 // E = 4w^2((y0x1-y1x0)(x1-x2)+(y1x2-y2x1)(x0-x1)) + 2(x2-x0)(y0x2-y2x0) |
| 551 // F = 4w^2(x1y2-x2y1)(x0y1-x1y0) - (x2y0-x0y2)^2 |
| 552 |
| 553 void set_conic_coeffs(const SkPoint p[3], Vertex verts[kVertsPerQuad], const flo
at weight) { |
| 554 const float ww4 = 4 * weight * weight; |
| 555 const float x0Mx1 = p[0].fX - p[1].fX; |
| 556 const float x1Mx2 = p[1].fX - p[2].fX; |
| 557 const float x0Mx2 = p[0].fX - p[2].fX; |
| 558 const float y0My1 = p[0].fY - p[1].fY; |
| 559 const float y1My2 = p[1].fY - p[2].fY; |
| 560 const float y0My2 = p[0].fY - p[2].fY; |
| 561 const float x0y1Mx1y0 = p[0].fX*p[1].fY - p[1].fX*p[0].fY; |
| 562 const float x1y2Mx2y1 = p[1].fX*p[2].fY - p[2].fX*p[1].fY; |
| 563 const float x0y2Mx2y0 = p[0].fX*p[2].fY - p[2].fX*p[0].fY; |
| 564 const float a = ww4 * y0My1 * y1My2 - y0My2 * y0My2; |
| 565 const float b = -ww4 * (x0Mx1 * y1My2 + x1Mx2 * y0My1) + 2 * x0Mx2 * y0My2; |
| 566 const float c = ww4 * x0Mx1 * x1Mx2 - x0Mx2 * x0Mx2; |
| 567 const float d = ww4 * (x0y1Mx1y0 * y1My2 + x1y2Mx2y1 * y0My1) - 2 * y0My2 *
x0y2Mx2y0; |
| 568 const float e = -ww4 * (x0y1Mx1y0 * x1Mx2 + x1y2Mx2y1 * x0Mx1) + 2 * x0Mx2 *
x0y2Mx2y0; |
| 569 const float f = ww4 * x1y2Mx2y1 * x0y1Mx1y0 - x0y2Mx2y0 * x0y2Mx2y0; |
| 570 |
| 571 for (int i = 0; i < kVertsPerQuad; ++i) { |
| 572 verts[i].fConic.fA = a/f; |
| 573 verts[i].fConic.fB = b/f; |
| 574 verts[i].fConic.fC = c/f; |
| 575 verts[i].fConic.fD = d/f; |
| 576 verts[i].fConic.fE = e/f; |
| 577 verts[i].fConic.fF = f/f; |
| 578 } |
| 579 } |
| 580 |
| 581 void add_conics(const SkPoint p[3], |
| 582 float weight, |
| 583 const SkMatrix* toDevice, |
| 584 const SkMatrix* toSrc, |
| 585 Vertex** vert, |
| 586 SkRect* devBounds) { |
| 587 bloat_quad(p, toDevice, toSrc, *vert, devBounds); |
| 588 set_conic_coeffs(p, *vert, weight); |
| 589 *vert += kVertsPerQuad; |
| 590 } |
| 591 |
| 457 void add_quads(const SkPoint p[3], | 592 void add_quads(const SkPoint p[3], |
| 458 int subdiv, | 593 int subdiv, |
| 459 const SkMatrix* toDevice, | 594 const SkMatrix* toDevice, |
| 460 const SkMatrix* toSrc, | 595 const SkMatrix* toSrc, |
| 461 Vertex** vert, | 596 Vertex** vert, |
| 462 SkRect* devBounds) { | 597 SkRect* devBounds) { |
| 463 GrAssert(subdiv >= 0); | 598 GrAssert(subdiv >= 0); |
| 464 if (subdiv) { | 599 if (subdiv) { |
| 465 SkPoint newP[5]; | 600 SkPoint newP[5]; |
| 466 SkChopQuadAtHalf(p, newP); | 601 SkChopQuadAtHalf(p, newP); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 508 (*vert)[1].fPos.set(SK_ScalarMax, SK_ScalarMax); | 643 (*vert)[1].fPos.set(SK_ScalarMax, SK_ScalarMax); |
| 509 (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax); | 644 (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax); |
| 510 (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax); | 645 (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax); |
| 511 } | 646 } |
| 512 | 647 |
| 513 *vert += kVertsPerLineSeg; | 648 *vert += kVertsPerLineSeg; |
| 514 } | 649 } |
| 515 | 650 |
| 516 } | 651 } |
| 517 | 652 |
| 653 /** |
| 654 * The output of this effect is a hairline edge for conics. |
| 655 * Conics specified by implicit equation Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0. |
| 656 * A, B, C, D are the first vec4 of vertex attributes and |
| 657 * E and F are the vec2 attached to 2nd vertex attrribute. |
| 658 * Coverage is max(0, 1-distance). |
| 659 */ |
| 660 class HairConicEdgeEffect : public GrEffect { |
| 661 public: |
| 662 static GrEffectRef* Create() { |
| 663 GR_CREATE_STATIC_EFFECT(gHairConicEdgeEffect, HairConicEdgeEffect, ()); |
| 664 gHairConicEdgeEffect->ref(); |
| 665 return gHairConicEdgeEffect; |
| 666 } |
| 667 |
| 668 virtual ~HairConicEdgeEffect() {} |
| 669 |
| 670 static const char* Name() { return "HairConicEdge"; } |
| 671 |
| 672 virtual void getConstantColorComponents(GrColor* color, |
| 673 uint32_t* validFlags) const SK_OVERR
IDE { |
| 674 *validFlags = 0; |
| 675 } |
| 676 |
| 677 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { |
| 678 return GrTBackendEffectFactory<HairConicEdgeEffect>::getInstance(); |
| 679 } |
| 680 |
| 681 class GLEffect : public GrGLEffect { |
| 682 public: |
| 683 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) |
| 684 : INHERITED (factory) {} |
| 685 |
| 686 virtual void emitCode(GrGLShaderBuilder* builder, |
| 687 const GrDrawEffect& drawEffect, |
| 688 EffectKey key, |
| 689 const char* outputColor, |
| 690 const char* inputColor, |
| 691 const TextureSamplerArray& samplers) SK_OVERRIDE { |
| 692 const char *vsCoeffABCDName, *fsCoeffABCDName; |
| 693 const char *vsCoeffEFName, *fsCoeffEFName; |
| 694 |
| 695 SkAssertResult(builder->enableFeature( |
| 696 GrGLShaderBuilder::kStandardDerivatives_GLSLFeature)); |
| 697 builder->addVarying(kVec4f_GrSLType, "ConicCoeffsABCD", |
| 698 &vsCoeffABCDName, &fsCoeffABCDName); |
| 699 const SkString* attr0Name = |
| 700 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice
s()[0]); |
| 701 builder->vsCodeAppendf("\t%s = %s;\n", vsCoeffABCDName, attr0Name->c
_str()); |
| 702 |
| 703 builder->addVarying(kVec2f_GrSLType, "ConicCoeffsEF", |
| 704 &vsCoeffEFName, &fsCoeffEFName); |
| 705 const SkString* attr1Name = |
| 706 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice
s()[1]); |
| 707 builder->vsCodeAppendf("\t%s = %s;\n", vsCoeffEFName, attr1Name->c_s
tr()); |
| 708 |
| 709 // Based on Gustavson 2006: "Beyond the Pixel: towards infinite reso
lution textures" |
| 710 builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n"); |
| 711 |
| 712 builder->fsCodeAppendf("\t\tvec3 uv1 = vec3(%s.xy, 1);\n", builder->
fragmentPosition()); |
| 713 builder->fsCodeAppend("\t\tvec3 u2uvv2 = uv1.xxy * uv1.xyy;\n"); |
| 714 builder->fsCodeAppendf("\t\tvec3 ABC = %s.xyz;\n", fsCoeffABCDName); |
| 715 builder->fsCodeAppendf("\t\tvec3 DEF = vec3(%s.w, %s.xy);\n", |
| 716 fsCoeffABCDName, fsCoeffEFName); |
| 717 |
| 718 builder->fsCodeAppend("\t\tfloat dfdx = dot(uv1,vec3(2.0*ABC.x,ABC.y
,DEF.x));\n"); |
| 719 builder->fsCodeAppend("\t\tfloat dfdy = dot(uv1,vec3(ABC.y, 2.0*ABC.
z,DEF.y));\n"); |
| 720 builder->fsCodeAppend("\t\tfloat gF = dfdx*dfdx + dfdy*dfdy;\n"); |
| 721 builder->fsCodeAppend("\t\tedgeAlpha = dot(ABC,u2uvv2) + dot(DEF,uv1
);\n"); |
| 722 builder->fsCodeAppend("\t\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / gF
);\n"); |
| 723 builder->fsCodeAppend("\t\tedgeAlpha = max((1.0 - edgeAlpha), 0.0);\
n"); |
| 724 // Add line below for smooth cubic ramp |
| 725 // builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2
.0*edgeAlpha);\n"); |
| 726 |
| 727 SkString modulate; |
| 728 GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha"); |
| 729 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str()
); |
| 730 } |
| 731 |
| 732 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG
LCaps&) { |
| 733 return 0x0; |
| 734 } |
| 735 |
| 736 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_
OVERRIDE {} |
| 737 |
| 738 private: |
| 739 typedef GrGLEffect INHERITED; |
| 740 }; |
| 741 |
| 742 private: |
| 743 HairConicEdgeEffect() { |
| 744 this->addVertexAttrib(kVec4f_GrSLType); |
| 745 this->addVertexAttrib(kVec2f_GrSLType); |
| 746 this->setWillReadFragmentPosition(); |
| 747 } |
| 748 |
| 749 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { |
| 750 return true; |
| 751 } |
| 752 |
| 753 GR_DECLARE_EFFECT_TEST; |
| 754 |
| 755 typedef GrEffect INHERITED; |
| 756 }; |
| 757 |
| 758 GR_DEFINE_EFFECT_TEST(HairConicEdgeEffect); |
| 759 |
| 760 GrEffectRef* HairConicEdgeEffect::TestCreate(SkMWCRandom* random, |
| 761 GrContext*, |
| 762 const GrDrawTargetCaps& caps, |
| 763 GrTexture*[]) { |
| 764 return HairConicEdgeEffect::Create(); |
| 765 } |
| 518 /////////////////////////////////////////////////////////////////////////////// | 766 /////////////////////////////////////////////////////////////////////////////// |
| 519 | 767 |
| 520 /** | 768 /** |
| 521 * The output of this effect is a hairline edge for quadratics. | 769 * The output of this effect is a hairline edge for quadratics. |
| 522 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first | 770 * Quadratic specified by 0=u^2-v canonical coords. u and v are the first |
| 523 * two components of the vertex attribute. Uses unsigned distance. | 771 * two components of the vertex attribute. Uses unsigned distance. |
| 524 * Coverage is min(0, 1-distance). 3rd & 4th component unused. | 772 * Coverage is min(0, 1-distance). 3rd & 4th component unused. |
| 525 * Requires shader derivative instruction support. | 773 * Requires shader derivative instruction support. |
| 526 */ | 774 */ |
| 527 class HairQuadEdgeEffect : public GrEffect { | 775 class HairQuadEdgeEffect : public GrEffect { |
| (...skipping 28 matching lines...) Expand all Loading... |
| 556 EffectKey key, | 804 EffectKey key, |
| 557 const char* outputColor, | 805 const char* outputColor, |
| 558 const char* inputColor, | 806 const char* inputColor, |
| 559 const TextureSamplerArray& samplers) SK_OVERRIDE { | 807 const TextureSamplerArray& samplers) SK_OVERRIDE { |
| 560 const char *vsName, *fsName; | 808 const char *vsName, *fsName; |
| 561 const SkString* attrName = | 809 const SkString* attrName = |
| 562 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice
s()[0]); | 810 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice
s()[0]); |
| 563 builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n"); | 811 builder->fsCodeAppendf("\t\tfloat edgeAlpha;\n"); |
| 564 | 812 |
| 565 SkAssertResult(builder->enableFeature( | 813 SkAssertResult(builder->enableFeature( |
| 566 GrGLShaderBuilder::kStandardDeriva
tives_GLSLFeature)); | 814 GrGLShaderBuilder::kStandardDerivatives_GLSLFeature)); |
| 567 builder->addVarying(kVec4f_GrSLType, "HairQuadEdge", &vsName, &fsNam
e); | 815 builder->addVarying(kVec4f_GrSLType, "HairQuadEdge", &vsName, &fsNam
e); |
| 568 | 816 |
| 569 builder->fsCodeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName); | 817 builder->fsCodeAppendf("\t\tvec2 duvdx = dFdx(%s.xy);\n", fsName); |
| 570 builder->fsCodeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName); | 818 builder->fsCodeAppendf("\t\tvec2 duvdy = dFdy(%s.xy);\n", fsName); |
| 571 builder->fsCodeAppendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.
y,\n" | 819 builder->fsCodeAppendf("\t\tvec2 gF = vec2(2.0*%s.x*duvdx.x - duvdx.
y,\n" |
| 572 "\t\t 2.0*%s.x*duvdy.x - duvdy.
y);\n", | 820 "\t\t 2.0*%s.x*duvdy.x - duvdy.
y);\n", |
| 573 fsName, fsName); | 821 fsName, fsName); |
| 574 builder->fsCodeAppendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsNa
me, fsName, | 822 builder->fsCodeAppendf("\t\tedgeAlpha = (%s.x*%s.x - %s.y);\n", fsNa
me, fsName, |
| 575 fsName); | 823 fsName); |
| 576 builder->fsCodeAppend("\t\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / do
t(gF, gF));\n"); | 824 builder->fsCodeAppend("\t\tedgeAlpha = sqrt(edgeAlpha*edgeAlpha / do
t(gF, gF));\n"); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 607 typedef GrEffect INHERITED; | 855 typedef GrEffect INHERITED; |
| 608 }; | 856 }; |
| 609 | 857 |
| 610 GR_DEFINE_EFFECT_TEST(HairQuadEdgeEffect); | 858 GR_DEFINE_EFFECT_TEST(HairQuadEdgeEffect); |
| 611 | 859 |
| 612 GrEffectRef* HairQuadEdgeEffect::TestCreate(SkMWCRandom* random, | 860 GrEffectRef* HairQuadEdgeEffect::TestCreate(SkMWCRandom* random, |
| 613 GrContext*, | 861 GrContext*, |
| 614 const GrDrawTargetCaps& caps, | 862 const GrDrawTargetCaps& caps, |
| 615 GrTexture*[]) { | 863 GrTexture*[]) { |
| 616 // Doesn't work without derivative instructions. | 864 // Doesn't work without derivative instructions. |
| 617 return caps.shaderDerivativeSupport() ? HairQuadEdgeEffect::Create() : NULL;
} | 865 return caps.shaderDerivativeSupport() ? HairQuadEdgeEffect::Create() : NULL; |
| 866 } |
| 618 | 867 |
| 619 /////////////////////////////////////////////////////////////////////////////// | 868 /////////////////////////////////////////////////////////////////////////////// |
| 620 | 869 |
| 621 /** | 870 /** |
| 622 * The output of this effect is a 1-pixel wide line. | 871 * The output of this effect is a 1-pixel wide line. |
| 623 * Input is 2D implicit device coord line eq (a*x + b*y +c = 0). 4th component u
nused. | 872 * Input is 2D implicit device coord line eq (a*x + b*y +c = 0). 4th component u
nused. |
| 624 */ | 873 */ |
| 625 class HairLineEdgeEffect : public GrEffect { | 874 class HairLineEdgeEffect : public GrEffect { |
| 626 public: | 875 public: |
| 627 | 876 |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 710 /////////////////////////////////////////////////////////////////////////////// | 959 /////////////////////////////////////////////////////////////////////////////// |
| 711 | 960 |
| 712 namespace { | 961 namespace { |
| 713 | 962 |
| 714 // position + edge | 963 // position + edge |
| 715 extern const GrVertexAttrib gHairlineAttribs[] = { | 964 extern const GrVertexAttrib gHairlineAttribs[] = { |
| 716 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBind
ing}, | 965 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBind
ing}, |
| 717 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin
g} | 966 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin
g} |
| 718 }; | 967 }; |
| 719 | 968 |
| 969 // Conic |
| 970 // position + ABCD + EF |
| 971 extern const GrVertexAttrib gConicVertexAttribs[] = { |
| 972 { kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBind
ing }, |
| 973 { kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin
g }, |
| 974 { kVec2f_GrVertexAttribType, 3*sizeof(GrPoint), kEffect_GrVertexAttribBindin
g } |
| 975 }; |
| 720 }; | 976 }; |
| 721 | 977 |
| 722 bool GrAAHairLinePathRenderer::createGeom( | 978 bool GrAAHairLinePathRenderer::createGeom( |
| 723 const SkPath& path, | 979 const SkPath& path, |
| 724 GrDrawTarget* target, | 980 GrDrawTarget* target, |
| 725 int* lineCnt, | 981 int* lineCnt, |
| 726 int* quadCnt, | 982 int* quadCnt, |
| 983 int* conicCnt, |
| 727 GrDrawTarget::AutoReleaseGeometry* arg, | 984 GrDrawTarget::AutoReleaseGeometry* arg, |
| 728 SkRect* devBounds) { | 985 SkRect* devBounds) { |
| 729 GrDrawState* drawState = target->drawState(); | 986 GrDrawState* drawState = target->drawState(); |
| 730 int rtHeight = drawState->getRenderTarget()->height(); | 987 int rtHeight = drawState->getRenderTarget()->height(); |
| 731 | 988 |
| 732 GrIRect devClipBounds; | 989 GrIRect devClipBounds; |
| 733 target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devC
lipBounds); | 990 target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devC
lipBounds); |
| 734 | 991 |
| 735 SkMatrix viewM = drawState->getViewMatrix(); | 992 SkMatrix viewM = drawState->getViewMatrix(); |
| 736 | 993 |
| 737 // All the vertices that we compute are within 1 of path control points with
the exception of | 994 // All the vertices that we compute are within 1 of path control points with
the exception of |
| 738 // one of the bounding vertices for each quad. The add_quads() function will
update the bounds | 995 // one of the bounding vertices for each quad. The add_quads() function will
update the bounds |
| 739 // for each quad added. | 996 // for each quad added. |
| 740 *devBounds = path.getBounds(); | 997 *devBounds = path.getBounds(); |
| 741 viewM.mapRect(devBounds); | 998 viewM.mapRect(devBounds); |
| 742 devBounds->outset(SK_Scalar1, SK_Scalar1); | 999 devBounds->outset(SK_Scalar1, SK_Scalar1); |
| 743 | 1000 |
| 744 PREALLOC_PTARRAY(128) lines; | 1001 PREALLOC_PTARRAY(128) lines; |
| 745 PREALLOC_PTARRAY(128) quads; | 1002 PREALLOC_PTARRAY(128) quads; |
| 1003 PREALLOC_PTARRAY(128) conics; |
| 746 IntArray qSubdivs; | 1004 IntArray qSubdivs; |
| 1005 FloatArray cWeights; |
| 747 *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds, | 1006 *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds, |
| 748 &lines, &quads, &qSubdivs); | 1007 &lines, &quads, &conics, &qSubdivs, &cWe
ights); |
| 749 | 1008 |
| 750 *lineCnt = lines.count() / 2; | 1009 *lineCnt = lines.count() / 2; |
| 751 int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt; | 1010 *conicCnt = conics.count() / 3; |
| 1011 int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt + |
| 1012 kVertsPerQuad * *conicCnt; |
| 752 | 1013 |
| 753 target->drawState()->setVertexAttribs<gHairlineAttribs>(SK_ARRAY_COUNT(gHair
lineAttribs)); | 1014 target->drawState()->setVertexAttribs<gConicVertexAttribs>(SK_ARRAY_COUNT(gC
onicVertexAttribs)); |
| 754 GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize()); | 1015 GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize()); |
| 755 | 1016 |
| 756 if (!arg->set(target, vertCnt, 0)) { | 1017 if (!arg->set(target, vertCnt, 0)) { |
| 757 return false; | 1018 return false; |
| 758 } | 1019 } |
| 759 | 1020 |
| 760 Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices()); | 1021 Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices()); |
| 761 | 1022 |
| 762 const SkMatrix* toDevice = NULL; | 1023 const SkMatrix* toDevice = NULL; |
| 763 const SkMatrix* toSrc = NULL; | 1024 const SkMatrix* toSrc = NULL; |
| 764 SkMatrix ivm; | 1025 SkMatrix ivm; |
| 765 | 1026 |
| 766 if (viewM.hasPerspective()) { | 1027 if (viewM.hasPerspective()) { |
| 767 if (viewM.invert(&ivm)) { | 1028 if (viewM.invert(&ivm)) { |
| 768 toDevice = &viewM; | 1029 toDevice = &viewM; |
| 769 toSrc = &ivm; | 1030 toSrc = &ivm; |
| 770 } | 1031 } |
| 771 } | 1032 } |
| 772 | 1033 |
| 773 for (int i = 0; i < *lineCnt; ++i) { | 1034 for (int i = 0; i < *lineCnt; ++i) { |
| 774 add_line(&lines[2*i], rtHeight, toSrc, &verts); | 1035 add_line(&lines[2*i], rtHeight, toSrc, &verts); |
| 775 } | 1036 } |
| 776 | 1037 |
| 777 int unsubdivQuadCnt = quads.count() / 3; | 1038 int unsubdivQuadCnt = quads.count() / 3; |
| 778 for (int i = 0; i < unsubdivQuadCnt; ++i) { | 1039 for (int i = 0; i < unsubdivQuadCnt; ++i) { |
| 779 GrAssert(qSubdivs[i] >= 0); | 1040 GrAssert(qSubdivs[i] >= 0); |
| 780 add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds); | 1041 add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds); |
| 781 } | 1042 } |
| 782 | 1043 |
| 1044 // Start Conics |
| 1045 for (int i = 0; i < *conicCnt; ++i) { |
| 1046 add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts, devBounds
); |
| 1047 } |
| 783 return true; | 1048 return true; |
| 784 } | 1049 } |
| 785 | 1050 |
| 786 bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path, | 1051 bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path, |
| 787 const SkStrokeRec& stroke, | 1052 const SkStrokeRec& stroke, |
| 788 const GrDrawTarget* target, | 1053 const GrDrawTarget* target, |
| 789 bool antiAlias) const { | 1054 bool antiAlias) const { |
| 790 if (!stroke.isHairlineStyle() || !antiAlias) { | 1055 if (!stroke.isHairlineStyle() || !antiAlias) { |
| 791 return false; | 1056 return false; |
| 792 } | 1057 } |
| 793 | 1058 |
| 794 static const uint32_t gReqDerivMask = SkPath::kCubic_SegmentMask | | 1059 static const uint32_t gReqDerivMask = SkPath::kCubic_SegmentMask | |
| 795 SkPath::kQuad_SegmentMask; | 1060 SkPath::kQuad_SegmentMask; |
| 796 if (!target->caps()->shaderDerivativeSupport() && | 1061 if (!target->caps()->shaderDerivativeSupport() && |
| 797 (gReqDerivMask & path.getSegmentMasks())) { | 1062 (gReqDerivMask & path.getSegmentMasks())) { |
| 798 return false; | 1063 return false; |
| 799 } | 1064 } |
| 800 return true; | 1065 return true; |
| 801 } | 1066 } |
| 802 | 1067 |
| 803 bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, | 1068 bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, |
| 804 const SkStrokeRec&, | 1069 const SkStrokeRec&, |
| 805 GrDrawTarget* target, | 1070 GrDrawTarget* target, |
| 806 bool antiAlias) { | 1071 bool antiAlias) { |
| 807 | 1072 |
| 808 int lineCnt; | 1073 int lineCnt; |
| 809 int quadCnt; | 1074 int quadCnt; |
| 1075 int conicCnt; |
| 810 GrDrawTarget::AutoReleaseGeometry arg; | 1076 GrDrawTarget::AutoReleaseGeometry arg; |
| 811 SkRect devBounds; | 1077 SkRect devBounds; |
| 812 | 1078 |
| 813 if (!this->createGeom(path, | 1079 if (!this->createGeom(path, |
| 814 target, | 1080 target, |
| 815 &lineCnt, | 1081 &lineCnt, |
| 816 &quadCnt, | 1082 &quadCnt, |
| 1083 &conicCnt, |
| 817 &arg, | 1084 &arg, |
| 818 &devBounds)) { | 1085 &devBounds)) { |
| 819 return false; | 1086 return false; |
| 820 } | 1087 } |
| 821 | 1088 |
| 822 GrDrawTarget::AutoStateRestore asr; | 1089 GrDrawTarget::AutoStateRestore asr; |
| 823 | 1090 |
| 824 // createGeom transforms the geometry to device space when the matrix does n
ot have | 1091 // createGeom transforms the geometry to device space when the matrix does n
ot have |
| 825 // perspective. | 1092 // perspective. |
| 826 if (target->getDrawState().getViewMatrix().hasPerspective()) { | 1093 if (target->getDrawState().getViewMatrix().hasPerspective()) { |
| 827 asr.set(target, GrDrawTarget::kPreserve_ASRInit); | 1094 asr.set(target, GrDrawTarget::kPreserve_ASRInit); |
| 828 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { | 1095 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { |
| 829 return false; | 1096 return false; |
| 830 } | 1097 } |
| 831 GrDrawState* drawState = target->drawState(); | 1098 GrDrawState* drawState = target->drawState(); |
| 832 | 1099 |
| 833 // TODO: See whether rendering lines as degenerate quads improves perf | 1100 // TODO: See whether rendering lines as degenerate quads improves perf |
| 834 // when we have a mix | 1101 // when we have a mix |
| 835 | 1102 |
| 836 enum { | 1103 enum { |
| 837 // the edge effects share this stage with glyph rendering | 1104 // the edge effects share this stage with glyph rendering |
| 838 // (kGlyphMaskStage in GrTextContext) && SW path rendering | 1105 // (kGlyphMaskStage in GrTextContext) && SW path rendering |
| 839 // (kPathMaskStage in GrSWMaskHelper) | 1106 // (kPathMaskStage in GrSWMaskHelper) |
| 840 kEdgeEffectStage = GrPaint::kTotalStages, | 1107 kEdgeEffectStage = GrPaint::kTotalStages, |
| 841 }; | 1108 }; |
| 842 static const int kEdgeAttrIndex = 1; | 1109 static const int kEdgeAttrIndex = 1; |
| 843 | 1110 |
| 844 GrEffectRef* hairLineEffect = HairLineEdgeEffect::Create(); | 1111 GrEffectRef* hairLineEffect = HairLineEdgeEffect::Create(); |
| 845 GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create(); | 1112 GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create(); |
| 1113 GrEffectRef* hairConicEffect = HairConicEdgeEffect::Create(); |
| 846 | 1114 |
| 847 // Check devBounds | 1115 // Check devBounds |
| 848 #if GR_DEBUG | 1116 #if GR_DEBUG |
| 849 SkRect tolDevBounds = devBounds; | 1117 SkRect tolDevBounds = devBounds; |
| 850 tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000); | 1118 tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000); |
| 851 SkRect actualBounds; | 1119 SkRect actualBounds; |
| 852 Vertex* verts = reinterpret_cast<Vertex*>(arg.vertices()); | 1120 Vertex* verts = reinterpret_cast<Vertex*>(arg.vertices()); |
| 853 int vCount = kVertsPerLineSeg * lineCnt + kVertsPerQuad * quadCnt; | 1121 int vCount = kVertsPerLineSeg * lineCnt + kVertsPerQuad * quadCnt + kVertsPe
rQuad * conicCnt; |
| 854 bool first = true; | 1122 bool first = true; |
| 855 for (int i = 0; i < vCount; ++i) { | 1123 for (int i = 0; i < vCount; ++i) { |
| 856 SkPoint pos = verts[i].fPos; | 1124 SkPoint pos = verts[i].fPos; |
| 857 // This is a hack to workaround the fact that we move some degenerate se
gments offscreen. | 1125 // This is a hack to workaround the fact that we move some degenerate se
gments offscreen. |
| 858 if (SK_ScalarMax == pos.fX) { | 1126 if (SK_ScalarMax == pos.fX) { |
| 859 continue; | 1127 continue; |
| 860 } | 1128 } |
| 861 drawState->getViewMatrix().mapPoints(&pos, 1); | 1129 drawState->getViewMatrix().mapPoints(&pos, 1); |
| 862 if (first) { | 1130 if (first) { |
| 863 actualBounds.set(pos.fX, pos.fY, pos.fX, pos.fY); | 1131 actualBounds.set(pos.fX, pos.fY, pos.fX, pos.fY); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 882 target->drawIndexed(kTriangles_GrPrimitiveType, | 1150 target->drawIndexed(kTriangles_GrPrimitiveType, |
| 883 kVertsPerLineSeg*lines, // startV | 1151 kVertsPerLineSeg*lines, // startV |
| 884 0, // startI | 1152 0, // startI |
| 885 kVertsPerLineSeg*n, // vCount | 1153 kVertsPerLineSeg*n, // vCount |
| 886 kIdxsPerLineSeg*n, | 1154 kIdxsPerLineSeg*n, |
| 887 &devBounds); // iCount | 1155 &devBounds); // iCount |
| 888 lines += n; | 1156 lines += n; |
| 889 } | 1157 } |
| 890 } | 1158 } |
| 891 | 1159 |
| 892 target->setIndexSourceToBuffer(fQuadsIndexBuffer); | 1160 { |
| 893 int quads = 0; | 1161 GrDrawState::AutoRestoreEffects are(drawState); |
| 894 drawState->addCoverageEffect(hairQuadEffect, kEdgeAttrIndex)->unref(); | 1162 target->setIndexSourceToBuffer(fQuadsIndexBuffer); |
| 895 while (quads < quadCnt) { | 1163 int quads = 0; |
| 896 int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer); | 1164 drawState->addCoverageEffect(hairQuadEffect, kEdgeAttrIndex)->unref(); |
| 897 target->drawIndexed(kTriangles_GrPrimitiveType, | 1165 while (quads < quadCnt) { |
| 898 4 * lineCnt + kVertsPerQuad*quads, // startV | 1166 int n = GrMin(quadCnt - quads, kNumQuadsInIdxBuffer); |
| 899 0, // startI | 1167 target->drawIndexed(kTriangles_GrPrimitiveType, |
| 900 kVertsPerQuad*n, // vCount | 1168 kVertsPerLineSeg * lineCnt + kVertsPerQuad*quads
, // startV |
| 901 kIdxsPerQuad*n, // iCount | 1169 0,
// startI |
| 902 &devBounds); | 1170 kVertsPerQuad*n,
// vCount |
| 903 quads += n; | 1171 kIdxsPerQuad*n,
// iCount |
| 1172 &devBounds); |
| 1173 quads += n; |
| 1174 } |
| 1175 } |
| 1176 |
| 1177 { |
| 1178 GrDrawState::AutoRestoreEffects are(drawState); |
| 1179 int conics = 0; |
| 1180 drawState->addCoverageEffect(hairConicEffect, 1, 2)->unref(); |
| 1181 while (conics < conicCnt) { |
| 1182 int n = GrMin(conicCnt - conics, kNumQuadsInIdxBuffer); |
| 1183 target->drawIndexed(kTriangles_GrPrimitiveType, |
| 1184 kVertsPerLineSeg*lineCnt + |
| 1185 kVertsPerQuad*(quadCnt + conics), // startV |
| 1186 0, // startI |
| 1187 kVertsPerQuad*n, // vCount |
| 1188 kIdxsPerQuad*n, // iCount |
| 1189 &devBounds); |
| 1190 conics += n; |
| 1191 } |
| 904 } | 1192 } |
| 905 target->resetIndexSource(); | 1193 target->resetIndexSource(); |
| 906 | 1194 |
| 907 return true; | 1195 return true; |
| 908 } | 1196 } |
| 1197 |
| OLD | NEW |