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