Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(753)

Side by Side Diff: src/gpu/GrTessellatingPathRenderer.cpp

Issue 1275553002: Implement caching of stroked paths in the tessellating path renderer. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Use IsStrokeHairlineOrEquivalent() instead of stroke->isHairline() Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « include/gpu/GrTestUtils.h ('k') | src/gpu/GrTestUtils.cpp » ('j') | src/gpu/GrTestUtils.cpp » ('J')

Powered by Google App Engine
This is Rietveld 408576698