| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "GrAAHairLinePathRenderer.h" | 8 #include "GrAAHairLinePathRenderer.h" |
| 9 | 9 |
| 10 #include "GrContext.h" | 10 #include "GrContext.h" |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 #include "gl/GrGLEffect.h" | 22 #include "gl/GrGLEffect.h" |
| 23 #include "gl/GrGLSL.h" | 23 #include "gl/GrGLSL.h" |
| 24 | 24 |
| 25 namespace { | 25 namespace { |
| 26 // quadratics are rendered as 5-sided polys in order to bound the | 26 // quadratics are rendered as 5-sided polys in order to bound the |
| 27 // AA stroke around the center-curve. See comments in push_quad_index_buffer and | 27 // AA stroke around the center-curve. See comments in push_quad_index_buffer and |
| 28 // bloat_quad. Quadratics and conics share an index buffer | 28 // bloat_quad. Quadratics and conics share an index buffer |
| 29 static const int kVertsPerQuad = 5; | 29 static const int kVertsPerQuad = 5; |
| 30 static const int kIdxsPerQuad = 9; | 30 static const int kIdxsPerQuad = 9; |
| 31 | 31 |
| 32 static const int kVertsPerCubic = 4; |
| 33 static const int kIdxsPerCubic = 6; |
| 34 |
| 32 static const int kVertsPerLineSeg = 4; | 35 static const int kVertsPerLineSeg = 4; |
| 33 static const int kIdxsPerLineSeg = 6; | 36 static const int kIdxsPerLineSeg = 6; |
| 34 | 37 |
| 35 static const int kNumQuadsInIdxBuffer = 256; | 38 static const int kNumQuadsInIdxBuffer = 256; |
| 36 static const size_t kQuadIdxSBufize = kIdxsPerQuad * | 39 static const size_t kQuadIdxSBufize = kIdxsPerQuad * |
| 37 sizeof(uint16_t) * | 40 sizeof(uint16_t) * |
| 38 kNumQuadsInIdxBuffer; | 41 kNumQuadsInIdxBuffer; |
| 39 | 42 |
| 43 static const int kNumCubicsInIdxBuffer = 256; |
| 44 static const size_t kCubicIdxSBufize = kIdxsPerCubic * |
| 45 sizeof(uint16_t) * |
| 46 kNumCubicsInIdxBuffer; |
| 47 |
| 48 bool push_cubic_index_data(GrIndexBuffer* cIdxBuffer) { |
| 49 uint16_t* data = (uint16_t*) cIdxBuffer->lock(); |
| 50 bool tempData = NULL == data; |
| 51 if (tempData) { |
| 52 data = SkNEW_ARRAY(uint16_t, kNumCubicsInIdxBuffer * kIdxsPerCubic); |
| 53 } |
| 54 for (int i = 0; i < kNumCubicsInIdxBuffer; ++i) { |
| 55 |
| 56 int baseIdx = i * kIdxsPerCubic; |
| 57 uint16_t baseVert = (uint16_t)(i * kVertsPerCubic); |
| 58 |
| 59 data[0 + baseIdx] = baseVert + 0; |
| 60 data[1 + baseIdx] = baseVert + 1; |
| 61 data[2 + baseIdx] = baseVert + 2; |
| 62 data[3 + baseIdx] = baseVert + 2; |
| 63 data[4 + baseIdx] = baseVert + 3; |
| 64 data[5 + baseIdx] = baseVert + 0; |
| 65 } |
| 66 if (tempData) { |
| 67 bool ret = cIdxBuffer->updateData(data, kCubicIdxSBufize); |
| 68 delete[] data; |
| 69 return ret; |
| 70 } else { |
| 71 cIdxBuffer->unlock(); |
| 72 return true; |
| 73 } |
| 74 } |
| 75 |
| 40 bool push_quad_index_data(GrIndexBuffer* qIdxBuffer) { | 76 bool push_quad_index_data(GrIndexBuffer* qIdxBuffer) { |
| 41 uint16_t* data = (uint16_t*) qIdxBuffer->lock(); | 77 uint16_t* data = (uint16_t*) qIdxBuffer->lock(); |
| 42 bool tempData = NULL == data; | 78 bool tempData = NULL == data; |
| 43 if (tempData) { | 79 if (tempData) { |
| 44 data = SkNEW_ARRAY(uint16_t, kNumQuadsInIdxBuffer * kIdxsPerQuad); | 80 data = SkNEW_ARRAY(uint16_t, kNumQuadsInIdxBuffer * kIdxsPerQuad); |
| 45 } | 81 } |
| 46 for (int i = 0; i < kNumQuadsInIdxBuffer; ++i) { | 82 for (int i = 0; i < kNumQuadsInIdxBuffer; ++i) { |
| 47 | 83 |
| 48 // Each quadratic is rendered as a five sided polygon. This poly bounds | 84 // Each quadratic is rendered as a five sided polygon. This poly bounds |
| 49 // the quadratic's bounding triangle but has been expanded so that the | 85 // the quadratic's bounding triangle but has been expanded so that the |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 85 if (NULL == lIdxBuffer) { | 121 if (NULL == lIdxBuffer) { |
| 86 return NULL; | 122 return NULL; |
| 87 } | 123 } |
| 88 GrGpu* gpu = context->getGpu(); | 124 GrGpu* gpu = context->getGpu(); |
| 89 GrIndexBuffer* qIdxBuf = gpu->createIndexBuffer(kQuadIdxSBufize, false); | 125 GrIndexBuffer* qIdxBuf = gpu->createIndexBuffer(kQuadIdxSBufize, false); |
| 90 SkAutoTUnref<GrIndexBuffer> qIdxBuffer(qIdxBuf); | 126 SkAutoTUnref<GrIndexBuffer> qIdxBuffer(qIdxBuf); |
| 91 if (NULL == qIdxBuf || | 127 if (NULL == qIdxBuf || |
| 92 !push_quad_index_data(qIdxBuf)) { | 128 !push_quad_index_data(qIdxBuf)) { |
| 93 return NULL; | 129 return NULL; |
| 94 } | 130 } |
| 131 GrIndexBuffer* cIdxBuf = gpu->createIndexBuffer(kCubicIdxSBufize, false); |
| 132 SkAutoTUnref<GrIndexBuffer> cIdxBuffer(cIdxBuf); |
| 133 if (NULL == cIdxBuf || |
| 134 !push_cubic_index_data(cIdxBuf)) { |
| 135 return NULL; |
| 136 } |
| 95 return SkNEW_ARGS(GrAAHairLinePathRenderer, | 137 return SkNEW_ARGS(GrAAHairLinePathRenderer, |
| 96 (context, lIdxBuffer, qIdxBuf)); | 138 (context, lIdxBuffer, qIdxBuf, cIdxBuf)); |
| 97 } | 139 } |
| 98 | 140 |
| 99 GrAAHairLinePathRenderer::GrAAHairLinePathRenderer( | 141 GrAAHairLinePathRenderer::GrAAHairLinePathRenderer( |
| 100 const GrContext* context, | 142 const GrContext* context, |
| 101 const GrIndexBuffer* linesIndexBuffer, | 143 const GrIndexBuffer* linesIndexBuffer, |
| 102 const GrIndexBuffer* quadsIndexBuffer) { | 144 const GrIndexBuffer* quadsIndexBuffer, |
| 145 const GrIndexBuffer* cubicsIndexBuffer)
{ |
| 103 fLinesIndexBuffer = linesIndexBuffer; | 146 fLinesIndexBuffer = linesIndexBuffer; |
| 104 linesIndexBuffer->ref(); | 147 linesIndexBuffer->ref(); |
| 105 fQuadsIndexBuffer = quadsIndexBuffer; | 148 fQuadsIndexBuffer = quadsIndexBuffer; |
| 106 quadsIndexBuffer->ref(); | 149 quadsIndexBuffer->ref(); |
| 150 fCubicsIndexBuffer = cubicsIndexBuffer; |
| 151 cubicsIndexBuffer->ref(); |
| 107 } | 152 } |
| 108 | 153 |
| 109 GrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() { | 154 GrAAHairLinePathRenderer::~GrAAHairLinePathRenderer() { |
| 110 fLinesIndexBuffer->unref(); | 155 fLinesIndexBuffer->unref(); |
| 111 fQuadsIndexBuffer->unref(); | 156 fQuadsIndexBuffer->unref(); |
| 157 fCubicsIndexBuffer->unref(); |
| 112 } | 158 } |
| 113 | 159 |
| 114 namespace { | 160 namespace { |
| 115 | 161 |
| 116 typedef SkTArray<SkPoint, true> PtArray; | 162 typedef SkTArray<SkPoint, true> PtArray; |
| 117 #define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> | 163 #define PREALLOC_PTARRAY(N) SkSTArray<(N),SkPoint, true> |
| 118 typedef SkTArray<int, true> IntArray; | 164 typedef SkTArray<int, true> IntArray; |
| 119 typedef SkTArray<float, true> FloatArray; | 165 typedef SkTArray<float, true> FloatArray; |
| 120 | 166 |
| 121 // Takes 178th time of logf on Z600 / VC2010 | 167 // Takes 178th time of logf on Z600 / VC2010 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 135 GrAssert(get_float_exp(100.f) == 6); | 181 GrAssert(get_float_exp(100.f) == 6); |
| 136 GrAssert(get_float_exp(1000.f) == 9); | 182 GrAssert(get_float_exp(1000.f) == 9); |
| 137 GrAssert(get_float_exp(1024.f) == 10); | 183 GrAssert(get_float_exp(1024.f) == 10); |
| 138 GrAssert(get_float_exp(3000000.f) == 21); | 184 GrAssert(get_float_exp(3000000.f) == 21); |
| 139 } | 185 } |
| 140 #endif | 186 #endif |
| 141 const int* iptr = (const int*)&x; | 187 const int* iptr = (const int*)&x; |
| 142 return (((*iptr) & 0x7f800000) >> 23) - 127; | 188 return (((*iptr) & 0x7f800000) >> 23) - 127; |
| 143 } | 189 } |
| 144 | 190 |
| 191 //int chop_cubic_at_loop_intersection(const SkPoint src[4], SkPoint dst[10], SkS
calar k[3] = NULL, |
| 192 // SkScalar l[3] = NULL, SkScalar m[3] = NULL
); |
| 193 |
| 145 // Uses the max curvature function for quads to estimate | 194 // Uses the max curvature function for quads to estimate |
| 146 // where to chop the conic. If the max curvature is not | 195 // where to chop the conic. If the max curvature is not |
| 147 // found along the curve segment it will return 1 and | 196 // found along the curve segment it will return 1 and |
| 148 // dst[0] is the original conic. If it returns 2 the dst[0] | 197 // dst[0] is the original conic. If it returns 2 the dst[0] |
| 149 // and dst[1] are the two new conics. | 198 // and dst[1] are the two new conics. |
| 150 int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) { | 199 int split_conic(const SkPoint src[3], SkConic dst[2], const SkScalar weight) { |
| 151 SkScalar t = SkFindQuadMaxCurvature(src); | 200 SkScalar t = SkFindQuadMaxCurvature(src); |
| 152 if (t == 0) { | 201 if (t == 0) { |
| 153 if (dst) { | 202 if (dst) { |
| 154 dst[0].set(src, weight); | 203 dst[0].set(src, weight); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 172 int conicCnt = split_conic(src, dstTemp, weight); | 221 int conicCnt = split_conic(src, dstTemp, weight); |
| 173 if (2 == conicCnt) { | 222 if (2 == conicCnt) { |
| 174 int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW); | 223 int conicCnt2 = split_conic(dstTemp[0].fPts, dst, dstTemp[0].fW); |
| 175 conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dst
Temp[1].fW); | 224 conicCnt = conicCnt2 + split_conic(dstTemp[1].fPts, &dst[conicCnt2], dst
Temp[1].fW); |
| 176 } else { | 225 } else { |
| 177 dst[0] = dstTemp[0]; | 226 dst[0] = dstTemp[0]; |
| 178 } | 227 } |
| 179 return conicCnt; | 228 return conicCnt; |
| 180 } | 229 } |
| 181 | 230 |
| 231 int is_degen_cubic(const SkPoint p[4]) { |
| 232 static const SkScalar gDegenerateToLineTol = SK_Scalar1; |
| 233 static const SkScalar gDegenerateToLineTolSqd = |
| 234 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); |
| 235 |
| 236 if (p[0].distanceToSqd(p[3]) < gDegenerateToLineTolSqd && |
| 237 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { |
| 238 return 1; |
| 239 } |
| 240 |
| 241 // if the points are all close to being colinear |
| 242 SkScalar dsqd1= p[1].distanceToLineBetweenSqd(p[0], p[3]); |
| 243 SkScalar dsqd2= p[2].distanceToLineBetweenSqd(p[0], p[3]); |
| 244 if (dsqd1 < gDegenerateToLineTolSqd && dsqd2 < gDegenerateToLineTolSqd) { |
| 245 return 1; |
| 246 } |
| 247 |
| 248 return 0; |
| 249 |
| 250 } |
| 251 |
| 182 // returns 0 if quad/conic is degen or close to it | 252 // returns 0 if quad/conic is degen or close to it |
| 183 // in this case approx the path with lines | 253 // in this case approx the path with lines |
| 184 // otherwise returns 1 | 254 // otherwise returns 1 |
| 185 int is_degen_quad_or_conic(const SkPoint p[3]) { | 255 int is_degen_quad_or_conic(const SkPoint p[3]) { |
| 186 static const SkScalar gDegenerateToLineTol = SK_Scalar1; | 256 static const SkScalar gDegenerateToLineTol = SK_Scalar1; |
| 187 static const SkScalar gDegenerateToLineTolSqd = | 257 static const SkScalar gDegenerateToLineTolSqd = |
| 188 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); | 258 SkScalarMul(gDegenerateToLineTol, gDegenerateToLineTol); |
| 189 | 259 |
| 190 if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || | 260 if (p[0].distanceToSqd(p[1]) < gDegenerateToLineTolSqd || |
| 191 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { | 261 p[1].distanceToSqd(p[2]) < gDegenerateToLineTolSqd) { |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 262 * perspective, then in they are in src space. We do this because we will | 332 * perspective, then in they are in src space. We do this because we will |
| 263 * subdivide large quads to reduce over-fill. This subdivision has to be | 333 * subdivide large quads to reduce over-fill. This subdivision has to be |
| 264 * performed before applying the perspective matrix. | 334 * performed before applying the perspective matrix. |
| 265 */ | 335 */ |
| 266 int generate_lines_and_quads(const SkPath& path, | 336 int generate_lines_and_quads(const SkPath& path, |
| 267 const SkMatrix& m, | 337 const SkMatrix& m, |
| 268 const SkIRect& devClipBounds, | 338 const SkIRect& devClipBounds, |
| 269 PtArray* lines, | 339 PtArray* lines, |
| 270 PtArray* quads, | 340 PtArray* quads, |
| 271 PtArray* conics, | 341 PtArray* conics, |
| 342 PtArray* cubics, |
| 272 IntArray* quadSubdivCnts, | 343 IntArray* quadSubdivCnts, |
| 273 FloatArray* conicWeights) { | 344 FloatArray* conicWeights, |
| 345 FloatArray* cubicKLM) { |
| 274 SkPath::Iter iter(path, false); | 346 SkPath::Iter iter(path, false); |
| 275 | 347 |
| 276 int totalQuadCount = 0; | 348 int totalQuadCount = 0; |
| 277 SkRect bounds; | 349 SkRect bounds; |
| 278 SkIRect ibounds; | 350 SkIRect ibounds; |
| 279 | 351 |
| 280 bool persp = m.hasPerspective(); | 352 bool persp = m.hasPerspective(); |
| 281 | 353 |
| 282 for (;;) { | 354 for (;;) { |
| 283 GrPoint pathPts[4]; | 355 GrPoint pathPts[4]; |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 360 pts[0] = qPts[0]; | 432 pts[0] = qPts[0]; |
| 361 pts[1] = qPts[1]; | 433 pts[1] = qPts[1]; |
| 362 pts[2] = qPts[2]; | 434 pts[2] = qPts[2]; |
| 363 quadSubdivCnts->push_back() = subdiv; | 435 quadSubdivCnts->push_back() = subdiv; |
| 364 totalQuadCount += 1 << subdiv; | 436 totalQuadCount += 1 << subdiv; |
| 365 } | 437 } |
| 366 } | 438 } |
| 367 } | 439 } |
| 368 break; | 440 break; |
| 369 } | 441 } |
| 370 case SkPath::kCubic_Verb: | 442 case SkPath::kCubic_Verb: { |
| 443 SkPoint dst[10]; |
| 444 SkScalar klm[9]; |
| 445 SkScalar klm_rev[3]; |
| 371 m.mapPoints(devPts, pathPts, 4); | 446 m.mapPoints(devPts, pathPts, 4); |
| 372 bounds.setBounds(devPts, 4); | 447 int cubicCnt = GrPathUtils::chopCubicAtLoopIntersection(pathPts,
dst, klm, |
| 373 bounds.outset(SK_Scalar1, SK_Scalar1); | 448 klm_rev,
devPts); |
| 374 bounds.roundOut(&ibounds); | 449 for (int i = 0; i < cubicCnt; ++i) { |
| 375 if (SkIRect::Intersects(devClipBounds, ibounds)) { | 450 SkPoint* chopPnts = &dst[i*3]; |
| 376 PREALLOC_PTARRAY(32) q; | 451 m.mapPoints(devPts, chopPnts, 4); |
| 377 // we don't need a direction if we aren't constraining the s
ubdivision | 452 bounds.setBounds(devPts, 4); |
| 378 static const SkPath::Direction kDummyDir = SkPath::kCCW_Dire
ction; | 453 bounds.outset(SK_Scalar1, SK_Scalar1); |
| 379 // We convert cubics to quadratics (for now). | 454 bounds.roundOut(&ibounds); |
| 380 // In perspective have to do conversion in src space. | 455 if (SkIRect::Intersects(devClipBounds, ibounds)) { |
| 381 if (persp) { | 456 if (is_degen_cubic(devPts)) { |
| 382 SkScalar tolScale = | 457 SkPoint* pts = lines->push_back_n(6); |
| 383 GrPathUtils::scaleToleranceToSrc(SK_Scalar1, m, | 458 pts[0] = devPts[0]; |
| 384 path.getBounds()); | 459 pts[1] = devPts[1]; |
| 385 GrPathUtils::convertCubicToQuads(pathPts, tolScale, fals
e, kDummyDir, &q); | 460 pts[2] = devPts[1]; |
| 386 } else { | 461 pts[3] = devPts[2]; |
| 387 GrPathUtils::convertCubicToQuads(devPts, SK_Scalar1, fal
se, kDummyDir, &q); | 462 pts[4] = devPts[2]; |
| 388 } | 463 pts[5] = devPts[3]; |
| 389 for (int i = 0; i < q.count(); i += 3) { | |
| 390 SkPoint* qInDevSpace; | |
| 391 // bounds has to be calculated in device space, but q is | |
| 392 // in src space when there is perspective. | |
| 393 if (persp) { | |
| 394 m.mapPoints(devPts, &q[i], 3); | |
| 395 bounds.setBounds(devPts, 3); | |
| 396 qInDevSpace = devPts; | |
| 397 } else { | 464 } else { |
| 398 bounds.setBounds(&q[i], 3); | 465 // when in perspective keep conics in src space |
| 399 qInDevSpace = &q[i]; | 466 SkPoint* cPts = persp ? chopPnts : devPts; |
| 400 } | 467 SkPoint* pts = cubics->push_back_n(4); |
| 401 bounds.outset(SK_Scalar1, SK_Scalar1); | 468 pts[0] = cPts[0]; |
| 402 bounds.roundOut(&ibounds); | 469 pts[1] = cPts[1]; |
| 403 if (SkIRect::Intersects(devClipBounds, ibounds)) { | 470 pts[2] = cPts[2]; |
| 404 int subdiv = num_quad_subdivs(qInDevSpace); | 471 pts[3] = cPts[3]; |
| 405 GrAssert(subdiv >= -1); | 472 SkScalar* klms = cubicKLM->push_back_n(9); |
| 406 if (-1 == subdiv) { | 473 // set sub sections klm to equal klm of whole curve
and |
| 407 SkPoint* pts = lines->push_back_n(4); | 474 // flip the signs of k, l if needed |
| 408 // lines should always be in device coords | 475 memcpy(klms, klm, 9 * sizeof(SkScalar)); |
| 409 pts[0] = qInDevSpace[0]; | 476 for (int j = 0; j < 6; ++j) { |
| 410 pts[1] = qInDevSpace[1]; | 477 klms[j] *= klm_rev[i]; |
| 411 pts[2] = qInDevSpace[1]; | |
| 412 pts[3] = qInDevSpace[2]; | |
| 413 } else { | |
| 414 SkPoint* pts = quads->push_back_n(3); | |
| 415 // q is already in src space when there is no | |
| 416 // perspective and dev coords otherwise. | |
| 417 pts[0] = q[0 + i]; | |
| 418 pts[1] = q[1 + i]; | |
| 419 pts[2] = q[2 + i]; | |
| 420 quadSubdivCnts->push_back() = subdiv; | |
| 421 totalQuadCount += 1 << subdiv; | |
| 422 } | 478 } |
| 423 } | 479 } |
| 424 } | 480 } |
| 425 } | 481 } |
| 426 break; | 482 break; |
| 483 } |
| 427 case SkPath::kClose_Verb: | 484 case SkPath::kClose_Verb: |
| 428 break; | 485 break; |
| 429 case SkPath::kDone_Verb: | 486 case SkPath::kDone_Verb: |
| 430 return totalQuadCount; | 487 return totalQuadCount; |
| 431 } | 488 } |
| 432 } | 489 } |
| 433 } | 490 } |
| 434 | 491 |
| 435 struct Vertex { | 492 struct Vertex { |
| 436 GrPoint fPos; | 493 GrPoint fPos; |
| 437 union { | 494 union { |
| 438 struct { | 495 struct { |
| 439 SkScalar fA; | 496 SkScalar fA; |
| 440 SkScalar fB; | 497 SkScalar fB; |
| 441 SkScalar fC; | 498 SkScalar fC; |
| 442 } fLine; | 499 } fLine; |
| 443 struct { | 500 struct { |
| 444 SkScalar fK; | 501 SkScalar fK; |
| 445 SkScalar fL; | 502 SkScalar fL; |
| 446 SkScalar fM; | 503 SkScalar fM; |
| 447 } fConic; | 504 } fBezier; |
| 448 GrVec fQuadCoord; | 505 GrVec fQuadCoord; |
| 449 struct { | 506 struct { |
| 450 SkScalar fBogus[4]; | 507 SkScalar fBogus[4]; |
| 451 }; | 508 }; |
| 452 }; | 509 }; |
| 453 }; | 510 }; |
| 454 | 511 |
| 455 GR_STATIC_ASSERT(sizeof(Vertex) == 3 * sizeof(GrPoint)); | 512 GR_STATIC_ASSERT(sizeof(Vertex) == 3 * sizeof(GrPoint)); |
| 456 | 513 |
| 457 void intersect_lines(const SkPoint& ptA, const SkVector& normA, | 514 void intersect_lines(const SkPoint& ptA, const SkVector& normA, |
| (...skipping 13 matching lines...) Expand all Loading... |
| 471 result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW); | 528 result->fY = SkScalarMul(lineAW, normB.fX) - SkScalarMul(normA.fX, lineBW); |
| 472 result->fY = SkScalarMul(result->fY, wInv); | 529 result->fY = SkScalarMul(result->fY, wInv); |
| 473 } | 530 } |
| 474 | 531 |
| 475 void set_uv_quad(const SkPoint qpts[3], Vertex verts[kVertsPerQuad]) { | 532 void set_uv_quad(const SkPoint qpts[3], Vertex verts[kVertsPerQuad]) { |
| 476 // this should be in the src space, not dev coords, when we have perspective | 533 // this should be in the src space, not dev coords, when we have perspective |
| 477 GrPathUtils::QuadUVMatrix DevToUV(qpts); | 534 GrPathUtils::QuadUVMatrix DevToUV(qpts); |
| 478 DevToUV.apply<kVertsPerQuad, sizeof(Vertex), sizeof(GrPoint)>(verts); | 535 DevToUV.apply<kVertsPerQuad, sizeof(Vertex), sizeof(GrPoint)>(verts); |
| 479 } | 536 } |
| 480 | 537 |
| 538 // Set verts to be bounding box around the control points cpts bloated |
| 539 // out by 1 in each direcition |
| 540 void bloat_cubic(const SkPoint cpts[4], const SkMatrix* toDevice, |
| 541 const SkMatrix* toSrc, Vertex verts[kVertsPerCubic], |
| 542 SkRect* devBounds) { |
| 543 GrAssert(!toDevice == !toSrc); |
| 544 // original cubic is specified by quad a,b,c,d |
| 545 SkPoint a = cpts[0]; |
| 546 SkPoint b = cpts[1]; |
| 547 SkPoint c = cpts[2]; |
| 548 SkPoint d = cpts[3]; |
| 549 |
| 550 if (toDevice) { |
| 551 toDevice->mapPoints(&a, 1); |
| 552 toDevice->mapPoints(&b, 1); |
| 553 toDevice->mapPoints(&c, 1); |
| 554 toDevice->mapPoints(&d, 1); |
| 555 } |
| 556 |
| 557 SkScalar minX = cpts[0].fX; |
| 558 SkScalar maxX = cpts[0].fX; |
| 559 SkScalar minY = cpts[0].fY; |
| 560 SkScalar maxY = cpts[0].fY; |
| 561 |
| 562 for (int i = 1; i < 4; ++i) { |
| 563 minX = SkMinScalar(minX, cpts[i].fX); |
| 564 maxX = SkMaxScalar(maxX, cpts[i].fX); |
| 565 minY = SkMinScalar(minY, cpts[i].fY); |
| 566 maxY = SkMaxScalar(maxY, cpts[i].fY); |
| 567 } |
| 568 |
| 569 minX -= 1.0f; |
| 570 maxX += 1.0f; |
| 571 minY -= 1.0f; |
| 572 maxY += 1.0f; |
| 573 |
| 574 Vertex& a1 = verts[0]; |
| 575 Vertex& b1 = verts[1]; |
| 576 Vertex& c1 = verts[2]; |
| 577 Vertex& d1 = verts[3]; |
| 578 |
| 579 a1.fPos.fX = minX; |
| 580 a1.fPos.fY = minY; |
| 581 b1.fPos.fX = maxX; |
| 582 b1.fPos.fY = minY; |
| 583 c1.fPos.fX = maxX; |
| 584 c1.fPos.fY = maxY; |
| 585 d1.fPos.fX = minX; |
| 586 d1.fPos.fY = maxY; |
| 587 |
| 588 devBounds->growToInclude(a1.fPos.fX, a1.fPos.fY); |
| 589 devBounds->growToInclude(b1.fPos.fX, b1.fPos.fY); |
| 590 devBounds->growToInclude(c1.fPos.fX, c1.fPos.fY); |
| 591 devBounds->growToInclude(d1.fPos.fX, d1.fPos.fY); |
| 592 |
| 593 if (toSrc) { |
| 594 toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(Vertex), kVertsPerCubi
c); |
| 595 } |
| 596 } |
| 597 |
| 481 void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, | 598 void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, |
| 482 const SkMatrix* toSrc, Vertex verts[kVertsPerQuad], | 599 const SkMatrix* toSrc, Vertex verts[kVertsPerQuad], |
| 483 SkRect* devBounds) { | 600 SkRect* devBounds) { |
| 484 GrAssert(!toDevice == !toSrc); | 601 GrAssert(!toDevice == !toSrc); |
| 485 // original quad is specified by tri a,b,c | 602 // original quad is specified by tri a,b,c |
| 486 SkPoint a = qpts[0]; | 603 SkPoint a = qpts[0]; |
| 487 SkPoint b = qpts[1]; | 604 SkPoint b = qpts[1]; |
| 488 SkPoint c = qpts[2]; | 605 SkPoint c = qpts[2]; |
| 489 | 606 |
| 490 if (toDevice) { | 607 if (toDevice) { |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 577 k[2] = (p[2].fX - p[0].fX) * p[0].fY - (p[2].fY - p[0].fY) * p[0].fX; | 694 k[2] = (p[2].fX - p[0].fX) * p[0].fY - (p[2].fY - p[0].fY) * p[0].fX; |
| 578 | 695 |
| 579 // scale the max absolute value of coeffs to 10 | 696 // scale the max absolute value of coeffs to 10 |
| 580 SkScalar scale = 0.0f; | 697 SkScalar scale = 0.0f; |
| 581 for (int i = 0; i < 3; ++i) { | 698 for (int i = 0; i < 3; ++i) { |
| 582 scale = SkMaxScalar(scale, SkScalarAbs(k[i])); | 699 scale = SkMaxScalar(scale, SkScalarAbs(k[i])); |
| 583 scale = SkMaxScalar(scale, SkScalarAbs(l[i])); | 700 scale = SkMaxScalar(scale, SkScalarAbs(l[i])); |
| 584 scale = SkMaxScalar(scale, SkScalarAbs(m[i])); | 701 scale = SkMaxScalar(scale, SkScalarAbs(m[i])); |
| 585 } | 702 } |
| 586 GrAssert(scale > 0); | 703 GrAssert(scale > 0); |
| 587 scale /= 10.0f; | 704 scale = 10.0f / scale; |
| 588 k[0] /= scale; | 705 k[0] *= scale; |
| 589 k[1] /= scale; | 706 k[1] *= scale; |
| 590 k[2] /= scale; | 707 k[2] *= scale; |
| 591 l[0] /= scale; | 708 l[0] *= scale; |
| 592 l[1] /= scale; | 709 l[1] *= scale; |
| 593 l[2] /= scale; | 710 l[2] *= scale; |
| 594 m[0] /= scale; | 711 m[0] *= scale; |
| 595 m[1] /= scale; | 712 m[1] *= scale; |
| 596 m[2] /= scale; | 713 m[2] *= scale; |
| 597 } | 714 } |
| 598 | 715 |
| 599 // Equations based off of Loop-Blinn Quadratic GPU Rendering | 716 // Equations based off of Loop-Blinn Quadratic GPU Rendering |
| 600 // Input Parametric: | 717 // Input Parametric: |
| 601 // 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) | 718 // 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) |
| 602 // Output Implicit: | 719 // Output Implicit: |
| 603 // f(x, y, w) = f(P) = K^2 - LM | 720 // f(x, y, w) = f(P) = K^2 - LM |
| 604 // K = dot(k, P), L = dot(l, P), M = dot(m, P) | 721 // K = dot(k, P), L = dot(l, P), M = dot(m, P) |
| 605 // k, l, m are calculated in function calc_conic_klm | 722 // k, l, m are calculated in function calc_conic_klm |
| 606 void set_conic_coeffs(const SkPoint p[3], Vertex verts[kVertsPerQuad], const flo
at weight) { | 723 void set_conic_klm(const SkPoint p[3], Vertex verts[kVertsPerQuad], const float
weight) { |
| 607 SkScalar k[3]; | 724 SkScalar k[3]; |
| 608 SkScalar l[3]; | 725 SkScalar l[3]; |
| 609 SkScalar m[3]; | 726 SkScalar m[3]; |
| 610 | 727 |
| 611 calc_conic_klm(p, weight, k, l, m); | 728 calc_conic_klm(p, weight, k, l, m); |
| 612 | 729 |
| 613 for (int i = 0; i < kVertsPerQuad; ++i) { | 730 for (int i = 0; i < kVertsPerQuad; ++i) { |
| 614 const SkPoint pnt = verts[i].fPos; | 731 const SkPoint pnt = verts[i].fPos; |
| 615 verts[i].fConic.fK = pnt.fX * k[0] + pnt.fY * k[1] + k[2]; | 732 verts[i].fBezier.fK = pnt.fX * k[0] + pnt.fY * k[1] + k[2]; |
| 616 verts[i].fConic.fL = pnt.fX * l[0] + pnt.fY * l[1] + l[2]; | 733 verts[i].fBezier.fL = pnt.fX * l[0] + pnt.fY * l[1] + l[2]; |
| 617 verts[i].fConic.fM = pnt.fX * m[0] + pnt.fY * m[1] + m[2]; | 734 verts[i].fBezier.fM = pnt.fX * m[0] + pnt.fY * m[1] + m[2]; |
| 618 } | 735 } |
| 619 } | 736 } |
| 620 | 737 |
| 738 void set_cubic_klm(const SkPoint p[4], Vertex verts[kVertsPerCubic], const SkSca
lar klm[9]) { |
| 739 for (int i = 0; i < kVertsPerCubic; ++i) { |
| 740 const SkPoint pnt = verts[i].fPos; |
| 741 verts[i].fBezier.fK = pnt.fX * klm[0] + pnt.fY * klm[1] + klm[2]; |
| 742 verts[i].fBezier.fL = pnt.fX * klm[3] + pnt.fY * klm[4] + klm[5]; |
| 743 verts[i].fBezier.fM = pnt.fX * klm[6] + pnt.fY * klm[7] + klm[8]; |
| 744 } |
| 745 } |
| 746 |
| 747 void add_cubics(const SkPoint p[3], |
| 748 const SkScalar klm[9], |
| 749 const SkMatrix* toDevice, |
| 750 const SkMatrix* toSrc, |
| 751 Vertex** vert, |
| 752 SkRect* devBounds) { |
| 753 bloat_cubic(p, toDevice, toSrc, *vert, devBounds); |
| 754 set_cubic_klm(p, *vert, klm); |
| 755 *vert += kVertsPerCubic; |
| 756 } |
| 757 |
| 621 void add_conics(const SkPoint p[3], | 758 void add_conics(const SkPoint p[3], |
| 622 float weight, | 759 float weight, |
| 623 const SkMatrix* toDevice, | 760 const SkMatrix* toDevice, |
| 624 const SkMatrix* toSrc, | 761 const SkMatrix* toSrc, |
| 625 Vertex** vert, | 762 Vertex** vert, |
| 626 SkRect* devBounds) { | 763 SkRect* devBounds) { |
| 627 bloat_quad(p, toDevice, toSrc, *vert, devBounds); | 764 bloat_quad(p, toDevice, toSrc, *vert, devBounds); |
| 628 set_conic_coeffs(p, *vert, weight); | 765 set_conic_klm(p, *vert, weight); |
| 629 *vert += kVertsPerQuad; | 766 *vert += kVertsPerQuad; |
| 630 } | 767 } |
| 631 | 768 |
| 632 void add_quads(const SkPoint p[3], | 769 void add_quads(const SkPoint p[3], |
| 633 int subdiv, | 770 int subdiv, |
| 634 const SkMatrix* toDevice, | 771 const SkMatrix* toDevice, |
| 635 const SkMatrix* toSrc, | 772 const SkMatrix* toSrc, |
| 636 Vertex** vert, | 773 Vertex** vert, |
| 637 SkRect* devBounds) { | 774 SkRect* devBounds) { |
| 638 GrAssert(subdiv >= 0); | 775 GrAssert(subdiv >= 0); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 685 (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax); | 822 (*vert)[2].fPos.set(SK_ScalarMax, SK_ScalarMax); |
| 686 (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax); | 823 (*vert)[3].fPos.set(SK_ScalarMax, SK_ScalarMax); |
| 687 } | 824 } |
| 688 | 825 |
| 689 *vert += kVertsPerLineSeg; | 826 *vert += kVertsPerLineSeg; |
| 690 } | 827 } |
| 691 | 828 |
| 692 } | 829 } |
| 693 | 830 |
| 694 /** | 831 /** |
| 832 * Shader is based off of "Resolution Independent Curve Rendering using |
| 833 * Programmable Graphics Hardware" by Loop and Blinn. |
| 834 * The output of this effect is a hairline edge for non rational cubics. |
| 835 * Cubics are specified by implicit equation K^3 - LM. |
| 836 * K, L, and M, are the first three values of the vertex attribute, |
| 837 * the fourth value is not used. Distance is calculated using a |
| 838 * first order approximation from the taylor series. |
| 839 * Coverage is max(0, 1-distance). |
| 840 */ |
| 841 class HairCubicEdgeEffect : public GrEffect { |
| 842 public: |
| 843 static GrEffectRef* Create() { |
| 844 GR_CREATE_STATIC_EFFECT(gHairCubicEdgeEffect, HairCubicEdgeEffect, ()); |
| 845 gHairCubicEdgeEffect->ref(); |
| 846 return gHairCubicEdgeEffect; |
| 847 } |
| 848 |
| 849 virtual ~HairCubicEdgeEffect() {} |
| 850 |
| 851 static const char* Name() { return "HairCubicEdge"; } |
| 852 |
| 853 virtual void getConstantColorComponents(GrColor* color, |
| 854 uint32_t* validFlags) const SK_OVERR
IDE { |
| 855 *validFlags = 0; |
| 856 } |
| 857 |
| 858 virtual const GrBackendEffectFactory& getFactory() const SK_OVERRIDE { |
| 859 return GrTBackendEffectFactory<HairCubicEdgeEffect>::getInstance(); |
| 860 } |
| 861 |
| 862 class GLEffect : public GrGLEffect { |
| 863 public: |
| 864 GLEffect(const GrBackendEffectFactory& factory, const GrDrawEffect&) |
| 865 : INHERITED (factory) {} |
| 866 |
| 867 virtual void emitCode(GrGLShaderBuilder* builder, |
| 868 const GrDrawEffect& drawEffect, |
| 869 EffectKey key, |
| 870 const char* outputColor, |
| 871 const char* inputColor, |
| 872 const TextureSamplerArray& samplers) SK_OVERRIDE { |
| 873 const char *vsName, *fsName; |
| 874 |
| 875 SkAssertResult(builder->enableFeature( |
| 876 GrGLShaderBuilder::kStandardDerivatives_GLSLFeature)); |
| 877 builder->addVarying(kVec4f_GrSLType, "CubicCoeffs", |
| 878 &vsName, &fsName); |
| 879 const SkString* attr0Name = |
| 880 builder->getEffectAttributeName(drawEffect.getVertexAttribIndice
s()[0]); |
| 881 builder->vsCodeAppendf("\t%s = %s;\n", vsName, attr0Name->c_str()); |
| 882 |
| 883 builder->fsCodeAppend("\t\tfloat edgeAlpha;\n"); |
| 884 |
| 885 builder->fsCodeAppendf("\t\tvec3 dklmdx = dFdx(%s.xyz);\n", fsName); |
| 886 builder->fsCodeAppendf("\t\tvec3 dklmdy = dFdy(%s.xyz);\n", fsName); |
| 887 builder->fsCodeAppendf("\t\tfloat dfdx =\n" |
| 888 "\t\t3.0*%s.x*%s.x*dklmdx.x - %s.y*dklmdx.z -
%s.z*dklmdx.y;\n", |
| 889 fsName, fsName, fsName, fsName); |
| 890 builder->fsCodeAppendf("\t\tfloat dfdy =\n" |
| 891 "\t\t3.0*%s.x*%s.x*dklmdy.x - %s.y*dklmdy.z -
%s.z*dklmdy.y;\n", |
| 892 fsName, fsName, fsName, fsName); |
| 893 builder->fsCodeAppend("\t\tvec2 gF = vec2(dfdx, dfdy);\n"); |
| 894 builder->fsCodeAppend("\t\tfloat gFM = sqrt(dot(gF, gF));\n"); |
| 895 builder->fsCodeAppendf("\t\tfloat func = abs(%s.x*%s.x*%s.x - %s.y*%
s.z);\n", |
| 896 fsName, fsName, fsName, fsName, fsName); |
| 897 builder->fsCodeAppend("\t\tedgeAlpha = func / gFM;\n"); |
| 898 builder->fsCodeAppend("\t\tedgeAlpha = max(1.0 - edgeAlpha, 0.0);\n"
); |
| 899 // Add line below for smooth cubic ramp |
| 900 // builder->fsCodeAppend("\t\tedgeAlpha = edgeAlpha*edgeAlpha*(3.0-2
.0*edgeAlpha);\n"); |
| 901 |
| 902 SkString modulate; |
| 903 GrGLSLModulatef<4>(&modulate, inputColor, "edgeAlpha"); |
| 904 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, modulate.c_str()
); |
| 905 } |
| 906 |
| 907 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrG
LCaps&) { |
| 908 return 0x0; |
| 909 } |
| 910 |
| 911 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_
OVERRIDE {} |
| 912 |
| 913 private: |
| 914 typedef GrGLEffect INHERITED; |
| 915 }; |
| 916 |
| 917 private: |
| 918 HairCubicEdgeEffect() { |
| 919 this->addVertexAttrib(kVec4f_GrSLType); |
| 920 } |
| 921 |
| 922 virtual bool onIsEqual(const GrEffect& other) const SK_OVERRIDE { |
| 923 return true; |
| 924 } |
| 925 |
| 926 GR_DECLARE_EFFECT_TEST; |
| 927 |
| 928 typedef GrEffect INHERITED; |
| 929 }; |
| 930 /** |
| 695 * Shader is based off of Loop-Blinn Quadratic GPU Rendering | 931 * Shader is based off of Loop-Blinn Quadratic GPU Rendering |
| 696 * The output of this effect is a hairline edge for conics. | 932 * The output of this effect is a hairline edge for conics. |
| 697 * Conics specified by implicit equation K^2 - LM. | 933 * Conics specified by implicit equation K^2 - LM. |
| 698 * K, L, and M, are the first three values of the vertex attribute, | 934 * K, L, and M, are the first three values of the vertex attribute, |
| 699 * the fourth value is not used. Distance is calculated using a | 935 * the fourth value is not used. Distance is calculated using a |
| 700 * first order approximation from the taylor series. | 936 * first order approximation from the taylor series. |
| 701 * Coverage is max(0, 1-distance). | 937 * Coverage is max(0, 1-distance). |
| 702 */ | 938 */ |
| 703 | 939 |
| 704 /** | 940 /** |
| (...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1033 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin
g} | 1269 {kVec4f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBindin
g} |
| 1034 }; | 1270 }; |
| 1035 }; | 1271 }; |
| 1036 | 1272 |
| 1037 bool GrAAHairLinePathRenderer::createGeom( | 1273 bool GrAAHairLinePathRenderer::createGeom( |
| 1038 const SkPath& path, | 1274 const SkPath& path, |
| 1039 GrDrawTarget* target, | 1275 GrDrawTarget* target, |
| 1040 int* lineCnt, | 1276 int* lineCnt, |
| 1041 int* quadCnt, | 1277 int* quadCnt, |
| 1042 int* conicCnt, | 1278 int* conicCnt, |
| 1279 int* cubicCnt, |
| 1043 GrDrawTarget::AutoReleaseGeometry* arg, | 1280 GrDrawTarget::AutoReleaseGeometry* arg, |
| 1044 SkRect* devBounds) { | 1281 SkRect* devBounds) { |
| 1045 GrDrawState* drawState = target->drawState(); | 1282 GrDrawState* drawState = target->drawState(); |
| 1046 int rtHeight = drawState->getRenderTarget()->height(); | 1283 int rtHeight = drawState->getRenderTarget()->height(); |
| 1047 | 1284 |
| 1048 SkIRect devClipBounds; | 1285 SkIRect devClipBounds; |
| 1049 target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devC
lipBounds); | 1286 target->getClip()->getConservativeBounds(drawState->getRenderTarget(), &devC
lipBounds); |
| 1050 | 1287 |
| 1051 SkMatrix viewM = drawState->getViewMatrix(); | 1288 SkMatrix viewM = drawState->getViewMatrix(); |
| 1052 | 1289 |
| 1053 // All the vertices that we compute are within 1 of path control points with
the exception of | 1290 // All the vertices that we compute are within 1 of path control points with
the exception of |
| 1054 // one of the bounding vertices for each quad. The add_quads() function will
update the bounds | 1291 // one of the bounding vertices for each quad. The add_quads() function will
update the bounds |
| 1055 // for each quad added. | 1292 // for each quad added. |
| 1056 *devBounds = path.getBounds(); | 1293 *devBounds = path.getBounds(); |
| 1057 viewM.mapRect(devBounds); | 1294 viewM.mapRect(devBounds); |
| 1058 devBounds->outset(SK_Scalar1, SK_Scalar1); | 1295 devBounds->outset(SK_Scalar1, SK_Scalar1); |
| 1059 | 1296 |
| 1060 PREALLOC_PTARRAY(128) lines; | 1297 PREALLOC_PTARRAY(128) lines; |
| 1061 PREALLOC_PTARRAY(128) quads; | 1298 PREALLOC_PTARRAY(128) quads; |
| 1062 PREALLOC_PTARRAY(128) conics; | 1299 PREALLOC_PTARRAY(128) conics; |
| 1300 PREALLOC_PTARRAY(128) cubics; |
| 1063 IntArray qSubdivs; | 1301 IntArray qSubdivs; |
| 1064 FloatArray cWeights; | 1302 FloatArray cWeights; |
| 1303 FloatArray cubicKLM; |
| 1065 *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds, | 1304 *quadCnt = generate_lines_and_quads(path, viewM, devClipBounds, |
| 1066 &lines, &quads, &conics, &qSubdivs, &cWe
ights); | 1305 &lines, &quads, &conics, &cubics, |
| 1306 &qSubdivs, &cWeights, &cubicKLM); |
| 1067 | 1307 |
| 1068 *lineCnt = lines.count() / 2; | 1308 *lineCnt = lines.count() / 2; |
| 1069 *conicCnt = conics.count() / 3; | 1309 *conicCnt = conics.count() / 3; |
| 1310 *cubicCnt = cubics.count() / 4; |
| 1070 int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt + | 1311 int vertCnt = kVertsPerLineSeg * *lineCnt + kVertsPerQuad * *quadCnt + |
| 1071 kVertsPerQuad * *conicCnt; | 1312 kVertsPerQuad * *conicCnt + kVertsPerCubic * *cubicCnt; |
| 1072 | 1313 |
| 1073 target->drawState()->setVertexAttribs<gHairlineAttribs>(SK_ARRAY_COUNT(gHair
lineAttribs)); | 1314 target->drawState()->setVertexAttribs<gHairlineAttribs>(SK_ARRAY_COUNT(gHair
lineAttribs)); |
| 1074 GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize()); | 1315 GrAssert(sizeof(Vertex) == target->getDrawState().getVertexSize()); |
| 1075 | 1316 |
| 1076 if (!arg->set(target, vertCnt, 0)) { | 1317 if (!arg->set(target, vertCnt, 0)) { |
| 1077 return false; | 1318 return false; |
| 1078 } | 1319 } |
| 1079 | 1320 |
| 1080 Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices()); | 1321 Vertex* verts = reinterpret_cast<Vertex*>(arg->vertices()); |
| 1081 | 1322 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1093 for (int i = 0; i < *lineCnt; ++i) { | 1334 for (int i = 0; i < *lineCnt; ++i) { |
| 1094 add_line(&lines[2*i], rtHeight, toSrc, &verts); | 1335 add_line(&lines[2*i], rtHeight, toSrc, &verts); |
| 1095 } | 1336 } |
| 1096 | 1337 |
| 1097 int unsubdivQuadCnt = quads.count() / 3; | 1338 int unsubdivQuadCnt = quads.count() / 3; |
| 1098 for (int i = 0; i < unsubdivQuadCnt; ++i) { | 1339 for (int i = 0; i < unsubdivQuadCnt; ++i) { |
| 1099 GrAssert(qSubdivs[i] >= 0); | 1340 GrAssert(qSubdivs[i] >= 0); |
| 1100 add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds); | 1341 add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds); |
| 1101 } | 1342 } |
| 1102 | 1343 |
| 1103 // Start Conics | |
| 1104 for (int i = 0; i < *conicCnt; ++i) { | 1344 for (int i = 0; i < *conicCnt; ++i) { |
| 1105 add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts, devBounds
); | 1345 add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts, devBounds
); |
| 1106 } | 1346 } |
| 1347 |
| 1348 for (int i = 0; i < *cubicCnt; ++i) { |
| 1349 add_cubics(&cubics[4*i], &cubicKLM[9*i], toDevice, toSrc, &verts, devBou
nds); |
| 1350 } |
| 1107 return true; | 1351 return true; |
| 1108 } | 1352 } |
| 1109 | 1353 |
| 1110 bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path, | 1354 bool GrAAHairLinePathRenderer::canDrawPath(const SkPath& path, |
| 1111 const SkStrokeRec& stroke, | 1355 const SkStrokeRec& stroke, |
| 1112 const GrDrawTarget* target, | 1356 const GrDrawTarget* target, |
| 1113 bool antiAlias) const { | 1357 bool antiAlias) const { |
| 1114 if (!stroke.isHairlineStyle() || !antiAlias) { | 1358 if (!stroke.isHairlineStyle() || !antiAlias) { |
| 1115 return false; | 1359 return false; |
| 1116 } | 1360 } |
| 1117 | 1361 |
| 1118 if (SkPath::kLine_SegmentMask == path.getSegmentMasks() || | 1362 if (SkPath::kLine_SegmentMask == path.getSegmentMasks() || |
| 1119 target->caps()->shaderDerivativeSupport()) { | 1363 target->caps()->shaderDerivativeSupport()) { |
| 1120 return true; | 1364 return true; |
| 1121 } | 1365 } |
| 1122 return false; | 1366 return false; |
| 1123 } | 1367 } |
| 1124 | 1368 |
| 1125 bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, | 1369 bool GrAAHairLinePathRenderer::onDrawPath(const SkPath& path, |
| 1126 const SkStrokeRec&, | 1370 const SkStrokeRec&, |
| 1127 GrDrawTarget* target, | 1371 GrDrawTarget* target, |
| 1128 bool antiAlias) { | 1372 bool antiAlias) { |
| 1129 | 1373 |
| 1130 int lineCnt; | 1374 int lineCnt; |
| 1131 int quadCnt; | 1375 int quadCnt; |
| 1132 int conicCnt; | 1376 int conicCnt; |
| 1377 int cubicCnt; |
| 1133 GrDrawTarget::AutoReleaseGeometry arg; | 1378 GrDrawTarget::AutoReleaseGeometry arg; |
| 1134 SkRect devBounds; | 1379 SkRect devBounds; |
| 1135 | 1380 |
| 1136 if (!this->createGeom(path, | 1381 if (!this->createGeom(path, |
| 1137 target, | 1382 target, |
| 1138 &lineCnt, | 1383 &lineCnt, |
| 1139 &quadCnt, | 1384 &quadCnt, |
| 1140 &conicCnt, | 1385 &conicCnt, |
| 1386 &cubicCnt, |
| 1141 &arg, | 1387 &arg, |
| 1142 &devBounds)) { | 1388 &devBounds)) { |
| 1143 return false; | 1389 return false; |
| 1144 } | 1390 } |
| 1145 | 1391 |
| 1146 GrDrawTarget::AutoStateRestore asr; | 1392 GrDrawTarget::AutoStateRestore asr; |
| 1147 | 1393 |
| 1148 // createGeom transforms the geometry to device space when the matrix does n
ot have | 1394 // createGeom transforms the geometry to device space when the matrix does n
ot have |
| 1149 // perspective. | 1395 // perspective. |
| 1150 if (target->getDrawState().getViewMatrix().hasPerspective()) { | 1396 if (target->getDrawState().getViewMatrix().hasPerspective()) { |
| 1151 asr.set(target, GrDrawTarget::kPreserve_ASRInit); | 1397 asr.set(target, GrDrawTarget::kPreserve_ASRInit); |
| 1152 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { | 1398 } else if (!asr.setIdentity(target, GrDrawTarget::kPreserve_ASRInit)) { |
| 1153 return false; | 1399 return false; |
| 1154 } | 1400 } |
| 1155 GrDrawState* drawState = target->drawState(); | 1401 GrDrawState* drawState = target->drawState(); |
| 1156 | 1402 |
| 1157 // TODO: See whether rendering lines as degenerate quads improves perf | 1403 // TODO: See whether rendering lines as degenerate quads improves perf |
| 1158 // when we have a mix | 1404 // when we have a mix |
| 1159 | 1405 |
| 1160 static const int kEdgeAttrIndex = 1; | 1406 static const int kEdgeAttrIndex = 1; |
| 1161 | 1407 |
| 1162 GrEffectRef* hairLineEffect = HairLineEdgeEffect::Create(); | 1408 GrEffectRef* hairLineEffect = HairLineEdgeEffect::Create(); |
| 1163 GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create(); | 1409 GrEffectRef* hairQuadEffect = HairQuadEdgeEffect::Create(); |
| 1164 GrEffectRef* hairConicEffect = HairConicEdgeEffect::Create(); | 1410 GrEffectRef* hairConicEffect = HairConicEdgeEffect::Create(); |
| 1411 GrEffectRef* hairCubicEffect = HairCubicEdgeEffect::Create(); |
| 1165 | 1412 |
| 1166 // Check devBounds | 1413 // Check devBounds |
| 1167 #if GR_DEBUG | 1414 #if GR_DEBUG |
| 1168 SkRect tolDevBounds = devBounds; | 1415 SkRect tolDevBounds = devBounds; |
| 1169 tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000); | 1416 tolDevBounds.outset(SK_Scalar1 / 10000, SK_Scalar1 / 10000); |
| 1170 SkRect actualBounds; | 1417 SkRect actualBounds; |
| 1171 Vertex* verts = reinterpret_cast<Vertex*>(arg.vertices()); | 1418 Vertex* verts = reinterpret_cast<Vertex*>(arg.vertices()); |
| 1172 int vCount = kVertsPerLineSeg * lineCnt + kVertsPerQuad * quadCnt + kVertsPe
rQuad * conicCnt; | 1419 int vCount = kVertsPerLineSeg * lineCnt + kVertsPerQuad * quadCnt + kVertsPe
rQuad * conicCnt; |
| 1173 bool first = true; | 1420 bool first = true; |
| 1174 for (int i = 0; i < vCount; ++i) { | 1421 for (int i = 0; i < vCount; ++i) { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1221 kVertsPerQuad*n,
// vCount | 1468 kVertsPerQuad*n,
// vCount |
| 1222 kIdxsPerQuad*n,
// iCount | 1469 kIdxsPerQuad*n,
// iCount |
| 1223 &devBounds); | 1470 &devBounds); |
| 1224 quads += n; | 1471 quads += n; |
| 1225 } | 1472 } |
| 1226 } | 1473 } |
| 1227 | 1474 |
| 1228 { | 1475 { |
| 1229 GrDrawState::AutoRestoreEffects are(drawState); | 1476 GrDrawState::AutoRestoreEffects are(drawState); |
| 1230 int conics = 0; | 1477 int conics = 0; |
| 1231 drawState->addCoverageEffect(hairConicEffect, 1, 2)->unref(); | 1478 drawState->addCoverageEffect(hairConicEffect, kEdgeAttrIndex)->unref(); |
| 1232 while (conics < conicCnt) { | 1479 while (conics < conicCnt) { |
| 1233 int n = GrMin(conicCnt - conics, kNumQuadsInIdxBuffer); | 1480 int n = GrMin(conicCnt - conics, kNumQuadsInIdxBuffer); |
| 1234 target->drawIndexed(kTriangles_GrPrimitiveType, | 1481 target->drawIndexed(kTriangles_GrPrimitiveType, |
| 1235 kVertsPerLineSeg*lineCnt + | 1482 kVertsPerLineSeg*lineCnt + |
| 1236 kVertsPerQuad*(quadCnt + conics), // startV | 1483 kVertsPerQuad*(quadCnt + conics), // startV |
| 1237 0, // startI | 1484 0, // startI |
| 1238 kVertsPerQuad*n, // vCount | 1485 kVertsPerQuad*n, // vCount |
| 1239 kIdxsPerQuad*n, // iCount | 1486 kIdxsPerQuad*n, // iCount |
| 1240 &devBounds); | 1487 &devBounds); |
| 1241 conics += n; | 1488 conics += n; |
| 1242 } | 1489 } |
| 1243 } | 1490 } |
| 1491 |
| 1492 { |
| 1493 GrDrawState::AutoRestoreEffects are(drawState); |
| 1494 target->setIndexSourceToBuffer(fCubicsIndexBuffer); |
| 1495 int cubics = 0; |
| 1496 drawState->addCoverageEffect(hairCubicEffect, kEdgeAttrIndex)->unref(); |
| 1497 while (cubics < cubicCnt) { |
| 1498 int n = GrMin(cubicCnt - cubics, kNumCubicsInIdxBuffer); |
| 1499 target->drawIndexed(kTriangles_GrPrimitiveType, |
| 1500 kVertsPerLineSeg * lineCnt + |
| 1501 kVertsPerQuad * (quadCnt + conicCnt) + |
| 1502 kVertsPerCubic * cubics,
// startV |
| 1503 0,
// startI |
| 1504 kVertsPerCubic*n,
// vCount |
| 1505 kIdxsPerCubic*n,
// iCount |
| 1506 &devBounds); |
| 1507 cubics += n; |
| 1508 } |
| 1509 } |
| 1244 target->resetIndexSource(); | 1510 target->resetIndexSource(); |
| 1245 | 1511 |
| 1246 return true; | 1512 return true; |
| 1247 } | 1513 } |
| OLD | NEW |