OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 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 "GrTessellatingPathRenderer.h" | 8 #include "GrTessellatingPathRenderer.h" |
9 | 9 |
10 #include "GrBatch.h" | 10 #include "GrBatch.h" |
11 #include "GrBatchTarget.h" | 11 #include "GrBatchTarget.h" |
12 #include "GrBatchTest.h" | 12 #include "GrBatchTest.h" |
13 #include "GrDefaultGeoProcFactory.h" | 13 #include "GrDefaultGeoProcFactory.h" |
14 #include "GrPathUtils.h" | 14 #include "GrPathUtils.h" |
15 #include "GrVertices.h" | 15 #include "GrVertices.h" |
16 #include "GrResourceCache.h" | |
17 #include "GrResourceProvider.h" | |
18 #include "SkChunkAlloc.h" | 16 #include "SkChunkAlloc.h" |
19 #include "SkGeometry.h" | 17 #include "SkGeometry.h" |
20 | 18 |
21 #include <stdio.h> | 19 #include <stdio.h> |
22 | 20 |
23 /* | 21 /* |
24 * This path renderer tessellates the path into triangles, uploads the triangles
to a | 22 * This path renderer tessellates the path into triangles, uploads the triangles
to a |
25 * vertex buffer, and renders them with a single draw call. It does not currentl
y do | 23 * vertex buffer, and renders them with a single draw call. It does not currentl
y do |
26 * antialiasing, so it must be used in conjunction with multisampling. | 24 * antialiasing, so it must be used in conjunction with multisampling. |
27 * | 25 * |
(...skipping 505 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
533 const SkPoint s = { SkScalarAve(r[0].fX, r[1].fX), SkScalarAve(r[0].fY, r[1]
.fY) }; | 531 const SkPoint s = { SkScalarAve(r[0].fX, r[1].fX), SkScalarAve(r[0].fY, r[1]
.fY) }; |
534 pointsLeft >>= 1; | 532 pointsLeft >>= 1; |
535 prev = generate_cubic_points(p0, q[0], r[0], s, tolSqd, prev, head, pointsLe
ft, alloc); | 533 prev = generate_cubic_points(p0, q[0], r[0], s, tolSqd, prev, head, pointsLe
ft, alloc); |
536 prev = generate_cubic_points(s, r[1], q[2], p3, tolSqd, prev, head, pointsLe
ft, alloc); | 534 prev = generate_cubic_points(s, r[1], q[2], p3, tolSqd, prev, head, pointsLe
ft, alloc); |
537 return prev; | 535 return prev; |
538 } | 536 } |
539 | 537 |
540 // Stage 1: convert the input path to a set of linear contours (linked list of V
ertices). | 538 // Stage 1: convert the input path to a set of linear contours (linked list of V
ertices). |
541 | 539 |
542 void path_to_contours(const SkPath& path, SkScalar tolerance, const SkRect& clip
Bounds, | 540 void path_to_contours(const SkPath& path, SkScalar tolerance, const SkRect& clip
Bounds, |
543 Vertex** contours, SkChunkAlloc& alloc, bool *isLinear) { | 541 Vertex** contours, SkChunkAlloc& alloc) { |
544 | 542 |
545 SkScalar toleranceSqd = tolerance * tolerance; | 543 SkScalar toleranceSqd = tolerance * tolerance; |
546 | 544 |
547 SkPoint pts[4]; | 545 SkPoint pts[4]; |
548 bool done = false; | 546 bool done = false; |
549 *isLinear = true; | |
550 SkPath::Iter iter(path, false); | 547 SkPath::Iter iter(path, false); |
551 Vertex* prev = NULL; | 548 Vertex* prev = NULL; |
552 Vertex* head = NULL; | 549 Vertex* head = NULL; |
553 if (path.isInverseFillType()) { | 550 if (path.isInverseFillType()) { |
554 SkPoint quad[4]; | 551 SkPoint quad[4]; |
555 clipBounds.toQuad(quad); | 552 clipBounds.toQuad(quad); |
556 for (int i = 3; i >= 0; i--) { | 553 for (int i = 3; i >= 0; i--) { |
557 prev = append_point_to_contour(quad[i], prev, &head, alloc); | 554 prev = append_point_to_contour(quad[i], prev, &head, alloc); |
558 } | 555 } |
559 head->fPrev = prev; | 556 head->fPrev = prev; |
560 prev->fNext = head; | 557 prev->fNext = head; |
561 *contours++ = head; | 558 *contours++ = head; |
562 head = prev = NULL; | 559 head = prev = NULL; |
563 } | 560 } |
564 SkAutoConicToQuads converter; | 561 SkAutoConicToQuads converter; |
565 while (!done) { | 562 while (!done) { |
566 SkPath::Verb verb = iter.next(pts); | 563 SkPath::Verb verb = iter.next(pts); |
567 switch (verb) { | 564 switch (verb) { |
568 case SkPath::kConic_Verb: { | 565 case SkPath::kConic_Verb: { |
569 SkScalar weight = iter.conicWeight(); | 566 SkScalar weight = iter.conicWeight(); |
570 const SkPoint* quadPts = converter.computeQuads(pts, weight, tol
eranceSqd); | 567 const SkPoint* quadPts = converter.computeQuads(pts, weight, tol
eranceSqd); |
571 for (int i = 0; i < converter.countQuads(); ++i) { | 568 for (int i = 0; i < converter.countQuads(); ++i) { |
572 int pointsLeft = GrPathUtils::quadraticPointCount(quadPts, t
olerance); | 569 int pointsLeft = GrPathUtils::quadraticPointCount(quadPts, t
olerance); |
573 prev = generate_quadratic_points(quadPts[0], quadPts[1], qua
dPts[2], | 570 prev = generate_quadratic_points(quadPts[0], quadPts[1], qua
dPts[2], |
574 toleranceSqd, prev, &head,
pointsLeft, alloc); | 571 toleranceSqd, prev, &head,
pointsLeft, alloc); |
575 quadPts += 2; | 572 quadPts += 2; |
576 } | 573 } |
577 *isLinear = false; | |
578 break; | 574 break; |
579 } | 575 } |
580 case SkPath::kMove_Verb: | 576 case SkPath::kMove_Verb: |
581 if (head) { | 577 if (head) { |
582 head->fPrev = prev; | 578 head->fPrev = prev; |
583 prev->fNext = head; | 579 prev->fNext = head; |
584 *contours++ = head; | 580 *contours++ = head; |
585 } | 581 } |
586 head = prev = NULL; | 582 head = prev = NULL; |
587 prev = append_point_to_contour(pts[0], prev, &head, alloc); | 583 prev = append_point_to_contour(pts[0], prev, &head, alloc); |
588 break; | 584 break; |
589 case SkPath::kLine_Verb: { | 585 case SkPath::kLine_Verb: { |
590 prev = append_point_to_contour(pts[1], prev, &head, alloc); | 586 prev = append_point_to_contour(pts[1], prev, &head, alloc); |
591 break; | 587 break; |
592 } | 588 } |
593 case SkPath::kQuad_Verb: { | 589 case SkPath::kQuad_Verb: { |
594 int pointsLeft = GrPathUtils::quadraticPointCount(pts, tolerance
); | 590 int pointsLeft = GrPathUtils::quadraticPointCount(pts, tolerance
); |
595 prev = generate_quadratic_points(pts[0], pts[1], pts[2], toleran
ceSqd, prev, | 591 prev = generate_quadratic_points(pts[0], pts[1], pts[2], toleran
ceSqd, prev, |
596 &head, pointsLeft, alloc); | 592 &head, pointsLeft, alloc); |
597 *isLinear = false; | |
598 break; | 593 break; |
599 } | 594 } |
600 case SkPath::kCubic_Verb: { | 595 case SkPath::kCubic_Verb: { |
601 int pointsLeft = GrPathUtils::cubicPointCount(pts, tolerance); | 596 int pointsLeft = GrPathUtils::cubicPointCount(pts, tolerance); |
602 prev = generate_cubic_points(pts[0], pts[1], pts[2], pts[3], | 597 prev = generate_cubic_points(pts[0], pts[1], pts[2], pts[3], |
603 toleranceSqd, prev, &head, pointsLeft, alloc); | 598 toleranceSqd, prev, &head, pointsLeft, alloc); |
604 *isLinear = false; | |
605 break; | 599 break; |
606 } | 600 } |
607 case SkPath::kClose_Verb: | 601 case SkPath::kClose_Verb: |
608 if (head) { | 602 if (head) { |
609 head->fPrev = prev; | 603 head->fPrev = prev; |
610 prev->fNext = head; | 604 prev->fNext = head; |
611 *contours++ = head; | 605 *contours++ = head; |
612 } | 606 } |
613 head = prev = NULL; | 607 head = prev = NULL; |
614 break; | 608 break; |
(...skipping 713 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1328 SkPoint* polys_to_triangles(Poly* polys, SkPath::FillType fillType, SkPoint* dat
a) { | 1322 SkPoint* polys_to_triangles(Poly* polys, SkPath::FillType fillType, SkPoint* dat
a) { |
1329 SkPoint* d = data; | 1323 SkPoint* d = data; |
1330 for (Poly* poly = polys; poly; poly = poly->fNext) { | 1324 for (Poly* poly = polys; poly; poly = poly->fNext) { |
1331 if (apply_fill_type(fillType, poly->fWinding)) { | 1325 if (apply_fill_type(fillType, poly->fWinding)) { |
1332 d = poly->emit(d); | 1326 d = poly->emit(d); |
1333 } | 1327 } |
1334 } | 1328 } |
1335 return d; | 1329 return d; |
1336 } | 1330 } |
1337 | 1331 |
1338 struct TessInfo { | |
1339 SkScalar fTolerance; | |
1340 int fCount; | |
1341 }; | |
1342 | |
1343 bool cache_match(GrVertexBuffer* vertexBuffer, SkScalar tol, int* actualCount) { | |
1344 if (!vertexBuffer) { | |
1345 return false; | |
1346 } | |
1347 const SkData* data = vertexBuffer->getUniqueKey().getCustomData(); | |
1348 SkASSERT(data); | |
1349 const TessInfo* info = static_cast<const TessInfo*>(data->data()); | |
1350 if (info->fTolerance == 0 || info->fTolerance < 3.0f * tol) { | |
1351 *actualCount = info->fCount; | |
1352 return true; | |
1353 } | |
1354 return false; | |
1355 } | |
1356 | |
1357 }; | 1332 }; |
1358 | 1333 |
1359 GrTessellatingPathRenderer::GrTessellatingPathRenderer() { | 1334 GrTessellatingPathRenderer::GrTessellatingPathRenderer() { |
1360 } | 1335 } |
1361 | 1336 |
1362 GrPathRenderer::StencilSupport GrTessellatingPathRenderer::onGetStencilSupport( | 1337 GrPathRenderer::StencilSupport GrTessellatingPathRenderer::onGetStencilSupport( |
1363 const GrDrawTarget*, | 1338 const GrDrawTarget*, |
1364 const GrPipelineBuil
der*, | 1339 const GrPipelineBuil
der*, |
1365 const SkPath&, | 1340 const SkPath&, |
1366 const GrStrokeInfo&)
const { | 1341 const GrStrokeInfo&)
const { |
1367 return GrPathRenderer::kNoSupport_StencilSupport; | 1342 return GrPathRenderer::kNoSupport_StencilSupport; |
1368 } | 1343 } |
1369 | 1344 |
1370 namespace { | |
1371 | |
1372 // When the SkPathRef genID changes, invalidate a corresponding GrResource descr
ibed by key. | |
1373 class PathInvalidator : public SkPathRef::GenIDChangeListener { | |
1374 public: | |
1375 explicit PathInvalidator(const GrUniqueKey& key) : fMsg(key) {} | |
1376 private: | |
1377 GrUniqueKeyInvalidatedMessage fMsg; | |
1378 | |
1379 void onChange() override { | |
1380 SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg); | |
1381 } | |
1382 }; | |
1383 | |
1384 } // namespace | |
1385 | |
1386 bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) cons
t { | 1345 bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) cons
t { |
1387 // This path renderer can draw all fill styles, but does not do antialiasing
. It can do convex | 1346 // This path renderer can draw all fill styles, but does not do antialiasing
. It can do convex |
1388 // and concave paths, but we'll leave the convex ones to simpler algorithms. | 1347 // and concave paths, but we'll leave the convex ones to simpler algorithms. |
1389 return args.fStroke->isFillStyle() && !args.fAntiAlias && !args.fPath->isCon
vex(); | 1348 return args.fStroke->isFillStyle() && !args.fAntiAlias && !args.fPath->isCon
vex(); |
1390 } | 1349 } |
1391 | 1350 |
1392 class TessellatingPathBatch : public GrBatch { | 1351 class TessellatingPathBatch : public GrBatch { |
1393 public: | 1352 public: |
1394 | 1353 |
1395 static GrBatch* Create(const GrColor& color, | 1354 static GrBatch* Create(const GrColor& color, |
(...skipping 15 matching lines...) Expand all Loading... |
1411 | 1370 |
1412 void initBatchTracker(const GrPipelineInfo& init) override { | 1371 void initBatchTracker(const GrPipelineInfo& init) override { |
1413 // Handle any color overrides | 1372 // Handle any color overrides |
1414 if (!init.readsColor()) { | 1373 if (!init.readsColor()) { |
1415 fColor = GrColor_ILLEGAL; | 1374 fColor = GrColor_ILLEGAL; |
1416 } | 1375 } |
1417 init.getOverrideColorIfSet(&fColor); | 1376 init.getOverrideColorIfSet(&fColor); |
1418 fPipelineInfo = init; | 1377 fPipelineInfo = init; |
1419 } | 1378 } |
1420 | 1379 |
1421 int tessellate(GrUniqueKey* key, | 1380 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline
) override { |
1422 GrResourceProvider* resourceProvider, | |
1423 SkAutoTUnref<GrVertexBuffer>& vertexBuffer) { | |
1424 SkRect pathBounds = fPath.getBounds(); | 1381 SkRect pathBounds = fPath.getBounds(); |
1425 Comparator c; | 1382 Comparator c; |
1426 if (pathBounds.width() > pathBounds.height()) { | 1383 if (pathBounds.width() > pathBounds.height()) { |
1427 c.sweep_lt = sweep_lt_horiz; | 1384 c.sweep_lt = sweep_lt_horiz; |
1428 c.sweep_gt = sweep_gt_horiz; | 1385 c.sweep_gt = sweep_gt_horiz; |
1429 } else { | 1386 } else { |
1430 c.sweep_lt = sweep_lt_vert; | 1387 c.sweep_lt = sweep_lt_vert; |
1431 c.sweep_gt = sweep_gt_vert; | 1388 c.sweep_gt = sweep_gt_vert; |
1432 } | 1389 } |
1433 SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; | 1390 SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; |
1434 SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, fViewMat
rix, pathBounds); | 1391 SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, fViewMat
rix, pathBounds); |
1435 int contourCnt; | 1392 int contourCnt; |
1436 int maxPts = GrPathUtils::worstCasePointCount(fPath, &contourCnt, tol); | 1393 int maxPts = GrPathUtils::worstCasePointCount(fPath, &contourCnt, tol); |
1437 if (maxPts <= 0) { | 1394 if (maxPts <= 0) { |
1438 return 0; | 1395 return; |
1439 } | 1396 } |
1440 if (maxPts > ((int)SK_MaxU16 + 1)) { | 1397 if (maxPts > ((int)SK_MaxU16 + 1)) { |
1441 SkDebugf("Path not rendered, too many verts (%d)\n", maxPts); | 1398 SkDebugf("Path not rendered, too many verts (%d)\n", maxPts); |
1442 return 0; | 1399 return; |
1443 } | 1400 } |
1444 SkPath::FillType fillType = fPath.getFillType(); | 1401 SkPath::FillType fillType = fPath.getFillType(); |
1445 if (SkPath::IsInverseFillType(fillType)) { | 1402 if (SkPath::IsInverseFillType(fillType)) { |
1446 contourCnt++; | 1403 contourCnt++; |
1447 } | 1404 } |
1448 | 1405 |
1449 LOG("got %d pts, %d contours\n", maxPts, contourCnt); | 1406 LOG("got %d pts, %d contours\n", maxPts, contourCnt); |
| 1407 SkAutoTUnref<const GrGeometryProcessor> gp; |
| 1408 { |
| 1409 using namespace GrDefaultGeoProcFactory; |
| 1410 |
| 1411 Color color(fColor); |
| 1412 LocalCoords localCoords(fPipelineInfo.readsLocalCoords() ? |
| 1413 LocalCoords::kUsePosition_Type : |
| 1414 LocalCoords::kUnused_Type); |
| 1415 Coverage::Type coverageType; |
| 1416 if (fPipelineInfo.readsCoverage()) { |
| 1417 coverageType = Coverage::kSolid_Type; |
| 1418 } else { |
| 1419 coverageType = Coverage::kNone_Type; |
| 1420 } |
| 1421 Coverage coverage(coverageType); |
| 1422 gp.reset(GrDefaultGeoProcFactory::Create(color, coverage, localCoord
s, |
| 1423 fViewMatrix)); |
| 1424 } |
| 1425 batchTarget->initDraw(gp, pipeline); |
| 1426 |
1450 SkAutoTDeleteArray<Vertex*> contours(SkNEW_ARRAY(Vertex *, contourCnt)); | 1427 SkAutoTDeleteArray<Vertex*> contours(SkNEW_ARRAY(Vertex *, contourCnt)); |
1451 | 1428 |
1452 // For the initial size of the chunk allocator, estimate based on the po
int count: | 1429 // For the initial size of the chunk allocator, estimate based on the po
int count: |
1453 // one vertex per point for the initial passes, plus two for the vertice
s in the | 1430 // one vertex per point for the initial passes, plus two for the vertice
s in the |
1454 // resulting Polys, since the same point may end up in two Polys. Assum
e minimal | 1431 // resulting Polys, since the same point may end up in two Polys. Assum
e minimal |
1455 // connectivity of one Edge per Vertex (will grow for intersections). | 1432 // connectivity of one Edge per Vertex (will grow for intersections). |
1456 SkChunkAlloc alloc(maxPts * (3 * sizeof(Vertex) + sizeof(Edge))); | 1433 SkChunkAlloc alloc(maxPts * (3 * sizeof(Vertex) + sizeof(Edge))); |
1457 bool isLinear; | 1434 path_to_contours(fPath, tol, fClipBounds, contours.get(), alloc); |
1458 path_to_contours(fPath, tol, fClipBounds, contours.get(), alloc, &isLine
ar); | |
1459 Poly* polys; | 1435 Poly* polys; |
1460 polys = contours_to_polys(contours.get(), contourCnt, c, alloc); | 1436 polys = contours_to_polys(contours.get(), contourCnt, c, alloc); |
1461 int count = 0; | 1437 int count = 0; |
1462 for (Poly* poly = polys; poly; poly = poly->fNext) { | 1438 for (Poly* poly = polys; poly; poly = poly->fNext) { |
1463 if (apply_fill_type(fillType, poly->fWinding) && poly->fCount >= 3)
{ | 1439 if (apply_fill_type(fillType, poly->fWinding) && poly->fCount >= 3)
{ |
1464 count += (poly->fCount - 2) * (WIREFRAME ? 6 : 3); | 1440 count += (poly->fCount - 2) * (WIREFRAME ? 6 : 3); |
1465 } | 1441 } |
1466 } | 1442 } |
1467 if (0 == count) { | 1443 if (0 == count) { |
1468 return 0; | 1444 return; |
1469 } | 1445 } |
1470 | 1446 |
1471 size_t size = count * sizeof(SkPoint); | 1447 size_t stride = gp->getVertexStride(); |
1472 if (!vertexBuffer.get() || vertexBuffer->gpuMemorySize() < size) { | 1448 SkASSERT(stride == sizeof(SkPoint)); |
1473 vertexBuffer.reset(resourceProvider->createVertexBuffer( | 1449 const GrVertexBuffer* vertexBuffer; |
1474 size, GrResourceProvider::kStatic_BufferUsage, 0)); | 1450 int firstVertex; |
| 1451 SkPoint* verts = static_cast<SkPoint*>( |
| 1452 batchTarget->makeVertSpace(stride, count, &vertexBuffer, &firstVerte
x)); |
| 1453 if (!verts) { |
| 1454 SkDebugf("Could not allocate vertices\n"); |
| 1455 return; |
1475 } | 1456 } |
1476 if (!vertexBuffer.get()) { | 1457 |
1477 SkDebugf("Could not allocate vertices\n"); | |
1478 return 0; | |
1479 } | |
1480 SkPoint* verts = static_cast<SkPoint*>(vertexBuffer->map()); | |
1481 LOG("emitting %d verts\n", count); | 1458 LOG("emitting %d verts\n", count); |
1482 SkPoint* end = polys_to_triangles(polys, fillType, verts); | 1459 SkPoint* end = polys_to_triangles(polys, fillType, verts); |
1483 vertexBuffer->unmap(); | |
1484 int actualCount = static_cast<int>(end - verts); | 1460 int actualCount = static_cast<int>(end - verts); |
1485 LOG("actual count: %d\n", actualCount); | 1461 LOG("actual count: %d\n", actualCount); |
1486 SkASSERT(actualCount <= count); | 1462 SkASSERT(actualCount <= count); |
1487 | 1463 |
1488 if (!fPath.isVolatile()) { | |
1489 TessInfo info; | |
1490 info.fTolerance = isLinear ? 0 : tol; | |
1491 info.fCount = actualCount; | |
1492 SkAutoTUnref<SkData> data(SkData::NewWithCopy(&info, sizeof(info))); | |
1493 key->setCustomData(data.get()); | |
1494 resourceProvider->assignUniqueKeyToResource(*key, vertexBuffer.get()
); | |
1495 SkPathPriv::AddGenIDChangeListener(fPath, SkNEW(PathInvalidator(*key
))); | |
1496 } | |
1497 return actualCount; | |
1498 } | |
1499 | |
1500 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline
) override { | |
1501 // construct a cache key from the path's genID and the view matrix | |
1502 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain()
; | |
1503 GrUniqueKey key; | |
1504 GrUniqueKey::Builder builder(&key, kDomain, 2); | |
1505 builder[0] = fPath.getGenerationID(); | |
1506 builder[1] = fPath.getFillType(); | |
1507 builder.finish(); | |
1508 GrResourceProvider* rp = batchTarget->resourceProvider(); | |
1509 SkAutoTUnref<GrVertexBuffer> vertexBuffer(rp->findAndRefTByUniqueKey<GrV
ertexBuffer>(key)); | |
1510 int actualCount; | |
1511 SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; | |
1512 SkScalar tol = GrPathUtils::scaleToleranceToSrc( | |
1513 screenSpaceTol, fViewMatrix, fPath.getBounds()); | |
1514 if (!cache_match(vertexBuffer.get(), tol, &actualCount)) { | |
1515 actualCount = tessellate(&key, rp, vertexBuffer); | |
1516 } | |
1517 | |
1518 if (actualCount == 0) { | |
1519 return; | |
1520 } | |
1521 | |
1522 SkAutoTUnref<const GrGeometryProcessor> gp; | |
1523 { | |
1524 using namespace GrDefaultGeoProcFactory; | |
1525 | |
1526 Color color(fColor); | |
1527 LocalCoords localCoords(fPipelineInfo.readsLocalCoords() ? | |
1528 LocalCoords::kUsePosition_Type : | |
1529 LocalCoords::kUnused_Type); | |
1530 Coverage::Type coverageType; | |
1531 if (fPipelineInfo.readsCoverage()) { | |
1532 coverageType = Coverage::kSolid_Type; | |
1533 } else { | |
1534 coverageType = Coverage::kNone_Type; | |
1535 } | |
1536 Coverage coverage(coverageType); | |
1537 gp.reset(GrDefaultGeoProcFactory::Create(color, coverage, localCoord
s, | |
1538 fViewMatrix)); | |
1539 } | |
1540 | |
1541 batchTarget->initDraw(gp, pipeline); | |
1542 SkASSERT(gp->getVertexStride() == sizeof(SkPoint)); | |
1543 | |
1544 GrPrimitiveType primitiveType = WIREFRAME ? kLines_GrPrimitiveType | 1464 GrPrimitiveType primitiveType = WIREFRAME ? kLines_GrPrimitiveType |
1545 : kTriangles_GrPrimitiveType; | 1465 : kTriangles_GrPrimitiveType; |
1546 GrVertices vertices; | 1466 GrVertices vertices; |
1547 vertices.init(primitiveType, vertexBuffer.get(), 0, actualCount); | 1467 vertices.init(primitiveType, vertexBuffer, firstVertex, actualCount); |
1548 batchTarget->draw(vertices); | 1468 batchTarget->draw(vertices); |
| 1469 |
| 1470 batchTarget->putBackVertices((size_t)(count - actualCount), stride); |
| 1471 return; |
1549 } | 1472 } |
1550 | 1473 |
1551 bool onCombineIfPossible(GrBatch*) override { | 1474 bool onCombineIfPossible(GrBatch*) override { |
1552 return false; | 1475 return false; |
1553 } | 1476 } |
1554 | 1477 |
1555 private: | 1478 private: |
1556 TessellatingPathBatch(const GrColor& color, | 1479 TessellatingPathBatch(const GrColor& color, |
1557 const SkPath& path, | 1480 const SkPath& path, |
1558 const SkMatrix& viewMatrix, | 1481 const SkMatrix& viewMatrix, |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1608 SkMatrix vmi; | 1531 SkMatrix vmi; |
1609 bool result = viewMatrix.invert(&vmi); | 1532 bool result = viewMatrix.invert(&vmi); |
1610 if (!result) { | 1533 if (!result) { |
1611 SkFAIL("Cannot invert matrix\n"); | 1534 SkFAIL("Cannot invert matrix\n"); |
1612 } | 1535 } |
1613 vmi.mapRect(&clipBounds); | 1536 vmi.mapRect(&clipBounds); |
1614 return TessellatingPathBatch::Create(color, path, viewMatrix, clipBounds); | 1537 return TessellatingPathBatch::Create(color, path, viewMatrix, clipBounds); |
1615 } | 1538 } |
1616 | 1539 |
1617 #endif | 1540 #endif |
OLD | NEW |