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" |
11 #include "GrBatchTarget.h" | 11 #include "GrBatchTarget.h" |
12 #include "GrBatchTest.h" | 12 #include "GrBatchTest.h" |
13 #include "GrDefaultGeoProcFactory.h" | 13 #include "GrDefaultGeoProcFactory.h" |
14 #include "GrPathUtils.h" | 14 #include "GrPathUtils.h" |
15 #include "GrVertices.h" | 15 #include "GrVertices.h" |
16 #include "GrResourceCache.h" | |
17 #include "GrResourceProvider.h" | |
16 #include "SkChunkAlloc.h" | 18 #include "SkChunkAlloc.h" |
17 #include "SkGeometry.h" | 19 #include "SkGeometry.h" |
18 | 20 |
19 #include <stdio.h> | 21 #include <stdio.h> |
20 | 22 |
21 /* | 23 /* |
22 * This path renderer tessellates the path into triangles, uploads the triangles to a | 24 * This path renderer tessellates the path into triangles, uploads the triangles to a |
23 * vertex buffer, and renders them with a single draw call. It does not currentl y do | 25 * vertex buffer, and renders them with a single draw call. It does not currentl y do |
24 * antialiasing, so it must be used in conjunction with multisampling. | 26 * antialiasing, so it must be used in conjunction with multisampling. |
25 * | 27 * |
(...skipping 505 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
531 const SkPoint s = { SkScalarAve(r[0].fX, r[1].fX), SkScalarAve(r[0].fY, r[1] .fY) }; | 533 const SkPoint s = { SkScalarAve(r[0].fX, r[1].fX), SkScalarAve(r[0].fY, r[1] .fY) }; |
532 pointsLeft >>= 1; | 534 pointsLeft >>= 1; |
533 prev = generate_cubic_points(p0, q[0], r[0], s, tolSqd, prev, head, pointsLe ft, alloc); | 535 prev = generate_cubic_points(p0, q[0], r[0], s, tolSqd, prev, head, pointsLe ft, alloc); |
534 prev = generate_cubic_points(s, r[1], q[2], p3, tolSqd, prev, head, pointsLe ft, alloc); | 536 prev = generate_cubic_points(s, r[1], q[2], p3, tolSqd, prev, head, pointsLe ft, alloc); |
535 return prev; | 537 return prev; |
536 } | 538 } |
537 | 539 |
538 // Stage 1: convert the input path to a set of linear contours (linked list of V ertices). | 540 // Stage 1: convert the input path to a set of linear contours (linked list of V ertices). |
539 | 541 |
540 void path_to_contours(const SkPath& path, SkScalar tolerance, const SkRect& clip Bounds, | 542 void path_to_contours(const SkPath& path, SkScalar tolerance, const SkRect& clip Bounds, |
541 Vertex** contours, SkChunkAlloc& alloc) { | 543 Vertex** contours, SkChunkAlloc& alloc, bool *isLinear) { |
542 | 544 |
543 SkScalar toleranceSqd = tolerance * tolerance; | 545 SkScalar toleranceSqd = tolerance * tolerance; |
544 | 546 |
545 SkPoint pts[4]; | 547 SkPoint pts[4]; |
546 bool done = false; | 548 bool done = false; |
549 *isLinear = true; | |
547 SkPath::Iter iter(path, false); | 550 SkPath::Iter iter(path, false); |
548 Vertex* prev = NULL; | 551 Vertex* prev = NULL; |
549 Vertex* head = NULL; | 552 Vertex* head = NULL; |
550 if (path.isInverseFillType()) { | 553 if (path.isInverseFillType()) { |
551 SkPoint quad[4]; | 554 SkPoint quad[4]; |
552 clipBounds.toQuad(quad); | 555 clipBounds.toQuad(quad); |
553 for (int i = 3; i >= 0; i--) { | 556 for (int i = 3; i >= 0; i--) { |
554 prev = append_point_to_contour(quad[i], prev, &head, alloc); | 557 prev = append_point_to_contour(quad[i], prev, &head, alloc); |
555 } | 558 } |
556 head->fPrev = prev; | 559 head->fPrev = prev; |
557 prev->fNext = head; | 560 prev->fNext = head; |
558 *contours++ = head; | 561 *contours++ = head; |
559 head = prev = NULL; | 562 head = prev = NULL; |
560 } | 563 } |
561 SkAutoConicToQuads converter; | 564 SkAutoConicToQuads converter; |
562 while (!done) { | 565 while (!done) { |
563 SkPath::Verb verb = iter.next(pts); | 566 SkPath::Verb verb = iter.next(pts); |
564 switch (verb) { | 567 switch (verb) { |
565 case SkPath::kConic_Verb: { | 568 case SkPath::kConic_Verb: { |
566 SkScalar weight = iter.conicWeight(); | 569 SkScalar weight = iter.conicWeight(); |
567 const SkPoint* quadPts = converter.computeQuads(pts, weight, tol eranceSqd); | 570 const SkPoint* quadPts = converter.computeQuads(pts, weight, tol eranceSqd); |
568 for (int i = 0; i < converter.countQuads(); ++i) { | 571 for (int i = 0; i < converter.countQuads(); ++i) { |
569 int pointsLeft = GrPathUtils::quadraticPointCount(quadPts, t olerance); | 572 int pointsLeft = GrPathUtils::quadraticPointCount(quadPts, t olerance); |
570 prev = generate_quadratic_points(quadPts[0], quadPts[1], qua dPts[2], | 573 prev = generate_quadratic_points(quadPts[0], quadPts[1], qua dPts[2], |
571 toleranceSqd, prev, &head, pointsLeft, alloc); | 574 toleranceSqd, prev, &head, pointsLeft, alloc); |
572 quadPts += 2; | 575 quadPts += 2; |
573 } | 576 } |
577 *isLinear = false; | |
574 break; | 578 break; |
575 } | 579 } |
576 case SkPath::kMove_Verb: | 580 case SkPath::kMove_Verb: |
577 if (head) { | 581 if (head) { |
578 head->fPrev = prev; | 582 head->fPrev = prev; |
579 prev->fNext = head; | 583 prev->fNext = head; |
580 *contours++ = head; | 584 *contours++ = head; |
581 } | 585 } |
582 head = prev = NULL; | 586 head = prev = NULL; |
583 prev = append_point_to_contour(pts[0], prev, &head, alloc); | 587 prev = append_point_to_contour(pts[0], prev, &head, alloc); |
584 break; | 588 break; |
585 case SkPath::kLine_Verb: { | 589 case SkPath::kLine_Verb: { |
586 prev = append_point_to_contour(pts[1], prev, &head, alloc); | 590 prev = append_point_to_contour(pts[1], prev, &head, alloc); |
587 break; | 591 break; |
588 } | 592 } |
589 case SkPath::kQuad_Verb: { | 593 case SkPath::kQuad_Verb: { |
590 int pointsLeft = GrPathUtils::quadraticPointCount(pts, tolerance ); | 594 int pointsLeft = GrPathUtils::quadraticPointCount(pts, tolerance ); |
591 prev = generate_quadratic_points(pts[0], pts[1], pts[2], toleran ceSqd, prev, | 595 prev = generate_quadratic_points(pts[0], pts[1], pts[2], toleran ceSqd, prev, |
592 &head, pointsLeft, alloc); | 596 &head, pointsLeft, alloc); |
597 *isLinear = false; | |
593 break; | 598 break; |
594 } | 599 } |
595 case SkPath::kCubic_Verb: { | 600 case SkPath::kCubic_Verb: { |
596 int pointsLeft = GrPathUtils::cubicPointCount(pts, tolerance); | 601 int pointsLeft = GrPathUtils::cubicPointCount(pts, tolerance); |
597 prev = generate_cubic_points(pts[0], pts[1], pts[2], pts[3], | 602 prev = generate_cubic_points(pts[0], pts[1], pts[2], pts[3], |
598 toleranceSqd, prev, &head, pointsLeft, alloc); | 603 toleranceSqd, prev, &head, pointsLeft, alloc); |
604 *isLinear = false; | |
599 break; | 605 break; |
600 } | 606 } |
601 case SkPath::kClose_Verb: | 607 case SkPath::kClose_Verb: |
602 if (head) { | 608 if (head) { |
603 head->fPrev = prev; | 609 head->fPrev = prev; |
604 prev->fNext = head; | 610 prev->fNext = head; |
605 *contours++ = head; | 611 *contours++ = head; |
606 } | 612 } |
607 head = prev = NULL; | 613 head = prev = NULL; |
608 break; | 614 break; |
(...skipping 713 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1322 SkPoint* polys_to_triangles(Poly* polys, SkPath::FillType fillType, SkPoint* dat a) { | 1328 SkPoint* polys_to_triangles(Poly* polys, SkPath::FillType fillType, SkPoint* dat a) { |
1323 SkPoint* d = data; | 1329 SkPoint* d = data; |
1324 for (Poly* poly = polys; poly; poly = poly->fNext) { | 1330 for (Poly* poly = polys; poly; poly = poly->fNext) { |
1325 if (apply_fill_type(fillType, poly->fWinding)) { | 1331 if (apply_fill_type(fillType, poly->fWinding)) { |
1326 d = poly->emit(d); | 1332 d = poly->emit(d); |
1327 } | 1333 } |
1328 } | 1334 } |
1329 return d; | 1335 return d; |
1330 } | 1336 } |
1331 | 1337 |
1338 bool cacheMatch(GrVertexBuffer* vertexBuffer, const SkMatrix& newMatrix) { | |
1339 if (!vertexBuffer) { | |
1340 return false; | |
1341 } | |
1342 const SkData* data = vertexBuffer->getCustomData(); | |
1343 if (!data || !data->data()) { // path is linear; matches any scale | |
1344 return true; | |
1345 } | |
1346 const SkSize* cachedScale = static_cast<const SkSize*>(data->data()); | |
bsalomon
2015/07/28 14:55:48
Rather than use the data on the VB, can we canonic
Stephen White
2015/07/28 15:10:28
I could do that, but then a single path with an an
bsalomon
2015/07/28 21:23:30
That makes sense. I wonder if there is an efficien
Stephen White
2015/07/28 22:11:23
I've done the latter (I think..)
| |
1347 SkASSERT(cachedScale); | |
1348 SkSize newScale; | |
1349 if (!newMatrix.decomposeScale(&newScale)) { | |
1350 return false; | |
1351 } | |
1352 if (newScale.width() > 0.01f * cachedScale->width() && newScale.width() < 3. 0f * cachedScale->width() | |
1353 && newScale.height() > 0.01f * cachedScale->height() && newScale.height() < 3.0f * cachedScale->height()) { | |
1354 return true; | |
1355 } | |
1356 return false; | |
1357 } | |
1358 | |
1332 }; | 1359 }; |
1333 | 1360 |
1334 GrTessellatingPathRenderer::GrTessellatingPathRenderer() { | 1361 GrTessellatingPathRenderer::GrTessellatingPathRenderer(GrContext* context) : fCo ntext(context) { |
1335 } | 1362 } |
1336 | 1363 |
1337 GrPathRenderer::StencilSupport GrTessellatingPathRenderer::onGetStencilSupport( | 1364 GrPathRenderer::StencilSupport GrTessellatingPathRenderer::onGetStencilSupport( |
1338 const GrDrawTarget*, | 1365 const GrDrawTarget*, |
1339 const GrPipelineBuil der*, | 1366 const GrPipelineBuil der*, |
1340 const SkPath&, | 1367 const SkPath&, |
1341 const GrStrokeInfo&) const { | 1368 const GrStrokeInfo&) const { |
1342 return GrPathRenderer::kNoSupport_StencilSupport; | 1369 return GrPathRenderer::kNoSupport_StencilSupport; |
1343 } | 1370 } |
1344 | 1371 |
1372 namespace { | |
1373 | |
1374 // When the SkPathRef genID changes, invalidate a corresponding GrResource descr ibed by key. | |
1375 class PathInvalidator : public SkPathRef::GenIDChangeListener { | |
1376 public: | |
1377 explicit PathInvalidator(const GrUniqueKey& key) : fMsg(key) {} | |
1378 private: | |
1379 GrUniqueKeyInvalidatedMessage fMsg; | |
1380 | |
1381 void onChange() override { | |
1382 SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg); | |
1383 } | |
1384 }; | |
1385 | |
1386 } // namespace | |
1387 | |
1388 | |
1345 bool GrTessellatingPathRenderer::canDrawPath(const GrDrawTarget* target, | 1389 bool GrTessellatingPathRenderer::canDrawPath(const GrDrawTarget* target, |
1346 const GrPipelineBuilder* pipelineBu ilder, | 1390 const GrPipelineBuilder* pipelineBu ilder, |
1347 const SkMatrix& viewMatrix, | 1391 const SkMatrix& viewMatrix, |
1348 const SkPath& path, | 1392 const SkPath& path, |
1349 const GrStrokeInfo& stroke, | 1393 const GrStrokeInfo& stroke, |
1350 bool antiAlias) const { | 1394 bool antiAlias) const { |
1351 // This path renderer can draw all fill styles, but does not do antialiasing . It can do convex | 1395 // This path renderer can draw all fill styles, but does not do antialiasing . It can do convex |
1352 // and concave paths, but we'll leave the convex ones to simpler algorithms. | 1396 // and concave paths, but we'll leave the convex ones to simpler algorithms. |
1353 return stroke.isFillStyle() && !antiAlias && !path.isConvex(); | 1397 return stroke.isFillStyle() && !antiAlias && !path.isConvex(); |
1354 } | 1398 } |
1355 | 1399 |
1356 class TessellatingPathBatch : public GrBatch { | 1400 class TessellatingPathBatch : public GrBatch { |
1357 public: | 1401 public: |
1358 | 1402 |
1359 static GrBatch* Create(const GrColor& color, | 1403 static GrBatch* Create(const GrColor& color, |
1360 const SkPath& path, | 1404 const SkPath& path, |
1361 const SkMatrix& viewMatrix, | 1405 const SkMatrix& viewMatrix, |
1362 SkRect clipBounds) { | 1406 SkRect clipBounds, |
1363 return SkNEW_ARGS(TessellatingPathBatch, (color, path, viewMatrix, clipB ounds)); | 1407 GrContext* context) { |
1408 return SkNEW_ARGS(TessellatingPathBatch, (color, path, viewMatrix, clipB ounds, context)); | |
1364 } | 1409 } |
1365 | 1410 |
1366 const char* name() const override { return "TessellatingPathBatch"; } | 1411 const char* name() const override { return "TessellatingPathBatch"; } |
1367 | 1412 |
1368 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { | 1413 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { |
1369 out->setKnownFourComponents(fColor); | 1414 out->setKnownFourComponents(fColor); |
1370 } | 1415 } |
1371 | 1416 |
1372 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { | 1417 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { |
1373 out->setUnknownSingleComponent(); | 1418 out->setUnknownSingleComponent(); |
1374 } | 1419 } |
1375 | 1420 |
1376 void initBatchTracker(const GrPipelineInfo& init) override { | 1421 void initBatchTracker(const GrPipelineInfo& init) override { |
1377 // Handle any color overrides | 1422 // Handle any color overrides |
1378 if (!init.readsColor()) { | 1423 if (!init.readsColor()) { |
1379 fColor = GrColor_ILLEGAL; | 1424 fColor = GrColor_ILLEGAL; |
1380 } | 1425 } |
1381 init.getOverrideColorIfSet(&fColor); | 1426 init.getOverrideColorIfSet(&fColor); |
1382 fPipelineInfo = init; | 1427 fPipelineInfo = init; |
1383 } | 1428 } |
1384 | 1429 |
1385 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline ) override { | 1430 int tessellate(const GrUniqueKey& key, SkAutoTUnref<GrVertexBuffer>& vertexB uffer) { |
1386 SkRect pathBounds = fPath.getBounds(); | 1431 SkRect pathBounds = fPath.getBounds(); |
1387 Comparator c; | 1432 Comparator c; |
1388 if (pathBounds.width() > pathBounds.height()) { | 1433 if (pathBounds.width() > pathBounds.height()) { |
1389 c.sweep_lt = sweep_lt_horiz; | 1434 c.sweep_lt = sweep_lt_horiz; |
1390 c.sweep_gt = sweep_gt_horiz; | 1435 c.sweep_gt = sweep_gt_horiz; |
1391 } else { | 1436 } else { |
1392 c.sweep_lt = sweep_lt_vert; | 1437 c.sweep_lt = sweep_lt_vert; |
1393 c.sweep_gt = sweep_gt_vert; | 1438 c.sweep_gt = sweep_gt_vert; |
1394 } | 1439 } |
1395 SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; | 1440 SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; |
1396 SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, fViewMat rix, pathBounds); | 1441 SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, fViewMat rix, pathBounds); |
1397 int contourCnt; | 1442 int contourCnt; |
1398 int maxPts = GrPathUtils::worstCasePointCount(fPath, &contourCnt, tol); | 1443 int maxPts = GrPathUtils::worstCasePointCount(fPath, &contourCnt, tol); |
1399 if (maxPts <= 0) { | 1444 if (maxPts <= 0) { |
1400 return; | 1445 return 0; |
1401 } | 1446 } |
1402 if (maxPts > ((int)SK_MaxU16 + 1)) { | 1447 if (maxPts > ((int)SK_MaxU16 + 1)) { |
1403 SkDebugf("Path not rendered, too many verts (%d)\n", maxPts); | 1448 SkDebugf("Path not rendered, too many verts (%d)\n", maxPts); |
1404 return; | 1449 return 0; |
1405 } | 1450 } |
1406 SkPath::FillType fillType = fPath.getFillType(); | 1451 SkPath::FillType fillType = fPath.getFillType(); |
1407 if (SkPath::IsInverseFillType(fillType)) { | 1452 if (SkPath::IsInverseFillType(fillType)) { |
1408 contourCnt++; | 1453 contourCnt++; |
1409 } | 1454 } |
1410 | 1455 |
1411 LOG("got %d pts, %d contours\n", maxPts, contourCnt); | 1456 LOG("got %d pts, %d contours\n", maxPts, contourCnt); |
1412 uint32_t flags = GrDefaultGeoProcFactory::kPosition_GPType; | |
1413 SkAutoTUnref<const GrGeometryProcessor> gp( | |
1414 GrDefaultGeoProcFactory::Create(flags, fColor, fPipelineInfo.readsLo calCoords(), | |
1415 !fPipelineInfo.readsCoverage(), fVie wMatrix, | |
1416 SkMatrix::I())); | |
1417 batchTarget->initDraw(gp, pipeline); | |
1418 | |
1419 SkAutoTDeleteArray<Vertex*> contours(SkNEW_ARRAY(Vertex *, contourCnt)); | 1457 SkAutoTDeleteArray<Vertex*> contours(SkNEW_ARRAY(Vertex *, contourCnt)); |
1420 | 1458 |
1421 // For the initial size of the chunk allocator, estimate based on the po int count: | 1459 // For the initial size of the chunk allocator, estimate based on the po int count: |
1422 // one vertex per point for the initial passes, plus two for the vertice s in the | 1460 // one vertex per point for the initial passes, plus two for the vertice s in the |
1423 // resulting Polys, since the same point may end up in two Polys. Assum e minimal | 1461 // resulting Polys, since the same point may end up in two Polys. Assum e minimal |
1424 // connectivity of one Edge per Vertex (will grow for intersections). | 1462 // connectivity of one Edge per Vertex (will grow for intersections). |
1425 SkChunkAlloc alloc(maxPts * (3 * sizeof(Vertex) + sizeof(Edge))); | 1463 SkChunkAlloc alloc(maxPts * (3 * sizeof(Vertex) + sizeof(Edge))); |
1426 path_to_contours(fPath, tol, fClipBounds, contours.get(), alloc); | 1464 bool isLinear; |
1465 path_to_contours(fPath, tol, fClipBounds, contours.get(), alloc, &isLine ar); | |
1427 Poly* polys; | 1466 Poly* polys; |
1428 polys = contours_to_polys(contours.get(), contourCnt, c, alloc); | 1467 polys = contours_to_polys(contours.get(), contourCnt, c, alloc); |
1429 int count = 0; | 1468 int count = 0; |
1430 for (Poly* poly = polys; poly; poly = poly->fNext) { | 1469 for (Poly* poly = polys; poly; poly = poly->fNext) { |
1431 if (apply_fill_type(fillType, poly->fWinding) && poly->fCount >= 3) { | 1470 if (apply_fill_type(fillType, poly->fWinding) && poly->fCount >= 3) { |
1432 count += (poly->fCount - 2) * (WIREFRAME ? 6 : 3); | 1471 count += (poly->fCount - 2) * (WIREFRAME ? 6 : 3); |
1433 } | 1472 } |
1434 } | 1473 } |
1435 if (0 == count) { | 1474 if (0 == count) { |
1436 return; | 1475 return 0; |
1437 } | 1476 } |
1438 | 1477 |
1439 size_t stride = gp->getVertexStride(); | 1478 vertexBuffer.reset(fContext->getGpu()->createVertexBuffer(count * sizeof (SkPoint), false)); |
1440 SkASSERT(stride == sizeof(SkPoint)); | 1479 if (!vertexBuffer.get()) { |
1441 const GrVertexBuffer* vertexBuffer; | |
1442 int firstVertex; | |
1443 SkPoint* verts = static_cast<SkPoint*>( | |
1444 batchTarget->makeVertSpace(stride, count, &vertexBuffer, &firstVerte x)); | |
1445 if (!verts) { | |
1446 SkDebugf("Could not allocate vertices\n"); | 1480 SkDebugf("Could not allocate vertices\n"); |
1447 return; | 1481 return 0; |
1448 } | 1482 } |
1449 | 1483 SkPoint* verts = static_cast<SkPoint*>(vertexBuffer->map()); |
1450 LOG("emitting %d verts\n", count); | 1484 LOG("emitting %d verts\n", count); |
1451 SkPoint* end = polys_to_triangles(polys, fillType, verts); | 1485 SkPoint* end = polys_to_triangles(polys, fillType, verts); |
1486 vertexBuffer->unmap(); | |
1452 int actualCount = static_cast<int>(end - verts); | 1487 int actualCount = static_cast<int>(end - verts); |
1453 LOG("actual count: %d\n", actualCount); | 1488 LOG("actual count: %d\n", actualCount); |
1454 SkASSERT(actualCount <= count); | 1489 SkASSERT(actualCount <= count); |
1455 | 1490 |
1491 if (!fPath.isVolatile()) { | |
1492 SkSize scale; | |
1493 if (!isLinear && fViewMatrix.decomposeScale(&scale)) { | |
1494 vertexBuffer->setCustomData(SkData::NewWithCopy(&scale, sizeof(s cale))); | |
1495 } | |
1496 fContext->resourceProvider()->assignUniqueKeyToResource(key, vertexB uffer.get()); | |
1497 fPath.pathRef()->addGenIDChangeListener(SkNEW(PathInvalidator(key))) ; | |
1498 } | |
1499 return actualCount; | |
1500 } | |
1501 | |
1502 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline ) override { | |
1503 // construct a cache key from the path's genID and the view matrix | |
1504 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain() ; | |
1505 GrUniqueKey key; | |
1506 GrUniqueKey::Builder builder(&key, kDomain, 1); | |
1507 builder[0] = fPath.getGenerationID(); | |
1508 builder.finish(); | |
1509 SkAutoTUnref<GrVertexBuffer> vertexBuffer(fContext->resourceProvider()-> findAndRefTByUniqueKey<GrVertexBuffer>(key)); | |
1510 int actualCount; | |
1511 if (cacheMatch(vertexBuffer.get(), fViewMatrix)) { | |
1512 actualCount = vertexBuffer->gpuMemorySize() / sizeof(SkPoint); | |
1513 } else { | |
1514 actualCount = tessellate(key, vertexBuffer); | |
1515 } | |
1516 | |
1517 if (actualCount == 0) { | |
1518 return; | |
1519 } | |
1520 | |
1521 uint32_t flags = GrDefaultGeoProcFactory::kPosition_GPType; | |
1522 SkAutoTUnref<const GrGeometryProcessor> gp( | |
1523 GrDefaultGeoProcFactory::Create(flags, fColor, fPipelineInfo.readsLo calCoords(), | |
1524 !fPipelineInfo.readsCoverage(), fVie wMatrix, | |
1525 SkMatrix::I())); | |
1526 batchTarget->initDraw(gp, pipeline); | |
1527 SkASSERT(gp->getVertexStride() == sizeof(SkPoint)); | |
1528 | |
1456 GrPrimitiveType primitiveType = WIREFRAME ? kLines_GrPrimitiveType | 1529 GrPrimitiveType primitiveType = WIREFRAME ? kLines_GrPrimitiveType |
1457 : kTriangles_GrPrimitiveType; | 1530 : kTriangles_GrPrimitiveType; |
1458 GrVertices vertices; | 1531 GrVertices vertices; |
1459 vertices.init(primitiveType, vertexBuffer, firstVertex, actualCount); | 1532 vertices.init(primitiveType, vertexBuffer.get(), 0, actualCount); |
1460 batchTarget->draw(vertices); | 1533 batchTarget->draw(vertices); |
1461 | |
1462 batchTarget->putBackVertices((size_t)(count - actualCount), stride); | |
1463 return; | |
1464 } | 1534 } |
1465 | 1535 |
1466 bool onCombineIfPossible(GrBatch*) override { | 1536 bool onCombineIfPossible(GrBatch*) override { |
1467 return false; | 1537 return false; |
1468 } | 1538 } |
1469 | 1539 |
1470 private: | 1540 private: |
1471 TessellatingPathBatch(const GrColor& color, | 1541 TessellatingPathBatch(const GrColor& color, |
1472 const SkPath& path, | 1542 const SkPath& path, |
1473 const SkMatrix& viewMatrix, | 1543 const SkMatrix& viewMatrix, |
1474 const SkRect& clipBounds) | 1544 const SkRect& clipBounds, |
1545 GrContext* context) | |
1475 : fColor(color) | 1546 : fColor(color) |
1476 , fPath(path) | 1547 , fPath(path) |
1477 , fViewMatrix(viewMatrix) | 1548 , fViewMatrix(viewMatrix) |
1478 , fClipBounds(clipBounds) { | 1549 , fClipBounds(clipBounds) |
1550 , fContext(context) { | |
1479 this->initClassID<TessellatingPathBatch>(); | 1551 this->initClassID<TessellatingPathBatch>(); |
1480 | 1552 |
1481 fBounds = path.getBounds(); | 1553 fBounds = path.getBounds(); |
1482 viewMatrix.mapRect(&fBounds); | 1554 viewMatrix.mapRect(&fBounds); |
1483 } | 1555 } |
1484 | 1556 |
1485 GrColor fColor; | 1557 GrColor fColor; |
1486 SkPath fPath; | 1558 SkPath fPath; |
1487 SkMatrix fViewMatrix; | 1559 SkMatrix fViewMatrix; |
1488 SkRect fClipBounds; // in source space | 1560 SkRect fClipBounds; // in source space |
1561 GrContext* fContext; | |
1489 GrPipelineInfo fPipelineInfo; | 1562 GrPipelineInfo fPipelineInfo; |
1490 }; | 1563 }; |
1491 | 1564 |
1492 bool GrTessellatingPathRenderer::onDrawPath(GrDrawTarget* target, | 1565 bool GrTessellatingPathRenderer::onDrawPath(GrDrawTarget* target, |
1493 GrPipelineBuilder* pipelineBuilder, | 1566 GrPipelineBuilder* pipelineBuilder, |
1494 GrColor color, | 1567 GrColor color, |
1495 const SkMatrix& viewM, | 1568 const SkMatrix& viewM, |
1496 const SkPath& path, | 1569 const SkPath& path, |
1497 const GrStrokeInfo&, | 1570 const GrStrokeInfo&, |
1498 bool antiAlias) { | 1571 bool antiAlias) { |
1499 SkASSERT(!antiAlias); | 1572 SkASSERT(!antiAlias); |
1500 const GrRenderTarget* rt = pipelineBuilder->getRenderTarget(); | 1573 const GrRenderTarget* rt = pipelineBuilder->getRenderTarget(); |
1501 if (NULL == rt) { | 1574 if (NULL == rt) { |
1502 return false; | 1575 return false; |
1503 } | 1576 } |
1504 | 1577 |
1505 SkIRect clipBoundsI; | 1578 SkIRect clipBoundsI; |
1506 pipelineBuilder->clip().getConservativeBounds(rt, &clipBoundsI); | 1579 pipelineBuilder->clip().getConservativeBounds(rt, &clipBoundsI); |
1507 SkRect clipBounds = SkRect::Make(clipBoundsI); | 1580 SkRect clipBounds = SkRect::Make(clipBoundsI); |
1508 SkMatrix vmi; | 1581 SkMatrix vmi; |
1509 if (!viewM.invert(&vmi)) { | 1582 if (!viewM.invert(&vmi)) { |
1510 return false; | 1583 return false; |
1511 } | 1584 } |
1512 vmi.mapRect(&clipBounds); | 1585 vmi.mapRect(&clipBounds); |
1513 SkAutoTUnref<GrBatch> batch(TessellatingPathBatch::Create(color, path, viewM , clipBounds)); | 1586 SkAutoTUnref<GrBatch> batch(TessellatingPathBatch::Create(color, path, viewM , clipBounds, fContext)); |
1514 target->drawBatch(*pipelineBuilder, batch); | 1587 target->drawBatch(*pipelineBuilder, batch); |
1515 | 1588 |
1516 return true; | 1589 return true; |
1517 } | 1590 } |
1518 | 1591 |
1519 //////////////////////////////////////////////////////////////////////////////// /////////////////// | 1592 //////////////////////////////////////////////////////////////////////////////// /////////////////// |
1520 | 1593 |
1521 #ifdef GR_TEST_UTILS | 1594 #ifdef GR_TEST_UTILS |
1522 | 1595 |
1523 BATCH_TEST_DEFINE(TesselatingPathBatch) { | 1596 BATCH_TEST_DEFINE(TesselatingPathBatch) { |
1524 GrColor color = GrRandomColor(random); | 1597 GrColor color = GrRandomColor(random); |
1525 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); | 1598 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random); |
1526 SkPath path = GrTest::TestPath(random); | 1599 SkPath path = GrTest::TestPath(random); |
1527 SkRect clipBounds = GrTest::TestRect(random); | 1600 SkRect clipBounds = GrTest::TestRect(random); |
1528 SkMatrix vmi; | 1601 SkMatrix vmi; |
1529 bool result = viewMatrix.invert(&vmi); | 1602 bool result = viewMatrix.invert(&vmi); |
1530 if (!result) { | 1603 if (!result) { |
1531 SkFAIL("Cannot invert matrix\n"); | 1604 SkFAIL("Cannot invert matrix\n"); |
1532 } | 1605 } |
1533 vmi.mapRect(&clipBounds); | 1606 vmi.mapRect(&clipBounds); |
1534 return TessellatingPathBatch::Create(color, path, viewMatrix, clipBounds); | 1607 return TessellatingPathBatch::Create(color, path, viewMatrix, clipBounds, co ntext); |
1535 } | 1608 } |
1536 | 1609 |
1537 #endif | 1610 #endif |
OLD | NEW |