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" |
| 11 #include "GrBatchTarget.h" |
10 #include "GrDefaultGeoProcFactory.h" | 12 #include "GrDefaultGeoProcFactory.h" |
11 #include "GrPathUtils.h" | 13 #include "GrPathUtils.h" |
12 #include "SkChunkAlloc.h" | 14 #include "SkChunkAlloc.h" |
13 #include "SkGeometry.h" | 15 #include "SkGeometry.h" |
14 | 16 |
15 #include <stdio.h> | 17 #include <stdio.h> |
16 | 18 |
17 /* | 19 /* |
18 * This path renderer tessellates the path into triangles, uploads the triangles
to a | 20 * This path renderer tessellates the path into triangles, uploads the triangles
to a |
19 * vertex buffer, and renders them with a single draw call. It does not currentl
y do | 21 * vertex buffer, and renders them with a single draw call. It does not currentl
y do |
(...skipping 1409 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1429 const GrPipelineBuilder* pipelineBu
ilder, | 1431 const GrPipelineBuilder* pipelineBu
ilder, |
1430 const SkMatrix& viewMatrix, | 1432 const SkMatrix& viewMatrix, |
1431 const SkPath& path, | 1433 const SkPath& path, |
1432 const SkStrokeRec& stroke, | 1434 const SkStrokeRec& stroke, |
1433 bool antiAlias) const { | 1435 bool antiAlias) const { |
1434 // This path renderer can draw all fill styles, but does not do antialiasing
. It can do convex | 1436 // This path renderer can draw all fill styles, but does not do antialiasing
. It can do convex |
1435 // and concave paths, but we'll leave the convex ones to simpler algorithms. | 1437 // and concave paths, but we'll leave the convex ones to simpler algorithms. |
1436 return stroke.isFillStyle() && !antiAlias && !path.isConvex(); | 1438 return stroke.isFillStyle() && !antiAlias && !path.isConvex(); |
1437 } | 1439 } |
1438 | 1440 |
| 1441 class TessellatingPathBatch : public GrBatch { |
| 1442 public: |
| 1443 |
| 1444 static GrBatch* Create(const GrColor& color, |
| 1445 const SkPath& path, |
| 1446 const SkMatrix& viewMatrix, |
| 1447 SkRect clipBounds) { |
| 1448 return SkNEW_ARGS(TessellatingPathBatch, (color, path, viewMatrix, clipB
ounds)); |
| 1449 } |
| 1450 |
| 1451 const char* name() const SK_OVERRIDE { return "TessellatingPathBatch"; } |
| 1452 |
| 1453 void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE { |
| 1454 out->setKnownFourComponents(fColor); |
| 1455 } |
| 1456 |
| 1457 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRID
E { |
| 1458 out->setUnknownSingleComponent(); |
| 1459 } |
| 1460 |
| 1461 void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE { |
| 1462 // Handle any color overrides |
| 1463 if (init.fColorIgnored) { |
| 1464 fColor = GrColor_ILLEGAL; |
| 1465 } else if (GrColor_ILLEGAL != init.fOverrideColor) { |
| 1466 fColor = init.fOverrideColor; |
| 1467 } |
| 1468 fPipelineInfo = init; |
| 1469 } |
| 1470 |
| 1471 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline
) SK_OVERRIDE { |
| 1472 SkScalar tol = GrPathUtils::scaleToleranceToSrc(SK_Scalar1, fViewMatrix,
fPath.getBounds()); |
| 1473 int contourCnt; |
| 1474 int maxPts = GrPathUtils::worstCasePointCount(fPath, &contourCnt, tol); |
| 1475 if (maxPts <= 0) { |
| 1476 return; |
| 1477 } |
| 1478 if (maxPts > ((int)SK_MaxU16 + 1)) { |
| 1479 SkDebugf("Path not rendered, too many verts (%d)\n", maxPts); |
| 1480 return; |
| 1481 } |
| 1482 SkPath::FillType fillType = fPath.getFillType(); |
| 1483 if (SkPath::IsInverseFillType(fillType)) { |
| 1484 contourCnt++; |
| 1485 } |
| 1486 |
| 1487 LOG("got %d pts, %d contours\n", maxPts, contourCnt); |
| 1488 uint32_t flags = GrDefaultGeoProcFactory::kPosition_GPType; |
| 1489 SkAutoTUnref<const GrGeometryProcessor> gp( |
| 1490 GrDefaultGeoProcFactory::Create(flags, fColor, fViewMatrix, SkMatrix
::I())); |
| 1491 batchTarget->initDraw(gp, pipeline); |
| 1492 gp->initBatchTracker(batchTarget->currentBatchTracker(), fPipelineInfo); |
| 1493 |
| 1494 SkAutoTDeleteArray<Vertex*> contours(SkNEW_ARRAY(Vertex *, contourCnt)); |
| 1495 |
| 1496 // For the initial size of the chunk allocator, estimate based on the po
int count: |
| 1497 // one vertex per point for the initial passes, plus two for the vertice
s in the |
| 1498 // resulting Polys, since the same point may end up in two Polys. Assum
e minimal |
| 1499 // connectivity of one Edge per Vertex (will grow for intersections). |
| 1500 SkChunkAlloc alloc(maxPts * (3 * sizeof(Vertex) + sizeof(Edge))); |
| 1501 path_to_contours(fPath, tol, fClipBounds, contours.get(), alloc); |
| 1502 Poly* polys; |
| 1503 polys = contours_to_polys(contours.get(), contourCnt, alloc); |
| 1504 int count = 0; |
| 1505 for (Poly* poly = polys; poly; poly = poly->fNext) { |
| 1506 if (apply_fill_type(fillType, poly->fWinding) && poly->fCount >= 3)
{ |
| 1507 count += (poly->fCount - 2) * (WIREFRAME ? 6 : 3); |
| 1508 } |
| 1509 } |
| 1510 |
| 1511 size_t stride = gp->getVertexStride(); |
| 1512 const GrVertexBuffer* vertexBuffer; |
| 1513 int firstVertex; |
| 1514 void* vertices = batchTarget->vertexPool()->makeSpace(stride, |
| 1515 count, |
| 1516 &vertexBuffer, |
| 1517 &firstVertex); |
| 1518 LOG("emitting %d verts\n", count); |
| 1519 void* end = polys_to_triangles(polys, fillType, vertices); |
| 1520 int actualCount = static_cast<int>( |
| 1521 (static_cast<char*>(end) - static_cast<char*>(vertices)) / stride); |
| 1522 LOG("actual count: %d\n", actualCount); |
| 1523 SkASSERT(actualCount <= count); |
| 1524 |
| 1525 GrPrimitiveType primitiveType = WIREFRAME ? kLines_GrPrimitiveType |
| 1526 : kTriangles_GrPrimitiveType; |
| 1527 GrDrawTarget::DrawInfo drawInfo; |
| 1528 drawInfo.setPrimitiveType(primitiveType); |
| 1529 drawInfo.setVertexBuffer(vertexBuffer); |
| 1530 drawInfo.setStartVertex(firstVertex); |
| 1531 drawInfo.setVertexCount(actualCount); |
| 1532 drawInfo.setStartIndex(0); |
| 1533 drawInfo.setIndexCount(0); |
| 1534 batchTarget->draw(drawInfo); |
| 1535 |
| 1536 batchTarget->putBackVertices((size_t)(count - actualCount), stride); |
| 1537 return; |
| 1538 } |
| 1539 |
| 1540 bool onCombineIfPossible(GrBatch*) SK_OVERRIDE { |
| 1541 return false; |
| 1542 } |
| 1543 |
| 1544 private: |
| 1545 TessellatingPathBatch(const GrColor& color, |
| 1546 const SkPath& path, |
| 1547 const SkMatrix& viewMatrix, |
| 1548 const SkRect& clipBounds) |
| 1549 : fColor(color) |
| 1550 , fPath(path) |
| 1551 , fViewMatrix(viewMatrix) |
| 1552 , fClipBounds(clipBounds) { |
| 1553 this->initClassID<TessellatingPathBatch>(); |
| 1554 } |
| 1555 |
| 1556 GrColor fColor; |
| 1557 SkPath fPath; |
| 1558 SkMatrix fViewMatrix; |
| 1559 SkRect fClipBounds; // in source space |
| 1560 GrPipelineInfo fPipelineInfo; |
| 1561 }; |
| 1562 |
1439 bool GrTessellatingPathRenderer::onDrawPath(GrDrawTarget* target, | 1563 bool GrTessellatingPathRenderer::onDrawPath(GrDrawTarget* target, |
1440 GrPipelineBuilder* pipelineBuilder, | 1564 GrPipelineBuilder* pipelineBuilder, |
1441 GrColor color, | 1565 GrColor color, |
1442 const SkMatrix& viewM, | 1566 const SkMatrix& viewM, |
1443 const SkPath& path, | 1567 const SkPath& path, |
1444 const SkStrokeRec& stroke, | 1568 const SkStrokeRec& stroke, |
1445 bool antiAlias) { | 1569 bool antiAlias) { |
1446 SkASSERT(!antiAlias); | 1570 SkASSERT(!antiAlias); |
1447 const GrRenderTarget* rt = pipelineBuilder->getRenderTarget(); | 1571 const GrRenderTarget* rt = pipelineBuilder->getRenderTarget(); |
1448 if (NULL == rt) { | 1572 if (NULL == rt) { |
1449 return false; | 1573 return false; |
1450 } | 1574 } |
1451 | 1575 |
1452 SkScalar tol = GrPathUtils::scaleToleranceToSrc(SK_Scalar1, viewM, path.getB
ounds()); | |
1453 | |
1454 int contourCnt; | |
1455 int maxPts = GrPathUtils::worstCasePointCount(path, &contourCnt, tol); | |
1456 if (maxPts <= 0) { | |
1457 return false; | |
1458 } | |
1459 if (maxPts > ((int)SK_MaxU16 + 1)) { | |
1460 SkDebugf("Path not rendered, too many verts (%d)\n", maxPts); | |
1461 return false; | |
1462 } | |
1463 SkPath::FillType fillType = path.getFillType(); | |
1464 if (SkPath::IsInverseFillType(fillType)) { | |
1465 contourCnt++; | |
1466 } | |
1467 | |
1468 LOG("got %d pts, %d contours\n", maxPts, contourCnt); | |
1469 | |
1470 SkAutoTDeleteArray<Vertex*> contours(SkNEW_ARRAY(Vertex *, contourCnt)); | |
1471 | |
1472 // For the initial size of the chunk allocator, estimate based on the point
count: | |
1473 // one vertex per point for the initial passes, plus two for the vertices in
the | |
1474 // resulting Polys, since the same point may end up in two Polys. Assume mi
nimal | |
1475 // connectivity of one Edge per Vertex (will grow for intersections). | |
1476 SkChunkAlloc alloc(maxPts * (3 * sizeof(Vertex) + sizeof(Edge))); | |
1477 SkIRect clipBoundsI; | 1576 SkIRect clipBoundsI; |
1478 pipelineBuilder->clip().getConservativeBounds(rt, &clipBoundsI); | 1577 pipelineBuilder->clip().getConservativeBounds(rt, &clipBoundsI); |
1479 SkRect clipBounds = SkRect::Make(clipBoundsI); | 1578 SkRect clipBounds = SkRect::Make(clipBoundsI); |
1480 SkMatrix vmi; | 1579 SkMatrix vmi; |
1481 if (!viewM.invert(&vmi)) { | 1580 if (!viewM.invert(&vmi)) { |
1482 return false; | 1581 return false; |
1483 } | 1582 } |
1484 vmi.mapRect(&clipBounds); | 1583 vmi.mapRect(&clipBounds); |
1485 path_to_contours(path, tol, clipBounds, contours.get(), alloc); | 1584 SkAutoTUnref<GrBatch> batch(TessellatingPathBatch::Create(color, path, viewM
, clipBounds)); |
1486 Poly* polys; | 1585 target->drawBatch(pipelineBuilder, batch); |
1487 uint32_t flags = GrDefaultGeoProcFactory::kPosition_GPType; | |
1488 polys = contours_to_polys(contours.get(), contourCnt, alloc); | |
1489 SkAutoTUnref<const GrGeometryProcessor> gp( | |
1490 GrDefaultGeoProcFactory::Create(flags, color, viewM, SkMatrix::I())); | |
1491 int count = 0; | |
1492 for (Poly* poly = polys; poly; poly = poly->fNext) { | |
1493 if (apply_fill_type(fillType, poly->fWinding) && poly->fCount >= 3) { | |
1494 count += (poly->fCount - 2) * (WIREFRAME ? 6 : 3); | |
1495 } | |
1496 } | |
1497 | |
1498 size_t stride = gp->getVertexStride(); | |
1499 GrDrawTarget::AutoReleaseGeometry arg; | |
1500 if (!arg.set(target, count, stride, 0)) { | |
1501 return false; | |
1502 } | |
1503 LOG("emitting %d verts\n", count); | |
1504 void* end = polys_to_triangles(polys, fillType, arg.vertices()); | |
1505 int actualCount = static_cast<int>((static_cast<char*>(end) - static_cast<ch
ar*>(arg.vertices())) / stride); | |
1506 LOG("actual count: %d\n", actualCount); | |
1507 SkASSERT(actualCount <= count); | |
1508 | |
1509 GrPrimitiveType primitiveType = WIREFRAME ? kLines_GrPrimitiveType | |
1510 : kTriangles_GrPrimitiveType; | |
1511 target->drawNonIndexed(pipelineBuilder, gp, primitiveType, 0, actualCount); | |
1512 | 1586 |
1513 return true; | 1587 return true; |
1514 } | 1588 } |
OLD | NEW |