Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2011 Google Inc. | 2 * Copyright 2011 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 "GrAAHairLinePathRenderer.h" | 8 #include "GrAAHairLinePathRenderer.h" |
| 9 | 9 |
| 10 #include "GrBatch.h" | |
| 11 #include "GrBatchTarget.h" | |
| 12 #include "GrBufferAllocPool.h" | |
| 10 #include "GrContext.h" | 13 #include "GrContext.h" |
| 11 #include "GrDefaultGeoProcFactory.h" | 14 #include "GrDefaultGeoProcFactory.h" |
| 12 #include "GrDrawTargetCaps.h" | 15 #include "GrDrawTargetCaps.h" |
| 13 #include "GrGpu.h" | 16 #include "GrGpu.h" |
| 14 #include "GrIndexBuffer.h" | 17 #include "GrIndexBuffer.h" |
| 15 #include "GrPathUtils.h" | 18 #include "GrPathUtils.h" |
| 16 #include "GrPipelineBuilder.h" | 19 #include "GrPipelineBuilder.h" |
| 17 #include "GrProcessor.h" | 20 #include "GrProcessor.h" |
| 18 #include "SkGeometry.h" | 21 #include "SkGeometry.h" |
| 19 #include "SkStroke.h" | 22 #include "SkStroke.h" |
| (...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 246 | 249 |
| 247 /** | 250 /** |
| 248 * Generates the lines and quads to be rendered. Lines are always recorded in | 251 * Generates the lines and quads to be rendered. Lines are always recorded in |
| 249 * device space. We will do a device space bloat to account for the 1pixel | 252 * device space. We will do a device space bloat to account for the 1pixel |
| 250 * thickness. | 253 * thickness. |
| 251 * Quads are recorded in device space unless m contains | 254 * Quads are recorded in device space unless m contains |
| 252 * perspective, then in they are in src space. We do this because we will | 255 * perspective, then in they are in src space. We do this because we will |
| 253 * subdivide large quads to reduce over-fill. This subdivision has to be | 256 * subdivide large quads to reduce over-fill. This subdivision has to be |
| 254 * performed before applying the perspective matrix. | 257 * performed before applying the perspective matrix. |
| 255 */ | 258 */ |
| 256 int generate_lines_and_quads(const SkPath& path, | 259 int gather_lines_and_quads(const SkPath& path, |
| 257 const SkMatrix& m, | 260 const SkMatrix& m, |
| 258 const SkIRect& devClipBounds, | 261 const SkIRect& devClipBounds, |
| 259 GrAAHairLinePathRenderer::PtArray* lines, | 262 GrAAHairLinePathRenderer::PtArray* lines, |
| 260 GrAAHairLinePathRenderer::PtArray* quads, | 263 GrAAHairLinePathRenderer::PtArray* quads, |
| 261 GrAAHairLinePathRenderer::PtArray* conics, | 264 GrAAHairLinePathRenderer::PtArray* conics, |
| 262 GrAAHairLinePathRenderer::IntArray* quadSubdivCnts, | 265 GrAAHairLinePathRenderer::IntArray* quadSubdivCnts, |
| 263 GrAAHairLinePathRenderer::FloatArray* conicWeights) { | 266 GrAAHairLinePathRenderer::FloatArray* conicWeights) { |
| 264 SkPath::Iter iter(path, false); | 267 SkPath::Iter iter(path, false); |
| 265 | 268 |
| 266 int totalQuadCount = 0; | 269 int totalQuadCount = 0; |
| 267 SkRect bounds; | 270 SkRect bounds; |
| 268 SkIRect ibounds; | 271 SkIRect ibounds; |
| 269 | 272 |
| 270 bool persp = m.hasPerspective(); | 273 bool persp = m.hasPerspective(); |
| 271 | 274 |
| 272 for (;;) { | 275 for (;;) { |
| 273 SkPoint pathPts[4]; | 276 SkPoint pathPts[4]; |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 462 result->fY = SkScalarMul(result->fY, wInv); | 465 result->fY = SkScalarMul(result->fY, wInv); |
| 463 } | 466 } |
| 464 | 467 |
| 465 void set_uv_quad(const SkPoint qpts[3], BezierVertex verts[kQuadNumVertices]) { | 468 void set_uv_quad(const SkPoint qpts[3], BezierVertex verts[kQuadNumVertices]) { |
| 466 // this should be in the src space, not dev coords, when we have perspective | 469 // this should be in the src space, not dev coords, when we have perspective |
| 467 GrPathUtils::QuadUVMatrix DevToUV(qpts); | 470 GrPathUtils::QuadUVMatrix DevToUV(qpts); |
| 468 DevToUV.apply<kQuadNumVertices, sizeof(BezierVertex), sizeof(SkPoint)>(verts ); | 471 DevToUV.apply<kQuadNumVertices, sizeof(BezierVertex), sizeof(SkPoint)>(verts ); |
| 469 } | 472 } |
| 470 | 473 |
| 471 void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, | 474 void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, |
| 472 const SkMatrix* toSrc, BezierVertex verts[kQuadNumVertices], | 475 const SkMatrix* toSrc, BezierVertex verts[kQuadNumVertices]) { |
| 473 SkRect* devBounds) { | |
| 474 SkASSERT(!toDevice == !toSrc); | 476 SkASSERT(!toDevice == !toSrc); |
| 475 // original quad is specified by tri a,b,c | 477 // original quad is specified by tri a,b,c |
| 476 SkPoint a = qpts[0]; | 478 SkPoint a = qpts[0]; |
| 477 SkPoint b = qpts[1]; | 479 SkPoint b = qpts[1]; |
| 478 SkPoint c = qpts[2]; | 480 SkPoint c = qpts[2]; |
| 479 | 481 |
| 480 if (toDevice) { | 482 if (toDevice) { |
| 481 toDevice->mapPoints(&a, 1); | 483 toDevice->mapPoints(&a, 1); |
| 482 toDevice->mapPoints(&b, 1); | 484 toDevice->mapPoints(&b, 1); |
| 483 toDevice->mapPoints(&c, 1); | 485 toDevice->mapPoints(&c, 1); |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 528 a0.fPos += abN; | 530 a0.fPos += abN; |
| 529 a1.fPos = a; | 531 a1.fPos = a; |
| 530 a1.fPos -= abN; | 532 a1.fPos -= abN; |
| 531 | 533 |
| 532 c0.fPos = c; | 534 c0.fPos = c; |
| 533 c0.fPos += cbN; | 535 c0.fPos += cbN; |
| 534 c1.fPos = c; | 536 c1.fPos = c; |
| 535 c1.fPos -= cbN; | 537 c1.fPos -= cbN; |
| 536 | 538 |
| 537 intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos); | 539 intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos); |
| 538 devBounds->growToInclude(&verts[0].fPos, sizeof(BezierVertex), kQuadNumVerti ces); | |
| 539 | 540 |
| 540 if (toSrc) { | 541 if (toSrc) { |
| 541 toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(BezierVertex), kQuadNu mVertices); | 542 toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(BezierVertex), kQuadNu mVertices); |
| 542 } | 543 } |
| 543 } | 544 } |
| 544 | 545 |
| 545 // Equations based off of Loop-Blinn Quadratic GPU Rendering | 546 // Equations based off of Loop-Blinn Quadratic GPU Rendering |
| 546 // Input Parametric: | 547 // Input Parametric: |
| 547 // P(t) = (P0*(1-t)^2 + 2*w*P1*t*(1-t) + P2*t^2) / (1-t)^2 + 2*w*t*(1-t) + t^2) | 548 // P(t) = (P0*(1-t)^2 + 2*w*P1*t*(1-t) + P2*t^2) / (1-t)^2 + 2*w*t*(1-t) + t^2) |
| 548 // Output Implicit: | 549 // Output Implicit: |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 560 verts[i].fConic.fK = pnt.fX * klm[0] + pnt.fY * klm[1] + klm[2]; | 561 verts[i].fConic.fK = pnt.fX * klm[0] + pnt.fY * klm[1] + klm[2]; |
| 561 verts[i].fConic.fL = pnt.fX * klm[3] + pnt.fY * klm[4] + klm[5]; | 562 verts[i].fConic.fL = pnt.fX * klm[3] + pnt.fY * klm[4] + klm[5]; |
| 562 verts[i].fConic.fM = pnt.fX * klm[6] + pnt.fY * klm[7] + klm[8]; | 563 verts[i].fConic.fM = pnt.fX * klm[6] + pnt.fY * klm[7] + klm[8]; |
| 563 } | 564 } |
| 564 } | 565 } |
| 565 | 566 |
| 566 void add_conics(const SkPoint p[3], | 567 void add_conics(const SkPoint p[3], |
| 567 const SkScalar weight, | 568 const SkScalar weight, |
| 568 const SkMatrix* toDevice, | 569 const SkMatrix* toDevice, |
| 569 const SkMatrix* toSrc, | 570 const SkMatrix* toSrc, |
| 570 BezierVertex** vert, | 571 BezierVertex** vert) { |
| 571 SkRect* devBounds) { | 572 bloat_quad(p, toDevice, toSrc, *vert); |
| 572 bloat_quad(p, toDevice, toSrc, *vert, devBounds); | |
| 573 set_conic_coeffs(p, *vert, weight); | 573 set_conic_coeffs(p, *vert, weight); |
| 574 *vert += kQuadNumVertices; | 574 *vert += kQuadNumVertices; |
| 575 } | 575 } |
| 576 | 576 |
| 577 void add_quads(const SkPoint p[3], | 577 void add_quads(const SkPoint p[3], |
| 578 int subdiv, | 578 int subdiv, |
| 579 const SkMatrix* toDevice, | 579 const SkMatrix* toDevice, |
| 580 const SkMatrix* toSrc, | 580 const SkMatrix* toSrc, |
| 581 BezierVertex** vert, | 581 BezierVertex** vert) { |
| 582 SkRect* devBounds) { | |
| 583 SkASSERT(subdiv >= 0); | 582 SkASSERT(subdiv >= 0); |
| 584 if (subdiv) { | 583 if (subdiv) { |
| 585 SkPoint newP[5]; | 584 SkPoint newP[5]; |
| 586 SkChopQuadAtHalf(p, newP); | 585 SkChopQuadAtHalf(p, newP); |
| 587 add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert, devBounds); | 586 add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert); |
| 588 add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert, devBounds); | 587 add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert); |
| 589 } else { | 588 } else { |
| 590 bloat_quad(p, toDevice, toSrc, *vert, devBounds); | 589 bloat_quad(p, toDevice, toSrc, *vert); |
| 591 set_uv_quad(p, *vert); | 590 set_uv_quad(p, *vert); |
| 592 *vert += kQuadNumVertices; | 591 *vert += kQuadNumVertices; |
| 593 } | 592 } |
| 594 } | 593 } |
| 595 | 594 |
| 596 void add_line(const SkPoint p[2], | 595 void add_line(const SkPoint p[2], |
| 597 const SkMatrix* toSrc, | 596 const SkMatrix* toSrc, |
| 598 uint8_t coverage, | 597 uint8_t coverage, |
| 599 LineVertex** vert) { | 598 LineVertex** vert) { |
| 600 const SkPoint& a = p[0]; | 599 const SkPoint& a = p[0]; |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 635 } | 634 } |
| 636 } | 635 } |
| 637 | 636 |
| 638 *vert += kLineSegNumVertices; | 637 *vert += kLineSegNumVertices; |
| 639 } | 638 } |
| 640 | 639 |
| 641 } | 640 } |
| 642 | 641 |
| 643 /////////////////////////////////////////////////////////////////////////////// | 642 /////////////////////////////////////////////////////////////////////////////// |
| 644 | 643 |
| 645 bool GrAAHairLinePathRenderer::createLineGeom(GrDrawTarget* target, | |
| 646 GrPipelineBuilder* pipelineBuilder , | |
| 647 const SkMatrix& viewMatrix, | |
| 648 uint8_t coverage, | |
| 649 size_t vertexStride, | |
| 650 GrDrawTarget::AutoReleaseGeometry* arg, | |
| 651 SkRect* devBounds, | |
| 652 const SkPath& path, | |
| 653 const PtArray& lines, | |
| 654 int lineCnt) { | |
| 655 int vertCnt = kLineSegNumVertices * lineCnt; | |
| 656 | |
| 657 SkASSERT(vertexStride == sizeof(LineVertex)); | |
| 658 if (!arg->set(target, vertCnt, vertexStride, 0)) { | |
| 659 return false; | |
| 660 } | |
| 661 | |
| 662 LineVertex* verts = reinterpret_cast<LineVertex*>(arg->vertices()); | |
| 663 | |
| 664 const SkMatrix* toSrc = NULL; | |
| 665 SkMatrix ivm; | |
| 666 | |
| 667 if (viewMatrix.hasPerspective()) { | |
| 668 if (viewMatrix.invert(&ivm)) { | |
| 669 toSrc = &ivm; | |
| 670 } | |
| 671 } | |
| 672 devBounds->set(lines.begin(), lines.count()); | |
| 673 for (int i = 0; i < lineCnt; ++i) { | |
| 674 add_line(&lines[2*i], toSrc, coverage, &verts); | |
| 675 } | |
| 676 // All the verts computed by add_line are within sqrt(1^2 + 0.5^2) of the en d points. | |
| 677 static const SkScalar kSqrtOfOneAndAQuarter = 1.118f; | |
| 678 // Add a little extra to account for vector normalization precision. | |
| 679 static const SkScalar kOutset = kSqrtOfOneAndAQuarter + SK_Scalar1 / 20; | |
| 680 devBounds->outset(kOutset, kOutset); | |
| 681 | |
| 682 return true; | |
| 683 } | |
| 684 | |
| 685 bool GrAAHairLinePathRenderer::createBezierGeom(GrDrawTarget* target, | |
| 686 GrPipelineBuilder* pipelineBuild er, | |
| 687 const SkMatrix& viewMatrix, | |
| 688 GrDrawTarget::AutoReleaseGeometr y* arg, | |
| 689 SkRect* devBounds, | |
| 690 const SkPath& path, | |
| 691 const PtArray& quads, | |
| 692 int quadCnt, | |
| 693 const PtArray& conics, | |
| 694 int conicCnt, | |
| 695 const IntArray& qSubdivs, | |
| 696 const FloatArray& cWeights, | |
| 697 size_t vertexStride) { | |
| 698 int vertCnt = kQuadNumVertices * quadCnt + kQuadNumVertices * conicCnt; | |
| 699 | |
| 700 if (!arg->set(target, vertCnt, vertexStride, 0)) { | |
| 701 return false; | |
| 702 } | |
| 703 | |
| 704 BezierVertex* verts = reinterpret_cast<BezierVertex*>(arg->vertices()); | |
| 705 | |
| 706 const SkMatrix* toDevice = NULL; | |
| 707 const SkMatrix* toSrc = NULL; | |
| 708 SkMatrix ivm; | |
| 709 | |
| 710 if (viewMatrix.hasPerspective()) { | |
| 711 if (viewMatrix.invert(&ivm)) { | |
| 712 toDevice = &viewMatrix; | |
| 713 toSrc = &ivm; | |
| 714 } | |
| 715 } | |
| 716 | |
| 717 // Seed the dev bounds with some pts known to be inside. Each quad and conic grows the bounding | |
| 718 // box to include its vertices. | |
| 719 SkPoint seedPts[2]; | |
| 720 if (quadCnt) { | |
| 721 seedPts[0] = quads[0]; | |
| 722 seedPts[1] = quads[2]; | |
| 723 } else if (conicCnt) { | |
| 724 seedPts[0] = conics[0]; | |
| 725 seedPts[1] = conics[2]; | |
| 726 } | |
| 727 if (toDevice) { | |
| 728 toDevice->mapPoints(seedPts, 2); | |
| 729 } | |
| 730 devBounds->set(seedPts[0], seedPts[1]); | |
| 731 | |
| 732 int unsubdivQuadCnt = quads.count() / 3; | |
| 733 for (int i = 0; i < unsubdivQuadCnt; ++i) { | |
| 734 SkASSERT(qSubdivs[i] >= 0); | |
| 735 add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts, devBounds); | |
| 736 } | |
| 737 | |
| 738 // Start Conics | |
| 739 for (int i = 0; i < conicCnt; ++i) { | |
| 740 add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts, devBounds ); | |
| 741 } | |
| 742 return true; | |
| 743 } | |
| 744 | |
| 745 bool GrAAHairLinePathRenderer::canDrawPath(const GrDrawTarget* target, | 644 bool GrAAHairLinePathRenderer::canDrawPath(const GrDrawTarget* target, |
| 746 const GrPipelineBuilder* pipelineBuil der, | 645 const GrPipelineBuilder* pipelineBuil der, |
| 747 const SkMatrix& viewMatrix, | 646 const SkMatrix& viewMatrix, |
| 748 const SkPath& path, | 647 const SkPath& path, |
| 749 const SkStrokeRec& stroke, | 648 const SkStrokeRec& stroke, |
| 750 bool antiAlias) const { | 649 bool antiAlias) const { |
| 751 if (!antiAlias) { | 650 if (!antiAlias) { |
| 752 return false; | 651 return false; |
| 753 } | 652 } |
| 754 | 653 |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 793 actualBounds.growToInclude(pos.fX, pos.fY); | 692 actualBounds.growToInclude(pos.fX, pos.fY); |
| 794 } | 693 } |
| 795 } | 694 } |
| 796 if (!first) { | 695 if (!first) { |
| 797 return tolDevBounds.contains(actualBounds); | 696 return tolDevBounds.contains(actualBounds); |
| 798 } | 697 } |
| 799 | 698 |
| 800 return true; | 699 return true; |
| 801 } | 700 } |
| 802 | 701 |
| 702 class AAHairlineBatch : public GrBatch { | |
| 703 public: | |
| 704 struct Geometry { | |
| 705 GrColor fColor; | |
| 706 uint8_t fCoverage; | |
| 707 SkMatrix fViewMatrix; | |
| 708 SkPath fPath; | |
| 709 SkDEBUGCODE(SkRect fDevBounds;) | |
| 710 SkIRect fDevClipBounds; | |
| 711 }; | |
| 712 | |
| 713 // TODO Batch itself should not hold on to index buffers. Instead, these sh ould live in the | |
| 714 // cache. | |
| 715 static GrBatch* Create(const Geometry& geometry, const GrIndexBuffer* linesI ndexBuffer, | |
| 716 const GrIndexBuffer* quadsIndexBuffer) { | |
| 717 return SkNEW_ARGS(AAHairlineBatch, (geometry, linesIndexBuffer, quadsInd exBuffer)); | |
| 718 } | |
| 719 | |
| 720 const char* name() const SK_OVERRIDE { return "AAHairlineBatch"; } | |
| 721 | |
| 722 void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE { | |
| 723 // When this is called on a batch, there is only one geometry bundle | |
| 724 out->setKnownFourComponents(fGeoData[0].fColor); | |
| 725 } | |
| 726 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRID E { | |
| 727 out->setUnknownSingleComponent(); | |
| 728 } | |
| 729 | |
| 730 void initBatchOpt(const GrBatchOpt& batchOpt) { | |
| 731 fBatchOpt = batchOpt; | |
| 732 } | |
| 733 | |
| 734 void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE { | |
| 735 // Handle any color overrides | |
| 736 if (init.fColorIgnored) { | |
| 737 fGeoData[0].fColor = GrColor_ILLEGAL; | |
| 738 } else if (GrColor_ILLEGAL != init.fOverrideColor) { | |
| 739 fGeoData[0].fColor = init.fOverrideColor; | |
| 740 } | |
| 741 | |
| 742 // setup batch properties | |
| 743 fBatch.fColorIgnored = init.fColorIgnored; | |
| 744 fBatch.fColor = fGeoData[0].fColor; | |
| 745 fBatch.fUsesLocalCoords = init.fUsesLocalCoords; | |
| 746 fBatch.fCoverageIgnored = init.fCoverageIgnored; | |
| 747 fBatch.fCoverage = fGeoData[0].fCoverage; | |
| 748 SkDEBUGCODE(fBatch.fDevBounds = fGeoData[0].fDevBounds;) | |
| 749 } | |
| 750 | |
| 751 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline ) SK_OVERRIDE { | |
| 752 int instanceCount = fGeoData.count(); | |
| 753 for (int i = 0; i < instanceCount; i++) { | |
| 754 const Geometry& args = fGeoData[i]; | |
| 755 | |
| 756 // createGeom transforms the geometry to device space when the matri x does not have | |
| 757 // perspective. | |
| 758 SkMatrix vm = args.fViewMatrix; | |
| 759 SkMatrix invert = SkMatrix::I(); | |
| 760 if (!args.fViewMatrix.hasPerspective()) { | |
| 761 vm = SkMatrix::I(); | |
| 762 if (!args.fViewMatrix.invert(&invert)) { | |
| 763 return; | |
| 764 } | |
| 765 } | |
| 766 | |
| 767 int lineCount; | |
| 768 int quadCount; | |
| 769 int conicCount; | |
| 770 PREALLOC_PTARRAY(128) lines; | |
| 771 PREALLOC_PTARRAY(128) quads; | |
| 772 PREALLOC_PTARRAY(128) conics; | |
| 773 IntArray qSubdivs; | |
| 774 FloatArray cWeights; | |
| 775 quadCount = gather_lines_and_quads(args.fPath, args.fViewMatrix, arg s.fDevClipBounds, | |
| 776 &lines, &quads, &conics, &qSubdiv s, &cWeights); | |
| 777 | |
| 778 lineCount = lines.count() / 2; | |
| 779 conicCount = conics.count() / 3; | |
| 780 | |
| 781 // do lines first | |
| 782 if (lineCount) { | |
| 783 this->generateLines(batchTarget, pipeline, args, vm, invert, lin es, lineCount); | |
| 784 } | |
| 785 | |
| 786 if (quadCount || conicCount) { | |
| 787 this->generateQuadsAndConics(batchTarget, | |
| 788 pipeline, | |
| 789 args, | |
| 790 quads, | |
| 791 quadCount, | |
| 792 conics, | |
| 793 conicCount, | |
| 794 qSubdivs, | |
| 795 cWeights, | |
| 796 vm, | |
| 797 invert); | |
| 798 } | |
| 799 } | |
| 800 } | |
| 801 | |
| 802 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } | |
| 803 | |
| 804 private: | |
| 805 typedef SkTArray<SkPoint, true> PtArray; | |
| 806 typedef SkTArray<int, true> IntArray; | |
| 807 typedef SkTArray<float, true> FloatArray; | |
| 808 | |
| 809 AAHairlineBatch(const Geometry& geometry, const GrIndexBuffer* linesIndexBuf fer, | |
| 810 const GrIndexBuffer* quadsIndexBuffer) | |
| 811 : fLinesIndexBuffer(linesIndexBuffer) | |
| 812 , fQuadsIndexBuffer(quadsIndexBuffer) { | |
| 813 SkASSERT(linesIndexBuffer && quadsIndexBuffer); | |
| 814 this->initClassID<AAHairlineBatch>(); | |
| 815 fGeoData.push_back(geometry); | |
| 816 } | |
| 817 | |
| 818 bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE { | |
| 819 AAHairlineBatch* that = t->cast<AAHairlineBatch>(); | |
| 820 | |
| 821 // We go to identity if we don't have perspective | |
| 822 if (this->viewMatrix().hasPerspective() && | |
| 823 !this->viewMatrix().cheapEqualTo(that->viewMatrix())) { | |
| 824 return false; | |
| 825 } | |
| 826 | |
| 827 // TODO we can actually batch hairlines if they are the same color in a kind of bulk method | |
| 828 // but we haven't implemented this yet | |
| 829 // TODO investigate going to vertex color and coverage? | |
| 830 if (this->coverage() != that->coverage()) { | |
| 831 return false; | |
| 832 } | |
| 833 | |
| 834 if (this->color() != that->color()) { | |
| 835 return false; | |
| 836 } | |
| 837 | |
| 838 SkASSERT(this->usesLocalCoords() == that->usesLocalCoords()); | |
| 839 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->vi ewMatrix())) { | |
| 840 return false; | |
| 841 } | |
| 842 | |
| 843 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()) ; | |
| 844 return true; | |
| 845 } | |
| 846 | |
| 847 GrColor color() const { return fBatch.fColor; } | |
| 848 uint8_t coverage() const { return fBatch.fCoverage; } | |
| 849 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } | |
| 850 const SkMatrix& viewMatrix() const { return fGeoData[0].fViewMatrix; } | |
| 851 | |
| 852 void generateLines(GrBatchTarget* batchTarget, | |
| 853 const GrPipeline* pipeline, | |
| 854 const Geometry& args, | |
| 855 const SkMatrix& viewMatrix, | |
| 856 const SkMatrix& invert, | |
| 857 const PtArray& lines, | |
| 858 int lineCnt) { | |
| 859 uint32_t gpFlags = GrDefaultGeoProcFactory::kPosition_GPType | | |
| 860 GrDefaultGeoProcFactory::kCoverage_GPType; | |
| 861 SkAutoTUnref<const GrGeometryProcessor> gp(GrDefaultGeoProcFactory::Crea te(gpFlags, | |
| 862 args.fColor, | |
| 863 viewMatrix, | |
| 864 invert, | |
| 865 false, | |
| 866 args.fCoverage)); | |
| 867 | |
| 868 batchTarget->initDraw(gp, pipeline); | |
| 869 fBatchesGenerated++; | |
|
bsalomon
2015/02/02 21:01:13
seems to me like batch target should track this, n
| |
| 870 | |
| 871 // TODO remove this when batch is everywhere | |
| 872 GrPipelineInfo init; | |
| 873 init.fColorIgnored = fBatch.fColorIgnored; | |
| 874 init.fOverrideColor = GrColor_ILLEGAL; | |
| 875 init.fCoverageIgnored = fBatch.fCoverageIgnored; | |
| 876 init.fUsesLocalCoords = this->usesLocalCoords(); | |
| 877 gp->initBatchTracker(batchTarget->currentBatchTracker(), init); | |
| 878 | |
| 879 const GrVertexBuffer* vertexBuffer; | |
| 880 int firstVertex; | |
| 881 | |
| 882 size_t vertexStride = gp->getVertexStride(); | |
| 883 int vertexCount = kLineSegNumVertices * lineCnt; | |
| 884 void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride, | |
| 885 vertexCount, | |
| 886 &vertexBuffer, | |
| 887 &firstVertex); | |
| 888 | |
| 889 SkASSERT(gp->getVertexStride() == sizeof(LineVertex)); | |
| 890 | |
| 891 // generate lines | |
| 892 const SkMatrix* toSrc = NULL; | |
| 893 if (args.fViewMatrix.hasPerspective()) { | |
| 894 SkMatrix perspectiveInvert; | |
| 895 if (!args.fViewMatrix.invert(&perspectiveInvert)) { | |
| 896 return; | |
| 897 } | |
| 898 toSrc = &perspectiveInvert; | |
| 899 } | |
| 900 | |
| 901 LineVertex* verts = reinterpret_cast<LineVertex*>(vertices); | |
| 902 for (int i = 0; i < lineCnt; ++i) { | |
| 903 add_line(&lines[2*i], toSrc, args.fCoverage, &verts); | |
| 904 } | |
| 905 | |
| 906 // Check devBounds | |
| 907 SkASSERT(check_bounds<LineVertex>(viewMatrix.hasPerspective() ? viewMatr ix : SkMatrix::I(), | |
| 908 args.fDevBounds, | |
| 909 vertices, | |
| 910 kLineSegNumVertices * lineCnt)); | |
| 911 | |
| 912 { | |
| 913 GrDrawTarget::DrawInfo info; | |
| 914 info.setVertexBuffer(vertexBuffer); | |
| 915 info.setIndexBuffer(fLinesIndexBuffer); | |
| 916 info.setPrimitiveType(kTriangles_GrPrimitiveType); | |
| 917 info.setStartIndex(0); | |
| 918 | |
| 919 int lines = 0; | |
| 920 while (lines < lineCnt) { | |
| 921 int n = SkTMin(lineCnt - lines, kLineSegsNumInIdxBuffer); | |
| 922 | |
| 923 info.setStartVertex(kLineSegNumVertices*lines + firstVertex); | |
| 924 info.setVertexCount(kLineSegNumVertices*n); | |
| 925 info.setIndexCount(kIdxsPerLineSeg*n); | |
| 926 batchTarget->draw(info); | |
| 927 | |
| 928 lines += n; | |
| 929 } | |
| 930 } | |
| 931 } | |
| 932 | |
| 933 void generateQuadsAndConics(GrBatchTarget* batchTarget, | |
| 934 const GrPipeline* pipeline, | |
| 935 const Geometry& args, | |
| 936 const PREALLOC_PTARRAY(128)& quads, | |
| 937 int quadCount, | |
| 938 const PREALLOC_PTARRAY(128)& conics, | |
| 939 int conicCount, | |
| 940 const IntArray& qSubdivs, | |
| 941 const FloatArray& cWeights, | |
| 942 const SkMatrix& vm, | |
| 943 const SkMatrix& invert) { | |
| 944 const GrVertexBuffer* vertexBuffer; | |
| 945 int firstVertex; | |
| 946 | |
| 947 size_t vertexStride = sizeof(BezierVertex); | |
| 948 int vertexCount = kQuadNumVertices * quadCount + kQuadNumVertices * coni cCount; | |
| 949 void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride, | |
| 950 vertexCount, | |
| 951 &vertexBuffer, | |
| 952 &firstVertex); | |
| 953 | |
| 954 if (!this->createBezierGeom(vertices, | |
| 955 args.fViewMatrix, | |
| 956 args.fPath, | |
| 957 quads, | |
| 958 quadCount, | |
| 959 conics, | |
| 960 conicCount, | |
| 961 qSubdivs, | |
| 962 cWeights, | |
| 963 vertexStride)) { | |
| 964 SkDebugf("Couldn't create bezier geometry\n"); | |
| 965 return; | |
| 966 } | |
| 967 | |
| 968 // Check devBounds | |
| 969 SkASSERT(check_bounds<BezierVertex>(vm, | |
| 970 args.fDevBounds, | |
| 971 vertices, | |
| 972 kQuadNumVertices * quadCount + | |
| 973 kQuadNumVertices * conicCount)); | |
| 974 | |
| 975 if (quadCount > 0) { | |
| 976 SkAutoTUnref<GrGeometryProcessor> hairQuadProcessor( | |
| 977 GrQuadEffect::Create(args.fColor, | |
| 978 vm, | |
| 979 kHairlineAA_GrProcessorEdgeType, | |
| 980 batchTarget->caps(), | |
| 981 invert, | |
| 982 args.fCoverage)); | |
| 983 | |
| 984 batchTarget->initDraw(hairQuadProcessor, pipeline); | |
| 985 fBatchesGenerated++; | |
| 986 | |
| 987 // TODO remove this when batch is everywhere | |
| 988 GrPipelineInfo init; | |
| 989 init.fColorIgnored = fBatch.fColorIgnored; | |
| 990 init.fOverrideColor = GrColor_ILLEGAL; | |
| 991 init.fCoverageIgnored = fBatch.fCoverageIgnored; | |
| 992 init.fUsesLocalCoords = this->usesLocalCoords(); | |
| 993 hairQuadProcessor->initBatchTracker(batchTarget->currentBatchTracker (), init); | |
| 994 | |
| 995 this->drawBeziers(batchTarget, | |
| 996 hairQuadProcessor, | |
| 997 pipeline, | |
| 998 vertexBuffer, | |
| 999 firstVertex, | |
| 1000 quadCount); | |
| 1001 } | |
| 1002 | |
| 1003 if (conicCount > 0) { | |
| 1004 SkAutoTUnref<GrGeometryProcessor> hairConicProcessor( | |
| 1005 GrConicEffect::Create(args.fColor, | |
| 1006 vm, | |
| 1007 kHairlineAA_GrProcessorEdgeType, | |
| 1008 batchTarget->caps(), | |
| 1009 invert, | |
| 1010 args.fCoverage)); | |
| 1011 | |
| 1012 batchTarget->initDraw(hairConicProcessor, pipeline); | |
| 1013 fBatchesGenerated++; | |
| 1014 | |
| 1015 // TODO remove this when batch is everywhere | |
| 1016 GrPipelineInfo init; | |
| 1017 init.fColorIgnored = fBatch.fColorIgnored; | |
| 1018 init.fOverrideColor = GrColor_ILLEGAL; | |
| 1019 init.fCoverageIgnored = fBatch.fCoverageIgnored; | |
| 1020 init.fUsesLocalCoords = this->usesLocalCoords(); | |
| 1021 hairConicProcessor->initBatchTracker(batchTarget->currentBatchTracke r(), init); | |
| 1022 | |
| 1023 this->drawConics(batchTarget, | |
| 1024 hairConicProcessor, | |
| 1025 pipeline, | |
| 1026 vertexBuffer, | |
| 1027 firstVertex, | |
| 1028 conicCount, | |
| 1029 quadCount); | |
| 1030 } | |
| 1031 } | |
| 1032 | |
| 1033 bool createBezierGeom(void* vertices, | |
| 1034 const SkMatrix& viewMatrix, | |
| 1035 const SkPath& path, | |
| 1036 const PtArray& quads, | |
| 1037 int quadCnt, | |
| 1038 const PtArray& conics, | |
| 1039 int conicCnt, | |
| 1040 const IntArray& qSubdivs, | |
| 1041 const FloatArray& cWeights, | |
| 1042 size_t vertexStride) { | |
| 1043 BezierVertex* verts = reinterpret_cast<BezierVertex*>(vertices); | |
| 1044 | |
| 1045 const SkMatrix* toDevice = NULL; | |
| 1046 const SkMatrix* toSrc = NULL; | |
| 1047 SkMatrix ivm; | |
| 1048 | |
| 1049 if (viewMatrix.hasPerspective()) { | |
| 1050 if (viewMatrix.invert(&ivm)) { | |
| 1051 toDevice = &viewMatrix; | |
| 1052 toSrc = &ivm; | |
| 1053 } | |
| 1054 } | |
| 1055 | |
| 1056 int unsubdivQuadCnt = quads.count() / 3; | |
| 1057 for (int i = 0; i < unsubdivQuadCnt; ++i) { | |
| 1058 SkASSERT(qSubdivs[i] >= 0); | |
| 1059 add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts); | |
| 1060 } | |
| 1061 | |
| 1062 // Start Conics | |
| 1063 for (int i = 0; i < conicCnt; ++i) { | |
| 1064 add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts); | |
| 1065 } | |
| 1066 return true; | |
| 1067 } | |
| 1068 | |
| 1069 void drawBeziers(GrBatchTarget* batchTarget, | |
| 1070 const GrGeometryProcessor* hairQuadProcessor, | |
| 1071 const GrPipeline* pipeline, | |
| 1072 const GrVertexBuffer* vertexBuffer, | |
| 1073 int firstVertex, | |
| 1074 int quadCount) { | |
| 1075 GrDrawTarget::DrawInfo info; | |
| 1076 info.setVertexBuffer(vertexBuffer); | |
| 1077 info.setIndexBuffer(fQuadsIndexBuffer); | |
| 1078 info.setPrimitiveType(kTriangles_GrPrimitiveType); | |
| 1079 info.setStartIndex(0); | |
| 1080 | |
| 1081 int quads = 0; | |
| 1082 while (quads < quadCount) { | |
| 1083 int n = SkTMin(quadCount - quads, kQuadsNumInIdxBuffer); | |
| 1084 | |
| 1085 info.setStartVertex(kQuadNumVertices*quads + firstVertex); | |
| 1086 info.setVertexCount(kQuadNumVertices*n); | |
| 1087 info.setIndexCount(kIdxsPerQuad*n); | |
| 1088 batchTarget->draw(info); | |
| 1089 | |
| 1090 quads += n; | |
| 1091 } | |
| 1092 } | |
| 1093 | |
| 1094 void drawConics(GrBatchTarget* batchTarget, | |
| 1095 const GrGeometryProcessor* hairConicProcessor, | |
| 1096 const GrPipeline* pipeline, | |
| 1097 const GrVertexBuffer* vertexBuffer, | |
| 1098 int firstVertex, | |
| 1099 int conicCount, | |
| 1100 int quadCount) { | |
| 1101 GrDrawTarget::DrawInfo info; | |
| 1102 info.setVertexBuffer(vertexBuffer); | |
| 1103 info.setIndexBuffer(fQuadsIndexBuffer); | |
| 1104 info.setPrimitiveType(kTriangles_GrPrimitiveType); | |
| 1105 info.setStartIndex(0); | |
| 1106 | |
| 1107 int conics = 0; | |
| 1108 while (conics < conicCount) { | |
| 1109 int n = SkTMin(conicCount - conics, kQuadsNumInIdxBuffer); | |
| 1110 | |
| 1111 info.setStartVertex(kQuadNumVertices*(quadCount + conics) + firstVer tex); | |
| 1112 info.setVertexCount(kQuadNumVertices*n); | |
| 1113 info.setIndexCount(kIdxsPerQuad*n); | |
| 1114 batchTarget->draw(info); | |
| 1115 | |
| 1116 conics += n; | |
| 1117 } | |
| 1118 } | |
| 1119 | |
| 1120 struct BatchTracker { | |
| 1121 GrColor fColor; | |
| 1122 uint8_t fCoverage; | |
| 1123 SkRect fDevBounds; | |
| 1124 bool fUsesLocalCoords; | |
| 1125 bool fColorIgnored; | |
| 1126 bool fCoverageIgnored; | |
| 1127 }; | |
| 1128 | |
| 1129 GrBatchOpt fBatchOpt; | |
| 1130 BatchTracker fBatch; | |
| 1131 SkSTArray<1, Geometry, true> fGeoData; | |
| 1132 const GrIndexBuffer* fLinesIndexBuffer; | |
| 1133 const GrIndexBuffer* fQuadsIndexBuffer; | |
| 1134 }; | |
| 1135 | |
| 803 bool GrAAHairLinePathRenderer::onDrawPath(GrDrawTarget* target, | 1136 bool GrAAHairLinePathRenderer::onDrawPath(GrDrawTarget* target, |
| 804 GrPipelineBuilder* pipelineBuilder, | 1137 GrPipelineBuilder* pipelineBuilder, |
| 805 GrColor color, | 1138 GrColor color, |
| 806 const SkMatrix& viewMatrix, | 1139 const SkMatrix& viewMatrix, |
| 807 const SkPath& path, | 1140 const SkPath& path, |
| 808 const SkStrokeRec& stroke, | 1141 const SkStrokeRec& stroke, |
| 809 bool antiAlias) { | 1142 bool) { |
| 810 SkScalar hairlineCoverage; | 1143 SkScalar hairlineCoverage; |
| 811 uint8_t newCoverage = 0xff; | 1144 uint8_t newCoverage = 0xff; |
| 812 if (IsStrokeHairlineOrEquivalent(stroke, viewMatrix, &hairlineCoverage)) { | 1145 if (IsStrokeHairlineOrEquivalent(stroke, viewMatrix, &hairlineCoverage)) { |
| 813 newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff); | 1146 newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff); |
| 814 } | 1147 } |
| 815 | 1148 |
| 816 SkIRect devClipBounds; | 1149 SkIRect devClipBounds; |
| 817 target->getClip()->getConservativeBounds(pipelineBuilder->getRenderTarget(), &devClipBounds); | 1150 target->getClip()->getConservativeBounds(pipelineBuilder->getRenderTarget(), &devClipBounds); |
| 818 | 1151 |
| 819 int lineCnt; | 1152 // This outset was determined experimentally by running skps and gms. It pr obably could be a |
| 820 int quadCnt; | 1153 // bit tighter |
| 821 int conicCnt; | 1154 SkRect devRect = path.getBounds(); |
| 822 PREALLOC_PTARRAY(128) lines; | 1155 devRect.outset(3, 3); |
| 823 PREALLOC_PTARRAY(128) quads; | 1156 viewMatrix.mapRect(&devRect); |
| 824 PREALLOC_PTARRAY(128) conics; | 1157 |
| 825 IntArray qSubdivs; | 1158 AAHairlineBatch::Geometry geometry; |
| 826 FloatArray cWeights; | 1159 geometry.fColor = color; |
| 827 quadCnt = generate_lines_and_quads(path, viewMatrix, devClipBounds, | 1160 geometry.fCoverage = newCoverage; |
| 828 &lines, &quads, &conics, &qSubdivs, &cWei ghts); | 1161 geometry.fViewMatrix = viewMatrix; |
| 829 lineCnt = lines.count() / 2; | 1162 geometry.fPath = path; |
| 830 conicCnt = conics.count() / 3; | 1163 SkDEBUGCODE(geometry.fDevBounds = devRect;) |
| 831 | 1164 geometry.fDevClipBounds = devClipBounds; |
| 832 // createGeom transforms the geometry to device space when the matrix does n ot have | 1165 |
| 833 // perspective. | 1166 GrBatch* batch = AAHairlineBatch::Create(geometry, fLinesIndexBuffer, fQuads IndexBuffer); |
| 834 SkMatrix vm = viewMatrix; | 1167 target->drawBatch(pipelineBuilder, batch, &devRect); |
| 835 SkMatrix invert = SkMatrix::I(); | |
| 836 if (!viewMatrix.hasPerspective()) { | |
| 837 vm = SkMatrix::I(); | |
| 838 if (!viewMatrix.invert(&invert)) { | |
| 839 return false; | |
| 840 } | |
| 841 } | |
| 842 | |
| 843 // do lines first | |
| 844 if (lineCnt) { | |
| 845 GrDrawTarget::AutoReleaseGeometry arg; | |
| 846 SkRect devBounds; | |
| 847 | |
| 848 GrPipelineBuilder::AutoRestoreEffects are(pipelineBuilder); | |
| 849 uint32_t gpFlags = GrDefaultGeoProcFactory::kPosition_GPType | | |
| 850 GrDefaultGeoProcFactory::kCoverage_GPType; | |
| 851 SkAutoTUnref<const GrGeometryProcessor> gp(GrDefaultGeoProcFactory::Crea te(gpFlags, | |
| 852 color, | |
| 853 vm, | |
| 854 invert, | |
| 855 false, | |
| 856 newCoverage)); | |
| 857 | |
| 858 if (!this->createLineGeom(target, | |
| 859 pipelineBuilder, | |
| 860 viewMatrix, | |
| 861 newCoverage, | |
| 862 gp->getVertexStride(), | |
| 863 &arg, | |
| 864 &devBounds, | |
| 865 path, | |
| 866 lines, | |
| 867 lineCnt)) { | |
| 868 return false; | |
| 869 } | |
| 870 | |
| 871 // Check devBounds | |
| 872 SkASSERT(check_bounds<LineVertex>(viewMatrix.hasPerspective() ? viewMatr ix : SkMatrix::I(), | |
| 873 devBounds, | |
| 874 arg.vertices(), | |
| 875 kLineSegNumVertices * lineCnt)); | |
| 876 | |
| 877 { | |
| 878 target->setIndexSourceToBuffer(fLinesIndexBuffer); | |
| 879 int lines = 0; | |
| 880 while (lines < lineCnt) { | |
| 881 int n = SkTMin(lineCnt - lines, kLineSegsNumInIdxBuffer); | |
| 882 target->drawIndexed(pipelineBuilder, | |
| 883 gp, | |
| 884 kTriangles_GrPrimitiveType, | |
| 885 kLineSegNumVertices*lines, // startV | |
| 886 0, // startI | |
| 887 kLineSegNumVertices*n, // vCount | |
| 888 kIdxsPerLineSeg*n, // iCount | |
| 889 &devBounds); | |
| 890 lines += n; | |
| 891 } | |
| 892 } | |
| 893 } | |
| 894 | |
| 895 // then quadratics/conics | |
| 896 if (quadCnt || conicCnt) { | |
| 897 GrDrawTarget::AutoReleaseGeometry arg; | |
| 898 SkRect devBounds; | |
| 899 | |
| 900 if (!this->createBezierGeom(target, | |
| 901 pipelineBuilder, | |
| 902 viewMatrix, | |
| 903 &arg, | |
| 904 &devBounds, | |
| 905 path, | |
| 906 quads, | |
| 907 quadCnt, | |
| 908 conics, | |
| 909 conicCnt, | |
| 910 qSubdivs, | |
| 911 cWeights, | |
| 912 sizeof(BezierVertex))) { | |
| 913 return false; | |
| 914 } | |
| 915 | |
| 916 // Check devBounds | |
| 917 SkASSERT(check_bounds<BezierVertex>(viewMatrix.hasPerspective() ? viewMa trix : | |
| 918 SkMatr ix::I(), | |
| 919 devBounds, | |
| 920 arg.vertices(), | |
| 921 kQuadNumVertices * quadCnt + | |
| 922 kQuadNumVertices * conicCnt)); | |
| 923 | |
| 924 if (quadCnt > 0) { | |
| 925 SkAutoTUnref<GrGeometryProcessor> hairQuadProcessor( | |
| 926 GrQuadEffect::Create(color, | |
| 927 vm, | |
| 928 kHairlineAA_GrProcessorEdgeType, | |
| 929 *target->caps(), | |
| 930 invert, | |
| 931 newCoverage)); | |
| 932 SkASSERT(hairQuadProcessor); | |
| 933 GrPipelineBuilder::AutoRestoreEffects are(pipelineBuilder); | |
| 934 target->setIndexSourceToBuffer(fQuadsIndexBuffer); | |
| 935 | |
| 936 int quads = 0; | |
| 937 while (quads < quadCnt) { | |
| 938 int n = SkTMin(quadCnt - quads, kQuadsNumInIdxBuffer); | |
| 939 target->drawIndexed(pipelineBuilder, | |
| 940 hairQuadProcessor, | |
| 941 kTriangles_GrPrimitiveType, | |
| 942 kQuadNumVertices*quads, // sta rtV | |
| 943 0, // sta rtI | |
| 944 kQuadNumVertices*n, // vCo unt | |
| 945 kIdxsPerQuad*n, // iCo unt | |
| 946 &devBounds); | |
| 947 quads += n; | |
| 948 } | |
| 949 } | |
| 950 | |
| 951 if (conicCnt > 0) { | |
| 952 SkAutoTUnref<GrGeometryProcessor> hairConicProcessor( | |
| 953 GrConicEffect::Create(color, vm, kHairlineAA_GrProcessorEdge Type, | |
| 954 *target->caps(), invert, newCoverage)) ; | |
| 955 SkASSERT(hairConicProcessor); | |
| 956 GrPipelineBuilder::AutoRestoreEffects are(pipelineBuilder); | |
| 957 target->setIndexSourceToBuffer(fQuadsIndexBuffer); | |
| 958 | |
| 959 int conics = 0; | |
| 960 while (conics < conicCnt) { | |
| 961 int n = SkTMin(conicCnt - conics, kQuadsNumInIdxBuffer); | |
| 962 target->drawIndexed(pipelineBuilder, | |
| 963 hairConicProcessor, | |
| 964 kTriangles_GrPrimitiveType, | |
| 965 kQuadNumVertices*(quadCnt + conics), // sta rtV | |
| 966 0, // sta rtI | |
| 967 kQuadNumVertices*n, // vCo unt | |
| 968 kIdxsPerQuad*n, // iCo unt | |
| 969 &devBounds); | |
| 970 conics += n; | |
| 971 } | |
| 972 } | |
| 973 } | |
| 974 | |
| 975 target->resetIndexSource(); | |
| 976 | 1168 |
| 977 return true; | 1169 return true; |
| 978 } | 1170 } |
| OLD | NEW |