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