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" |
(...skipping 1366 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1377 GrUniqueKeyInvalidatedMessage fMsg; | 1377 GrUniqueKeyInvalidatedMessage fMsg; |
1378 | 1378 |
1379 void onChange() override { | 1379 void onChange() override { |
1380 SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg); | 1380 SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg); |
1381 } | 1381 } |
1382 }; | 1382 }; |
1383 | 1383 |
1384 } // namespace | 1384 } // namespace |
1385 | 1385 |
1386 bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) cons
t { | 1386 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 | 1387 // This path renderer can draw all fill styles, all stroke styles except hai
rlines, but does |
1388 // and concave paths, but we'll leave the convex ones to simpler algorithms. | 1388 // not do antialiasing. It can do convex and concave paths, but we'll leave
the convex ones to |
1389 return args.fStroke->isFillStyle() && !args.fAntiAlias && !args.fPath->isCon
vex(); | 1389 // simpler algorithms. |
| 1390 return !IsStrokeHairlineOrEquivalent(*args.fStroke, *args.fViewMatrix, NULL)
&& |
| 1391 !args.fAntiAlias && !args.fPath->isConvex(); |
1390 } | 1392 } |
1391 | 1393 |
1392 class TessellatingPathBatch : public GrBatch { | 1394 class TessellatingPathBatch : public GrBatch { |
1393 public: | 1395 public: |
1394 | 1396 |
1395 static GrBatch* Create(const GrColor& color, | 1397 static GrBatch* Create(const GrColor& color, |
1396 const SkPath& path, | 1398 const SkPath& path, |
| 1399 const GrStrokeInfo& stroke, |
1397 const SkMatrix& viewMatrix, | 1400 const SkMatrix& viewMatrix, |
1398 SkRect clipBounds) { | 1401 SkRect clipBounds) { |
1399 return SkNEW_ARGS(TessellatingPathBatch, (color, path, viewMatrix, clipB
ounds)); | 1402 return SkNEW_ARGS(TessellatingPathBatch, (color, path, stroke, viewMatri
x, clipBounds)); |
1400 } | 1403 } |
1401 | 1404 |
1402 const char* name() const override { return "TessellatingPathBatch"; } | 1405 const char* name() const override { return "TessellatingPathBatch"; } |
1403 | 1406 |
1404 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { | 1407 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { |
1405 out->setKnownFourComponents(fColor); | 1408 out->setKnownFourComponents(fColor); |
1406 } | 1409 } |
1407 | 1410 |
1408 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { | 1411 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { |
1409 out->setUnknownSingleComponent(); | 1412 out->setUnknownSingleComponent(); |
1410 } | 1413 } |
1411 | 1414 |
1412 void initBatchTracker(const GrPipelineInfo& init) override { | 1415 void initBatchTracker(const GrPipelineInfo& init) override { |
1413 // Handle any color overrides | 1416 // Handle any color overrides |
1414 if (!init.readsColor()) { | 1417 if (!init.readsColor()) { |
1415 fColor = GrColor_ILLEGAL; | 1418 fColor = GrColor_ILLEGAL; |
1416 } | 1419 } |
1417 init.getOverrideColorIfSet(&fColor); | 1420 init.getOverrideColorIfSet(&fColor); |
1418 fPipelineInfo = init; | 1421 fPipelineInfo = init; |
1419 } | 1422 } |
1420 | 1423 |
1421 int tessellate(GrUniqueKey* key, | 1424 int tessellate(GrUniqueKey* key, |
1422 GrResourceProvider* resourceProvider, | 1425 GrResourceProvider* resourceProvider, |
1423 SkAutoTUnref<GrVertexBuffer>& vertexBuffer) { | 1426 SkAutoTUnref<GrVertexBuffer>& vertexBuffer) { |
1424 SkRect pathBounds = fPath.getBounds(); | 1427 SkPath path; |
| 1428 GrStrokeInfo stroke(fStroke); |
| 1429 if (stroke.isDashed()) { |
| 1430 if (!stroke.applyDashToPath(&path, &stroke, fPath)) { |
| 1431 return 0; |
| 1432 } |
| 1433 } else { |
| 1434 path = fPath; |
| 1435 } |
| 1436 if (!stroke.isFillStyle()) { |
| 1437 stroke.setResScale(SkScalarAbs(fViewMatrix.getMaxScale())); |
| 1438 if (!stroke.applyToPath(&path, path)) { |
| 1439 return 0; |
| 1440 } |
| 1441 stroke.setFillStyle(); |
| 1442 } |
| 1443 SkRect pathBounds = path.getBounds(); |
1425 Comparator c; | 1444 Comparator c; |
1426 if (pathBounds.width() > pathBounds.height()) { | 1445 if (pathBounds.width() > pathBounds.height()) { |
1427 c.sweep_lt = sweep_lt_horiz; | 1446 c.sweep_lt = sweep_lt_horiz; |
1428 c.sweep_gt = sweep_gt_horiz; | 1447 c.sweep_gt = sweep_gt_horiz; |
1429 } else { | 1448 } else { |
1430 c.sweep_lt = sweep_lt_vert; | 1449 c.sweep_lt = sweep_lt_vert; |
1431 c.sweep_gt = sweep_gt_vert; | 1450 c.sweep_gt = sweep_gt_vert; |
1432 } | 1451 } |
1433 SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; | 1452 SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; |
1434 SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, fViewMat
rix, pathBounds); | 1453 SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, fViewMat
rix, pathBounds); |
1435 int contourCnt; | 1454 int contourCnt; |
1436 int maxPts = GrPathUtils::worstCasePointCount(fPath, &contourCnt, tol); | 1455 int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt, tol); |
1437 if (maxPts <= 0) { | 1456 if (maxPts <= 0) { |
1438 return 0; | 1457 return 0; |
1439 } | 1458 } |
1440 if (maxPts > ((int)SK_MaxU16 + 1)) { | 1459 if (maxPts > ((int)SK_MaxU16 + 1)) { |
1441 SkDebugf("Path not rendered, too many verts (%d)\n", maxPts); | 1460 SkDebugf("Path not rendered, too many verts (%d)\n", maxPts); |
1442 return 0; | 1461 return 0; |
1443 } | 1462 } |
1444 SkPath::FillType fillType = fPath.getFillType(); | 1463 SkPath::FillType fillType = path.getFillType(); |
1445 if (SkPath::IsInverseFillType(fillType)) { | 1464 if (SkPath::IsInverseFillType(fillType)) { |
1446 contourCnt++; | 1465 contourCnt++; |
1447 } | 1466 } |
1448 | 1467 |
1449 LOG("got %d pts, %d contours\n", maxPts, contourCnt); | 1468 LOG("got %d pts, %d contours\n", maxPts, contourCnt); |
1450 SkAutoTDeleteArray<Vertex*> contours(SkNEW_ARRAY(Vertex *, contourCnt)); | 1469 SkAutoTDeleteArray<Vertex*> contours(SkNEW_ARRAY(Vertex *, contourCnt)); |
1451 | 1470 |
1452 // For the initial size of the chunk allocator, estimate based on the po
int count: | 1471 // 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 | 1472 // 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 | 1473 // 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). | 1474 // connectivity of one Edge per Vertex (will grow for intersections). |
1456 SkChunkAlloc alloc(maxPts * (3 * sizeof(Vertex) + sizeof(Edge))); | 1475 SkChunkAlloc alloc(maxPts * (3 * sizeof(Vertex) + sizeof(Edge))); |
1457 bool isLinear; | 1476 bool isLinear; |
1458 path_to_contours(fPath, tol, fClipBounds, contours.get(), alloc, &isLine
ar); | 1477 path_to_contours(path, tol, fClipBounds, contours.get(), alloc, &isLinea
r); |
1459 Poly* polys; | 1478 Poly* polys; |
1460 polys = contours_to_polys(contours.get(), contourCnt, c, alloc); | 1479 polys = contours_to_polys(contours.get(), contourCnt, c, alloc); |
1461 int count = 0; | 1480 int count = 0; |
1462 for (Poly* poly = polys; poly; poly = poly->fNext) { | 1481 for (Poly* poly = polys; poly; poly = poly->fNext) { |
1463 if (apply_fill_type(fillType, poly->fWinding) && poly->fCount >= 3)
{ | 1482 if (apply_fill_type(fillType, poly->fWinding) && poly->fCount >= 3)
{ |
1464 count += (poly->fCount - 2) * (WIREFRAME ? 6 : 3); | 1483 count += (poly->fCount - 2) * (WIREFRAME ? 6 : 3); |
1465 } | 1484 } |
1466 } | 1485 } |
1467 if (0 == count) { | 1486 if (0 == count) { |
1468 return 0; | 1487 return 0; |
(...skipping 27 matching lines...) Expand all Loading... |
1496 } | 1515 } |
1497 return actualCount; | 1516 return actualCount; |
1498 } | 1517 } |
1499 | 1518 |
1500 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline
) override { | 1519 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline
) override { |
1501 // construct a cache key from the path's genID and the view matrix | 1520 // construct a cache key from the path's genID and the view matrix |
1502 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain()
; | 1521 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain()
; |
1503 GrUniqueKey key; | 1522 GrUniqueKey key; |
1504 int clipBoundsSize32 = | 1523 int clipBoundsSize32 = |
1505 fPath.isInverseFillType() ? sizeof(fClipBounds) / sizeof(uint32_t) :
0; | 1524 fPath.isInverseFillType() ? sizeof(fClipBounds) / sizeof(uint32_t) :
0; |
1506 GrUniqueKey::Builder builder(&key, kDomain, 2 + clipBoundsSize32); | 1525 int strokeDataSize32 = fStroke.computeUniqueKeyFragmentData32Cnt(); |
| 1526 GrUniqueKey::Builder builder(&key, kDomain, 2 + clipBoundsSize32 + strok
eDataSize32); |
1507 builder[0] = fPath.getGenerationID(); | 1527 builder[0] = fPath.getGenerationID(); |
1508 builder[1] = fPath.getFillType(); | 1528 builder[1] = fPath.getFillType(); |
1509 // For inverse fills, the tessellation is dependent on clip bounds. | 1529 // For inverse fills, the tessellation is dependent on clip bounds. |
1510 if (fPath.isInverseFillType()) { | 1530 if (fPath.isInverseFillType()) { |
1511 memcpy(&builder[2], &fClipBounds, sizeof(fClipBounds)); | 1531 memcpy(&builder[2], &fClipBounds, sizeof(fClipBounds)); |
1512 } | 1532 } |
| 1533 fStroke.asUniqueKeyFragment(&builder[2 + clipBoundsSize32]); |
1513 builder.finish(); | 1534 builder.finish(); |
1514 GrResourceProvider* rp = batchTarget->resourceProvider(); | 1535 GrResourceProvider* rp = batchTarget->resourceProvider(); |
1515 SkAutoTUnref<GrVertexBuffer> vertexBuffer(rp->findAndRefTByUniqueKey<GrV
ertexBuffer>(key)); | 1536 SkAutoTUnref<GrVertexBuffer> vertexBuffer(rp->findAndRefTByUniqueKey<GrV
ertexBuffer>(key)); |
1516 int actualCount; | 1537 int actualCount; |
1517 SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; | 1538 SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; |
1518 SkScalar tol = GrPathUtils::scaleToleranceToSrc( | 1539 SkScalar tol = GrPathUtils::scaleToleranceToSrc( |
1519 screenSpaceTol, fViewMatrix, fPath.getBounds()); | 1540 screenSpaceTol, fViewMatrix, fPath.getBounds()); |
1520 if (!cache_match(vertexBuffer.get(), tol, &actualCount)) { | 1541 if (!cache_match(vertexBuffer.get(), tol, &actualCount)) { |
1521 actualCount = tessellate(&key, rp, vertexBuffer); | 1542 actualCount = tessellate(&key, rp, vertexBuffer); |
1522 } | 1543 } |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1554 batchTarget->draw(vertices); | 1575 batchTarget->draw(vertices); |
1555 } | 1576 } |
1556 | 1577 |
1557 bool onCombineIfPossible(GrBatch*) override { | 1578 bool onCombineIfPossible(GrBatch*) override { |
1558 return false; | 1579 return false; |
1559 } | 1580 } |
1560 | 1581 |
1561 private: | 1582 private: |
1562 TessellatingPathBatch(const GrColor& color, | 1583 TessellatingPathBatch(const GrColor& color, |
1563 const SkPath& path, | 1584 const SkPath& path, |
| 1585 const GrStrokeInfo& stroke, |
1564 const SkMatrix& viewMatrix, | 1586 const SkMatrix& viewMatrix, |
1565 const SkRect& clipBounds) | 1587 const SkRect& clipBounds) |
1566 : fColor(color) | 1588 : fColor(color) |
1567 , fPath(path) | 1589 , fPath(path) |
| 1590 , fStroke(stroke) |
1568 , fViewMatrix(viewMatrix) | 1591 , fViewMatrix(viewMatrix) |
1569 , fClipBounds(clipBounds) { | 1592 , fClipBounds(clipBounds) { |
1570 this->initClassID<TessellatingPathBatch>(); | 1593 this->initClassID<TessellatingPathBatch>(); |
1571 | 1594 |
1572 fBounds = path.getBounds(); | 1595 fBounds = path.getBounds(); |
| 1596 if (!stroke.isFillStyle()) { |
| 1597 SkScalar radius = SkScalarHalf(stroke.getWidth()); |
| 1598 if (stroke.getJoin() == SkPaint::kMiter_Join) { |
| 1599 SkScalar scale = stroke.getMiter(); |
| 1600 if (scale > SK_Scalar1) { |
| 1601 radius = SkScalarMul(radius, scale); |
| 1602 } |
| 1603 } |
| 1604 fBounds.outset(radius, radius); |
| 1605 } |
1573 viewMatrix.mapRect(&fBounds); | 1606 viewMatrix.mapRect(&fBounds); |
1574 } | 1607 } |
1575 | 1608 |
1576 GrColor fColor; | 1609 GrColor fColor; |
1577 SkPath fPath; | 1610 SkPath fPath; |
| 1611 GrStrokeInfo fStroke; |
1578 SkMatrix fViewMatrix; | 1612 SkMatrix fViewMatrix; |
1579 SkRect fClipBounds; // in source space | 1613 SkRect fClipBounds; // in source space |
1580 GrPipelineInfo fPipelineInfo; | 1614 GrPipelineInfo fPipelineInfo; |
1581 }; | 1615 }; |
1582 | 1616 |
1583 bool GrTessellatingPathRenderer::onDrawPath(const DrawPathArgs& args) { | 1617 bool GrTessellatingPathRenderer::onDrawPath(const DrawPathArgs& args) { |
1584 SkASSERT(!args.fAntiAlias); | 1618 SkASSERT(!args.fAntiAlias); |
1585 const GrRenderTarget* rt = args.fPipelineBuilder->getRenderTarget(); | 1619 const GrRenderTarget* rt = args.fPipelineBuilder->getRenderTarget(); |
1586 if (NULL == rt) { | 1620 if (NULL == rt) { |
1587 return false; | 1621 return false; |
1588 } | 1622 } |
1589 | 1623 |
1590 SkIRect clipBoundsI; | 1624 SkIRect clipBoundsI; |
1591 args.fPipelineBuilder->clip().getConservativeBounds(rt, &clipBoundsI); | 1625 args.fPipelineBuilder->clip().getConservativeBounds(rt, &clipBoundsI); |
1592 SkRect clipBounds = SkRect::Make(clipBoundsI); | 1626 SkRect clipBounds = SkRect::Make(clipBoundsI); |
1593 SkMatrix vmi; | 1627 SkMatrix vmi; |
1594 if (!args.fViewMatrix->invert(&vmi)) { | 1628 if (!args.fViewMatrix->invert(&vmi)) { |
1595 return false; | 1629 return false; |
1596 } | 1630 } |
1597 vmi.mapRect(&clipBounds); | 1631 vmi.mapRect(&clipBounds); |
1598 SkAutoTUnref<GrBatch> batch(TessellatingPathBatch::Create(args.fColor, *args
.fPath, | 1632 SkAutoTUnref<GrBatch> batch(TessellatingPathBatch::Create(args.fColor, *args
.fPath, |
1599 *args.fViewMatrix,
clipBounds)); | 1633 *args.fStroke, *ar
gs.fViewMatrix, |
| 1634 clipBounds)); |
1600 args.fTarget->drawBatch(*args.fPipelineBuilder, batch); | 1635 args.fTarget->drawBatch(*args.fPipelineBuilder, batch); |
1601 | 1636 |
1602 return true; | 1637 return true; |
1603 } | 1638 } |
1604 | 1639 |
1605 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 1640 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
1606 | 1641 |
1607 #ifdef GR_TEST_UTILS | 1642 #ifdef GR_TEST_UTILS |
1608 | 1643 |
1609 BATCH_TEST_DEFINE(TesselatingPathBatch) { | 1644 BATCH_TEST_DEFINE(TesselatingPathBatch) { |
1610 GrColor color = GrRandomColor(random); | 1645 GrColor color = GrRandomColor(random); |
1611 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); | 1646 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); |
1612 SkPath path = GrTest::TestPath(random); | 1647 SkPath path = GrTest::TestPath(random); |
1613 SkRect clipBounds = GrTest::TestRect(random); | 1648 SkRect clipBounds = GrTest::TestRect(random); |
1614 SkMatrix vmi; | 1649 SkMatrix vmi; |
1615 bool result = viewMatrix.invert(&vmi); | 1650 bool result = viewMatrix.invert(&vmi); |
1616 if (!result) { | 1651 if (!result) { |
1617 SkFAIL("Cannot invert matrix\n"); | 1652 SkFAIL("Cannot invert matrix\n"); |
1618 } | 1653 } |
1619 vmi.mapRect(&clipBounds); | 1654 vmi.mapRect(&clipBounds); |
1620 return TessellatingPathBatch::Create(color, path, viewMatrix, clipBounds); | 1655 GrStrokeInfo strokeInfo = GrTest::TestStrokeInfo(random); |
| 1656 return TessellatingPathBatch::Create(color, path, strokeInfo, viewMatrix, cl
ipBounds); |
1621 } | 1657 } |
1622 | 1658 |
1623 #endif | 1659 #endif |
OLD | NEW |