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

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

Issue 1114353004: Implement vertex buffer caching in the tessellated path renderer. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Merge resource cache fix, leak fix, inverse winding fix 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
« no previous file with comments | « src/core/SkPathRef.cpp ('k') | tests/PathTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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"
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
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
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 struct TessInfo {
1339 SkScalar fTolerance;
1340 int fCount;
1341 };
1342
1343 bool cache_match(GrVertexBuffer* vertexBuffer, SkScalar tol, int* actualCount) {
1344 if (!vertexBuffer) {
1345 return false;
1346 }
1347 const SkData* data = vertexBuffer->getUniqueKey().getCustomData();
1348 SkASSERT(data);
1349 const TessInfo* info = static_cast<const TessInfo*>(data->data());
1350 if (info->fTolerance == 0 || info->fTolerance < 3.0f * tol) {
1351 *actualCount = info->fCount;
1352 return true;
1353 }
1354 return false;
1355 }
1356
1332 }; 1357 };
1333 1358
1334 GrTessellatingPathRenderer::GrTessellatingPathRenderer() { 1359 GrTessellatingPathRenderer::GrTessellatingPathRenderer() {
1335 } 1360 }
1336 1361
1337 GrPathRenderer::StencilSupport GrTessellatingPathRenderer::onGetStencilSupport( 1362 GrPathRenderer::StencilSupport GrTessellatingPathRenderer::onGetStencilSupport(
1338 const GrDrawTarget*, 1363 const GrDrawTarget*,
1339 const GrPipelineBuil der*, 1364 const GrPipelineBuil der*,
1340 const SkPath&, 1365 const SkPath&,
1341 const GrStrokeInfo&) const { 1366 const GrStrokeInfo&) const {
1342 return GrPathRenderer::kNoSupport_StencilSupport; 1367 return GrPathRenderer::kNoSupport_StencilSupport;
1343 } 1368 }
1344 1369
1370 namespace {
1371
1372 // When the SkPathRef genID changes, invalidate a corresponding GrResource descr ibed by key.
1373 class PathInvalidator : public SkPathRef::GenIDChangeListener {
1374 public:
1375 explicit PathInvalidator(const GrUniqueKey& key) : fMsg(key) {}
1376 private:
1377 GrUniqueKeyInvalidatedMessage fMsg;
1378
1379 void onChange() override {
1380 SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg);
1381 }
1382 };
1383
1384 } // namespace
1385
1345 bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) cons t { 1386 bool GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) cons t {
1346 // 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, but does not do antialiasing . It can do convex
1347 // and concave paths, but we'll leave the convex ones to simpler algorithms. 1388 // and concave paths, but we'll leave the convex ones to simpler algorithms.
1348 return args.fStroke->isFillStyle() && !args.fAntiAlias && !args.fPath->isCon vex(); 1389 return args.fStroke->isFillStyle() && !args.fAntiAlias && !args.fPath->isCon vex();
1349 } 1390 }
1350 1391
1351 class TessellatingPathBatch : public GrBatch { 1392 class TessellatingPathBatch : public GrBatch {
1352 public: 1393 public:
1353 1394
1354 static GrBatch* Create(const GrColor& color, 1395 static GrBatch* Create(const GrColor& color,
(...skipping 15 matching lines...) Expand all
1370 1411
1371 void initBatchTracker(const GrPipelineInfo& init) override { 1412 void initBatchTracker(const GrPipelineInfo& init) override {
1372 // Handle any color overrides 1413 // Handle any color overrides
1373 if (!init.readsColor()) { 1414 if (!init.readsColor()) {
1374 fColor = GrColor_ILLEGAL; 1415 fColor = GrColor_ILLEGAL;
1375 } 1416 }
1376 init.getOverrideColorIfSet(&fColor); 1417 init.getOverrideColorIfSet(&fColor);
1377 fPipelineInfo = init; 1418 fPipelineInfo = init;
1378 } 1419 }
1379 1420
1380 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline ) override { 1421 int tessellate(GrUniqueKey* key,
1422 GrResourceProvider* resourceProvider,
1423 SkAutoTUnref<GrVertexBuffer>& vertexBuffer) {
1381 SkRect pathBounds = fPath.getBounds(); 1424 SkRect pathBounds = fPath.getBounds();
1382 Comparator c; 1425 Comparator c;
1383 if (pathBounds.width() > pathBounds.height()) { 1426 if (pathBounds.width() > pathBounds.height()) {
1384 c.sweep_lt = sweep_lt_horiz; 1427 c.sweep_lt = sweep_lt_horiz;
1385 c.sweep_gt = sweep_gt_horiz; 1428 c.sweep_gt = sweep_gt_horiz;
1386 } else { 1429 } else {
1387 c.sweep_lt = sweep_lt_vert; 1430 c.sweep_lt = sweep_lt_vert;
1388 c.sweep_gt = sweep_gt_vert; 1431 c.sweep_gt = sweep_gt_vert;
1389 } 1432 }
1390 SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance; 1433 SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance;
1391 SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, fViewMat rix, pathBounds); 1434 SkScalar tol = GrPathUtils::scaleToleranceToSrc(screenSpaceTol, fViewMat rix, pathBounds);
1392 int contourCnt; 1435 int contourCnt;
1393 int maxPts = GrPathUtils::worstCasePointCount(fPath, &contourCnt, tol); 1436 int maxPts = GrPathUtils::worstCasePointCount(fPath, &contourCnt, tol);
1394 if (maxPts <= 0) { 1437 if (maxPts <= 0) {
1395 return; 1438 return 0;
1396 } 1439 }
1397 if (maxPts > ((int)SK_MaxU16 + 1)) { 1440 if (maxPts > ((int)SK_MaxU16 + 1)) {
1398 SkDebugf("Path not rendered, too many verts (%d)\n", maxPts); 1441 SkDebugf("Path not rendered, too many verts (%d)\n", maxPts);
1399 return; 1442 return 0;
1400 } 1443 }
1401 SkPath::FillType fillType = fPath.getFillType(); 1444 SkPath::FillType fillType = fPath.getFillType();
1402 if (SkPath::IsInverseFillType(fillType)) { 1445 if (SkPath::IsInverseFillType(fillType)) {
1403 contourCnt++; 1446 contourCnt++;
1404 } 1447 }
1405 1448
1406 LOG("got %d pts, %d contours\n", maxPts, contourCnt); 1449 LOG("got %d pts, %d contours\n", maxPts, contourCnt);
1407 SkAutoTUnref<const GrGeometryProcessor> gp;
1408 {
1409 using namespace GrDefaultGeoProcFactory;
1410
1411 Color color(fColor);
1412 LocalCoords localCoords(fPipelineInfo.readsLocalCoords() ?
1413 LocalCoords::kUsePosition_Type :
1414 LocalCoords::kUnused_Type);
1415 Coverage::Type coverageType;
1416 if (fPipelineInfo.readsCoverage()) {
1417 coverageType = Coverage::kSolid_Type;
1418 } else {
1419 coverageType = Coverage::kNone_Type;
1420 }
1421 Coverage coverage(coverageType);
1422 gp.reset(GrDefaultGeoProcFactory::Create(color, coverage, localCoord s,
1423 fViewMatrix));
1424 }
1425 batchTarget->initDraw(gp, pipeline);
1426
1427 SkAutoTDeleteArray<Vertex*> contours(SkNEW_ARRAY(Vertex *, contourCnt)); 1450 SkAutoTDeleteArray<Vertex*> contours(SkNEW_ARRAY(Vertex *, contourCnt));
1428 1451
1429 // 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:
1430 // 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
1431 // 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
1432 // connectivity of one Edge per Vertex (will grow for intersections). 1455 // connectivity of one Edge per Vertex (will grow for intersections).
1433 SkChunkAlloc alloc(maxPts * (3 * sizeof(Vertex) + sizeof(Edge))); 1456 SkChunkAlloc alloc(maxPts * (3 * sizeof(Vertex) + sizeof(Edge)));
1434 path_to_contours(fPath, tol, fClipBounds, contours.get(), alloc); 1457 bool isLinear;
1458 path_to_contours(fPath, tol, fClipBounds, contours.get(), alloc, &isLine ar);
1435 Poly* polys; 1459 Poly* polys;
1436 polys = contours_to_polys(contours.get(), contourCnt, c, alloc); 1460 polys = contours_to_polys(contours.get(), contourCnt, c, alloc);
1437 int count = 0; 1461 int count = 0;
1438 for (Poly* poly = polys; poly; poly = poly->fNext) { 1462 for (Poly* poly = polys; poly; poly = poly->fNext) {
1439 if (apply_fill_type(fillType, poly->fWinding) && poly->fCount >= 3) { 1463 if (apply_fill_type(fillType, poly->fWinding) && poly->fCount >= 3) {
1440 count += (poly->fCount - 2) * (WIREFRAME ? 6 : 3); 1464 count += (poly->fCount - 2) * (WIREFRAME ? 6 : 3);
1441 } 1465 }
1442 } 1466 }
1443 if (0 == count) { 1467 if (0 == count) {
1444 return; 1468 return 0;
1445 } 1469 }
1446 1470
1447 size_t stride = gp->getVertexStride(); 1471 size_t size = count * sizeof(SkPoint);
1448 SkASSERT(stride == sizeof(SkPoint)); 1472 if (!vertexBuffer.get() || vertexBuffer->gpuMemorySize() < size) {
1449 const GrVertexBuffer* vertexBuffer; 1473 vertexBuffer.reset(resourceProvider->createVertexBuffer(
1450 int firstVertex; 1474 size, GrResourceProvider::kStatic_BufferUsage, 0));
1451 SkPoint* verts = static_cast<SkPoint*>( 1475 }
1452 batchTarget->makeVertSpace(stride, count, &vertexBuffer, &firstVerte x)); 1476 if (!vertexBuffer.get()) {
1453 if (!verts) {
1454 SkDebugf("Could not allocate vertices\n"); 1477 SkDebugf("Could not allocate vertices\n");
1455 return; 1478 return 0;
1456 } 1479 }
1457 1480 SkPoint* verts = static_cast<SkPoint*>(vertexBuffer->map());
1458 LOG("emitting %d verts\n", count); 1481 LOG("emitting %d verts\n", count);
1459 SkPoint* end = polys_to_triangles(polys, fillType, verts); 1482 SkPoint* end = polys_to_triangles(polys, fillType, verts);
1483 vertexBuffer->unmap();
1460 int actualCount = static_cast<int>(end - verts); 1484 int actualCount = static_cast<int>(end - verts);
1461 LOG("actual count: %d\n", actualCount); 1485 LOG("actual count: %d\n", actualCount);
1462 SkASSERT(actualCount <= count); 1486 SkASSERT(actualCount <= count);
1463 1487
1488 if (!fPath.isVolatile()) {
1489 TessInfo info;
1490 info.fTolerance = isLinear ? 0 : tol;
1491 info.fCount = actualCount;
1492 SkAutoTUnref<SkData> data(SkData::NewWithCopy(&info, sizeof(info)));
1493 key->setCustomData(data.get());
1494 resourceProvider->assignUniqueKeyToResource(*key, vertexBuffer.get() );
1495 SkPathPriv::AddGenIDChangeListener(fPath, SkNEW(PathInvalidator(*key )));
1496 }
1497 return actualCount;
1498 }
1499
1500 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline ) override {
1501 // construct a cache key from the path's genID and the view matrix
1502 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain() ;
1503 GrUniqueKey key;
1504 int clipBoundsSize32 =
1505 fPath.isInverseFillType() ? sizeof(fClipBounds) / sizeof(uint32_t) : 0;
1506 GrUniqueKey::Builder builder(&key, kDomain, 2 + clipBoundsSize32);
1507 builder[0] = fPath.getGenerationID();
1508 builder[1] = fPath.getFillType();
1509 // For inverse fills, the tessellation is dependent on clip bounds.
1510 if (fPath.isInverseFillType()) {
1511 memcpy(&builder[2], &fClipBounds, sizeof(fClipBounds));
1512 }
1513 builder.finish();
1514 GrResourceProvider* rp = batchTarget->resourceProvider();
1515 SkAutoTUnref<GrVertexBuffer> vertexBuffer(rp->findAndRefTByUniqueKey<GrV ertexBuffer>(key));
1516 int actualCount;
1517 SkScalar screenSpaceTol = GrPathUtils::kDefaultTolerance;
1518 SkScalar tol = GrPathUtils::scaleToleranceToSrc(
1519 screenSpaceTol, fViewMatrix, fPath.getBounds());
1520 if (!cache_match(vertexBuffer.get(), tol, &actualCount)) {
1521 actualCount = tessellate(&key, rp, vertexBuffer);
1522 }
1523
1524 if (actualCount == 0) {
1525 return;
1526 }
1527
1528 SkAutoTUnref<const GrGeometryProcessor> gp;
1529 {
1530 using namespace GrDefaultGeoProcFactory;
1531
1532 Color color(fColor);
1533 LocalCoords localCoords(fPipelineInfo.readsLocalCoords() ?
1534 LocalCoords::kUsePosition_Type :
1535 LocalCoords::kUnused_Type);
1536 Coverage::Type coverageType;
1537 if (fPipelineInfo.readsCoverage()) {
1538 coverageType = Coverage::kSolid_Type;
1539 } else {
1540 coverageType = Coverage::kNone_Type;
1541 }
1542 Coverage coverage(coverageType);
1543 gp.reset(GrDefaultGeoProcFactory::Create(color, coverage, localCoord s,
1544 fViewMatrix));
1545 }
1546
1547 batchTarget->initDraw(gp, pipeline);
1548 SkASSERT(gp->getVertexStride() == sizeof(SkPoint));
1549
1464 GrPrimitiveType primitiveType = WIREFRAME ? kLines_GrPrimitiveType 1550 GrPrimitiveType primitiveType = WIREFRAME ? kLines_GrPrimitiveType
1465 : kTriangles_GrPrimitiveType; 1551 : kTriangles_GrPrimitiveType;
1466 GrVertices vertices; 1552 GrVertices vertices;
1467 vertices.init(primitiveType, vertexBuffer, firstVertex, actualCount); 1553 vertices.init(primitiveType, vertexBuffer.get(), 0, actualCount);
1468 batchTarget->draw(vertices); 1554 batchTarget->draw(vertices);
1469
1470 batchTarget->putBackVertices((size_t)(count - actualCount), stride);
1471 return;
1472 } 1555 }
1473 1556
1474 bool onCombineIfPossible(GrBatch*) override { 1557 bool onCombineIfPossible(GrBatch*) override {
1475 return false; 1558 return false;
1476 } 1559 }
1477 1560
1478 private: 1561 private:
1479 TessellatingPathBatch(const GrColor& color, 1562 TessellatingPathBatch(const GrColor& color,
1480 const SkPath& path, 1563 const SkPath& path,
1481 const SkMatrix& viewMatrix, 1564 const SkMatrix& viewMatrix,
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
1531 SkMatrix vmi; 1614 SkMatrix vmi;
1532 bool result = viewMatrix.invert(&vmi); 1615 bool result = viewMatrix.invert(&vmi);
1533 if (!result) { 1616 if (!result) {
1534 SkFAIL("Cannot invert matrix\n"); 1617 SkFAIL("Cannot invert matrix\n");
1535 } 1618 }
1536 vmi.mapRect(&clipBounds); 1619 vmi.mapRect(&clipBounds);
1537 return TessellatingPathBatch::Create(color, path, viewMatrix, clipBounds); 1620 return TessellatingPathBatch::Create(color, path, viewMatrix, clipBounds);
1538 } 1621 }
1539 1622
1540 #endif 1623 #endif
OLDNEW
« no previous file with comments | « src/core/SkPathRef.cpp ('k') | tests/PathTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698