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" | |
13 #include "GrContext.h" | 10 #include "GrContext.h" |
14 #include "GrDefaultGeoProcFactory.h" | 11 #include "GrDefaultGeoProcFactory.h" |
15 #include "GrDrawTargetCaps.h" | 12 #include "GrDrawTargetCaps.h" |
16 #include "GrGpu.h" | 13 #include "GrGpu.h" |
17 #include "GrIndexBuffer.h" | 14 #include "GrIndexBuffer.h" |
18 #include "GrPathUtils.h" | 15 #include "GrPathUtils.h" |
19 #include "GrPipelineBuilder.h" | 16 #include "GrPipelineBuilder.h" |
20 #include "GrProcessor.h" | 17 #include "GrProcessor.h" |
21 #include "SkGeometry.h" | 18 #include "SkGeometry.h" |
22 #include "SkStroke.h" | 19 #include "SkStroke.h" |
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
249 | 246 |
250 /** | 247 /** |
251 * Generates the lines and quads to be rendered. Lines are always recorded in | 248 * Generates the lines and quads to be rendered. Lines are always recorded in |
252 * device space. We will do a device space bloat to account for the 1pixel | 249 * device space. We will do a device space bloat to account for the 1pixel |
253 * thickness. | 250 * thickness. |
254 * Quads are recorded in device space unless m contains | 251 * Quads are recorded in device space unless m contains |
255 * perspective, then in they are in src space. We do this because we will | 252 * perspective, then in they are in src space. We do this because we will |
256 * subdivide large quads to reduce over-fill. This subdivision has to be | 253 * subdivide large quads to reduce over-fill. This subdivision has to be |
257 * performed before applying the perspective matrix. | 254 * performed before applying the perspective matrix. |
258 */ | 255 */ |
259 int gather_lines_and_quads(const SkPath& path, | 256 int generate_lines_and_quads(const SkPath& path, |
260 const SkMatrix& m, | 257 const SkMatrix& m, |
261 const SkIRect& devClipBounds, | 258 const SkIRect& devClipBounds, |
262 GrAAHairLinePathRenderer::PtArray* lines, | 259 GrAAHairLinePathRenderer::PtArray* lines, |
263 GrAAHairLinePathRenderer::PtArray* quads, | 260 GrAAHairLinePathRenderer::PtArray* quads, |
264 GrAAHairLinePathRenderer::PtArray* conics, | 261 GrAAHairLinePathRenderer::PtArray* conics, |
265 GrAAHairLinePathRenderer::IntArray* quadSubdivCnts, | 262 GrAAHairLinePathRenderer::IntArray* quadSubdivCnts, |
266 GrAAHairLinePathRenderer::FloatArray* conicWeights) { | 263 GrAAHairLinePathRenderer::FloatArray* conicWeights)
{ |
267 SkPath::Iter iter(path, false); | 264 SkPath::Iter iter(path, false); |
268 | 265 |
269 int totalQuadCount = 0; | 266 int totalQuadCount = 0; |
270 SkRect bounds; | 267 SkRect bounds; |
271 SkIRect ibounds; | 268 SkIRect ibounds; |
272 | 269 |
273 bool persp = m.hasPerspective(); | 270 bool persp = m.hasPerspective(); |
274 | 271 |
275 for (;;) { | 272 for (;;) { |
276 SkPoint pathPts[4]; | 273 SkPoint pathPts[4]; |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
465 result->fY = SkScalarMul(result->fY, wInv); | 462 result->fY = SkScalarMul(result->fY, wInv); |
466 } | 463 } |
467 | 464 |
468 void set_uv_quad(const SkPoint qpts[3], BezierVertex verts[kQuadNumVertices]) { | 465 void set_uv_quad(const SkPoint qpts[3], BezierVertex verts[kQuadNumVertices]) { |
469 // this should be in the src space, not dev coords, when we have perspective | 466 // this should be in the src space, not dev coords, when we have perspective |
470 GrPathUtils::QuadUVMatrix DevToUV(qpts); | 467 GrPathUtils::QuadUVMatrix DevToUV(qpts); |
471 DevToUV.apply<kQuadNumVertices, sizeof(BezierVertex), sizeof(SkPoint)>(verts
); | 468 DevToUV.apply<kQuadNumVertices, sizeof(BezierVertex), sizeof(SkPoint)>(verts
); |
472 } | 469 } |
473 | 470 |
474 void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, | 471 void bloat_quad(const SkPoint qpts[3], const SkMatrix* toDevice, |
475 const SkMatrix* toSrc, BezierVertex verts[kQuadNumVertices]) { | 472 const SkMatrix* toSrc, BezierVertex verts[kQuadNumVertices], |
| 473 SkRect* devBounds) { |
476 SkASSERT(!toDevice == !toSrc); | 474 SkASSERT(!toDevice == !toSrc); |
477 // original quad is specified by tri a,b,c | 475 // original quad is specified by tri a,b,c |
478 SkPoint a = qpts[0]; | 476 SkPoint a = qpts[0]; |
479 SkPoint b = qpts[1]; | 477 SkPoint b = qpts[1]; |
480 SkPoint c = qpts[2]; | 478 SkPoint c = qpts[2]; |
481 | 479 |
482 if (toDevice) { | 480 if (toDevice) { |
483 toDevice->mapPoints(&a, 1); | 481 toDevice->mapPoints(&a, 1); |
484 toDevice->mapPoints(&b, 1); | 482 toDevice->mapPoints(&b, 1); |
485 toDevice->mapPoints(&c, 1); | 483 toDevice->mapPoints(&c, 1); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
530 a0.fPos += abN; | 528 a0.fPos += abN; |
531 a1.fPos = a; | 529 a1.fPos = a; |
532 a1.fPos -= abN; | 530 a1.fPos -= abN; |
533 | 531 |
534 c0.fPos = c; | 532 c0.fPos = c; |
535 c0.fPos += cbN; | 533 c0.fPos += cbN; |
536 c1.fPos = c; | 534 c1.fPos = c; |
537 c1.fPos -= cbN; | 535 c1.fPos -= cbN; |
538 | 536 |
539 intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos); | 537 intersect_lines(a0.fPos, abN, c0.fPos, cbN, &b0.fPos); |
| 538 devBounds->growToInclude(&verts[0].fPos, sizeof(BezierVertex), kQuadNumVerti
ces); |
540 | 539 |
541 if (toSrc) { | 540 if (toSrc) { |
542 toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(BezierVertex), kQuadNu
mVertices); | 541 toSrc->mapPointsWithStride(&verts[0].fPos, sizeof(BezierVertex), kQuadNu
mVertices); |
543 } | 542 } |
544 } | 543 } |
545 | 544 |
546 // Equations based off of Loop-Blinn Quadratic GPU Rendering | 545 // Equations based off of Loop-Blinn Quadratic GPU Rendering |
547 // Input Parametric: | 546 // Input Parametric: |
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) | 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) |
549 // Output Implicit: | 548 // Output Implicit: |
(...skipping 11 matching lines...) Expand all Loading... |
561 verts[i].fConic.fK = pnt.fX * klm[0] + pnt.fY * klm[1] + klm[2]; | 560 verts[i].fConic.fK = pnt.fX * klm[0] + pnt.fY * klm[1] + klm[2]; |
562 verts[i].fConic.fL = pnt.fX * klm[3] + pnt.fY * klm[4] + klm[5]; | 561 verts[i].fConic.fL = pnt.fX * klm[3] + pnt.fY * klm[4] + klm[5]; |
563 verts[i].fConic.fM = pnt.fX * klm[6] + pnt.fY * klm[7] + klm[8]; | 562 verts[i].fConic.fM = pnt.fX * klm[6] + pnt.fY * klm[7] + klm[8]; |
564 } | 563 } |
565 } | 564 } |
566 | 565 |
567 void add_conics(const SkPoint p[3], | 566 void add_conics(const SkPoint p[3], |
568 const SkScalar weight, | 567 const SkScalar weight, |
569 const SkMatrix* toDevice, | 568 const SkMatrix* toDevice, |
570 const SkMatrix* toSrc, | 569 const SkMatrix* toSrc, |
571 BezierVertex** vert) { | 570 BezierVertex** vert, |
572 bloat_quad(p, toDevice, toSrc, *vert); | 571 SkRect* devBounds) { |
| 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) { |
582 SkASSERT(subdiv >= 0); | 583 SkASSERT(subdiv >= 0); |
583 if (subdiv) { | 584 if (subdiv) { |
584 SkPoint newP[5]; | 585 SkPoint newP[5]; |
585 SkChopQuadAtHalf(p, newP); | 586 SkChopQuadAtHalf(p, newP); |
586 add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert); | 587 add_quads(newP + 0, subdiv-1, toDevice, toSrc, vert, devBounds); |
587 add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert); | 588 add_quads(newP + 2, subdiv-1, toDevice, toSrc, vert, devBounds); |
588 } else { | 589 } else { |
589 bloat_quad(p, toDevice, toSrc, *vert); | 590 bloat_quad(p, toDevice, toSrc, *vert, devBounds); |
590 set_uv_quad(p, *vert); | 591 set_uv_quad(p, *vert); |
591 *vert += kQuadNumVertices; | 592 *vert += kQuadNumVertices; |
592 } | 593 } |
593 } | 594 } |
594 | 595 |
595 void add_line(const SkPoint p[2], | 596 void add_line(const SkPoint p[2], |
596 const SkMatrix* toSrc, | 597 const SkMatrix* toSrc, |
597 uint8_t coverage, | 598 uint8_t coverage, |
598 LineVertex** vert) { | 599 LineVertex** vert) { |
599 const SkPoint& a = p[0]; | 600 const SkPoint& a = p[0]; |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
634 } | 635 } |
635 } | 636 } |
636 | 637 |
637 *vert += kLineSegNumVertices; | 638 *vert += kLineSegNumVertices; |
638 } | 639 } |
639 | 640 |
640 } | 641 } |
641 | 642 |
642 /////////////////////////////////////////////////////////////////////////////// | 643 /////////////////////////////////////////////////////////////////////////////// |
643 | 644 |
| 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 |
644 bool GrAAHairLinePathRenderer::canDrawPath(const GrDrawTarget* target, | 745 bool GrAAHairLinePathRenderer::canDrawPath(const GrDrawTarget* target, |
645 const GrPipelineBuilder* pipelineBuil
der, | 746 const GrPipelineBuilder* pipelineBuil
der, |
646 const SkMatrix& viewMatrix, | 747 const SkMatrix& viewMatrix, |
647 const SkPath& path, | 748 const SkPath& path, |
648 const SkStrokeRec& stroke, | 749 const SkStrokeRec& stroke, |
649 bool antiAlias) const { | 750 bool antiAlias) const { |
650 if (!antiAlias) { | 751 if (!antiAlias) { |
651 return false; | 752 return false; |
652 } | 753 } |
653 | 754 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
692 actualBounds.growToInclude(pos.fX, pos.fY); | 793 actualBounds.growToInclude(pos.fX, pos.fY); |
693 } | 794 } |
694 } | 795 } |
695 if (!first) { | 796 if (!first) { |
696 return tolDevBounds.contains(actualBounds); | 797 return tolDevBounds.contains(actualBounds); |
697 } | 798 } |
698 | 799 |
699 return true; | 800 return true; |
700 } | 801 } |
701 | 802 |
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 | |
870 // TODO remove this when batch is everywhere | |
871 GrPipelineInfo init; | |
872 init.fColorIgnored = fBatch.fColorIgnored; | |
873 init.fOverrideColor = GrColor_ILLEGAL; | |
874 init.fCoverageIgnored = fBatch.fCoverageIgnored; | |
875 init.fUsesLocalCoords = this->usesLocalCoords(); | |
876 gp->initBatchTracker(batchTarget->currentBatchTracker(), init); | |
877 | |
878 const GrVertexBuffer* vertexBuffer; | |
879 int firstVertex; | |
880 | |
881 size_t vertexStride = gp->getVertexStride(); | |
882 int vertexCount = kLineSegNumVertices * lineCnt; | |
883 void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride, | |
884 vertexCount, | |
885 &vertexBuffer, | |
886 &firstVertex); | |
887 | |
888 SkASSERT(gp->getVertexStride() == sizeof(LineVertex)); | |
889 | |
890 // generate lines | |
891 const SkMatrix* toSrc = NULL; | |
892 if (args.fViewMatrix.hasPerspective()) { | |
893 SkMatrix perspectiveInvert; | |
894 if (!args.fViewMatrix.invert(&perspectiveInvert)) { | |
895 return; | |
896 } | |
897 toSrc = &perspectiveInvert; | |
898 } | |
899 | |
900 LineVertex* verts = reinterpret_cast<LineVertex*>(vertices); | |
901 for (int i = 0; i < lineCnt; ++i) { | |
902 add_line(&lines[2*i], toSrc, args.fCoverage, &verts); | |
903 } | |
904 | |
905 // Check devBounds | |
906 SkASSERT(check_bounds<LineVertex>(viewMatrix.hasPerspective() ? viewMatr
ix : SkMatrix::I(), | |
907 args.fDevBounds, | |
908 vertices, | |
909 kLineSegNumVertices * lineCnt)); | |
910 | |
911 { | |
912 GrDrawTarget::DrawInfo info; | |
913 info.setVertexBuffer(vertexBuffer); | |
914 info.setIndexBuffer(fLinesIndexBuffer); | |
915 info.setPrimitiveType(kTriangles_GrPrimitiveType); | |
916 info.setStartIndex(0); | |
917 | |
918 int lines = 0; | |
919 while (lines < lineCnt) { | |
920 int n = SkTMin(lineCnt - lines, kLineSegsNumInIdxBuffer); | |
921 | |
922 info.setStartVertex(kLineSegNumVertices*lines + firstVertex); | |
923 info.setVertexCount(kLineSegNumVertices*n); | |
924 info.setIndexCount(kIdxsPerLineSeg*n); | |
925 batchTarget->draw(info); | |
926 | |
927 lines += n; | |
928 } | |
929 } | |
930 } | |
931 | |
932 void generateQuadsAndConics(GrBatchTarget* batchTarget, | |
933 const GrPipeline* pipeline, | |
934 const Geometry& args, | |
935 const PREALLOC_PTARRAY(128)& quads, | |
936 int quadCount, | |
937 const PREALLOC_PTARRAY(128)& conics, | |
938 int conicCount, | |
939 const IntArray& qSubdivs, | |
940 const FloatArray& cWeights, | |
941 const SkMatrix& vm, | |
942 const SkMatrix& invert) { | |
943 const GrVertexBuffer* vertexBuffer; | |
944 int firstVertex; | |
945 | |
946 size_t vertexStride = sizeof(BezierVertex); | |
947 int vertexCount = kQuadNumVertices * quadCount + kQuadNumVertices * coni
cCount; | |
948 void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride, | |
949 vertexCount, | |
950 &vertexBuffer, | |
951 &firstVertex); | |
952 | |
953 if (!this->createBezierGeom(vertices, | |
954 args.fViewMatrix, | |
955 args.fPath, | |
956 quads, | |
957 quadCount, | |
958 conics, | |
959 conicCount, | |
960 qSubdivs, | |
961 cWeights, | |
962 vertexStride)) { | |
963 SkDebugf("Couldn't create bezier geometry\n"); | |
964 return; | |
965 } | |
966 | |
967 // Check devBounds | |
968 SkASSERT(check_bounds<BezierVertex>(vm, | |
969 args.fDevBounds, | |
970 vertices, | |
971 kQuadNumVertices * quadCount + | |
972 kQuadNumVertices * conicCount)); | |
973 | |
974 if (quadCount > 0) { | |
975 SkAutoTUnref<GrGeometryProcessor> hairQuadProcessor( | |
976 GrQuadEffect::Create(args.fColor, | |
977 vm, | |
978 kHairlineAA_GrProcessorEdgeType, | |
979 batchTarget->caps(), | |
980 invert, | |
981 args.fCoverage)); | |
982 | |
983 batchTarget->initDraw(hairQuadProcessor, pipeline); | |
984 | |
985 // TODO remove this when batch is everywhere | |
986 GrPipelineInfo init; | |
987 init.fColorIgnored = fBatch.fColorIgnored; | |
988 init.fOverrideColor = GrColor_ILLEGAL; | |
989 init.fCoverageIgnored = fBatch.fCoverageIgnored; | |
990 init.fUsesLocalCoords = this->usesLocalCoords(); | |
991 hairQuadProcessor->initBatchTracker(batchTarget->currentBatchTracker
(), init); | |
992 | |
993 this->drawBeziers(batchTarget, | |
994 hairQuadProcessor, | |
995 pipeline, | |
996 vertexBuffer, | |
997 firstVertex, | |
998 quadCount); | |
999 } | |
1000 | |
1001 if (conicCount > 0) { | |
1002 SkAutoTUnref<GrGeometryProcessor> hairConicProcessor( | |
1003 GrConicEffect::Create(args.fColor, | |
1004 vm, | |
1005 kHairlineAA_GrProcessorEdgeType, | |
1006 batchTarget->caps(), | |
1007 invert, | |
1008 args.fCoverage)); | |
1009 | |
1010 batchTarget->initDraw(hairConicProcessor, pipeline); | |
1011 | |
1012 // TODO remove this when batch is everywhere | |
1013 GrPipelineInfo init; | |
1014 init.fColorIgnored = fBatch.fColorIgnored; | |
1015 init.fOverrideColor = GrColor_ILLEGAL; | |
1016 init.fCoverageIgnored = fBatch.fCoverageIgnored; | |
1017 init.fUsesLocalCoords = this->usesLocalCoords(); | |
1018 hairConicProcessor->initBatchTracker(batchTarget->currentBatchTracke
r(), init); | |
1019 | |
1020 this->drawConics(batchTarget, | |
1021 hairConicProcessor, | |
1022 pipeline, | |
1023 vertexBuffer, | |
1024 firstVertex, | |
1025 conicCount, | |
1026 quadCount); | |
1027 } | |
1028 } | |
1029 | |
1030 bool createBezierGeom(void* vertices, | |
1031 const SkMatrix& viewMatrix, | |
1032 const SkPath& path, | |
1033 const PtArray& quads, | |
1034 int quadCnt, | |
1035 const PtArray& conics, | |
1036 int conicCnt, | |
1037 const IntArray& qSubdivs, | |
1038 const FloatArray& cWeights, | |
1039 size_t vertexStride) { | |
1040 BezierVertex* verts = reinterpret_cast<BezierVertex*>(vertices); | |
1041 | |
1042 const SkMatrix* toDevice = NULL; | |
1043 const SkMatrix* toSrc = NULL; | |
1044 SkMatrix ivm; | |
1045 | |
1046 if (viewMatrix.hasPerspective()) { | |
1047 if (viewMatrix.invert(&ivm)) { | |
1048 toDevice = &viewMatrix; | |
1049 toSrc = &ivm; | |
1050 } | |
1051 } | |
1052 | |
1053 int unsubdivQuadCnt = quads.count() / 3; | |
1054 for (int i = 0; i < unsubdivQuadCnt; ++i) { | |
1055 SkASSERT(qSubdivs[i] >= 0); | |
1056 add_quads(&quads[3*i], qSubdivs[i], toDevice, toSrc, &verts); | |
1057 } | |
1058 | |
1059 // Start Conics | |
1060 for (int i = 0; i < conicCnt; ++i) { | |
1061 add_conics(&conics[3*i], cWeights[i], toDevice, toSrc, &verts); | |
1062 } | |
1063 return true; | |
1064 } | |
1065 | |
1066 void drawBeziers(GrBatchTarget* batchTarget, | |
1067 const GrGeometryProcessor* hairQuadProcessor, | |
1068 const GrPipeline* pipeline, | |
1069 const GrVertexBuffer* vertexBuffer, | |
1070 int firstVertex, | |
1071 int quadCount) { | |
1072 GrDrawTarget::DrawInfo info; | |
1073 info.setVertexBuffer(vertexBuffer); | |
1074 info.setIndexBuffer(fQuadsIndexBuffer); | |
1075 info.setPrimitiveType(kTriangles_GrPrimitiveType); | |
1076 info.setStartIndex(0); | |
1077 | |
1078 int quads = 0; | |
1079 while (quads < quadCount) { | |
1080 int n = SkTMin(quadCount - quads, kQuadsNumInIdxBuffer); | |
1081 | |
1082 info.setStartVertex(kQuadNumVertices*quads + firstVertex); | |
1083 info.setVertexCount(kQuadNumVertices*n); | |
1084 info.setIndexCount(kIdxsPerQuad*n); | |
1085 batchTarget->draw(info); | |
1086 | |
1087 quads += n; | |
1088 } | |
1089 } | |
1090 | |
1091 void drawConics(GrBatchTarget* batchTarget, | |
1092 const GrGeometryProcessor* hairConicProcessor, | |
1093 const GrPipeline* pipeline, | |
1094 const GrVertexBuffer* vertexBuffer, | |
1095 int firstVertex, | |
1096 int conicCount, | |
1097 int quadCount) { | |
1098 GrDrawTarget::DrawInfo info; | |
1099 info.setVertexBuffer(vertexBuffer); | |
1100 info.setIndexBuffer(fQuadsIndexBuffer); | |
1101 info.setPrimitiveType(kTriangles_GrPrimitiveType); | |
1102 info.setStartIndex(0); | |
1103 | |
1104 int conics = 0; | |
1105 while (conics < conicCount) { | |
1106 int n = SkTMin(conicCount - conics, kQuadsNumInIdxBuffer); | |
1107 | |
1108 info.setStartVertex(kQuadNumVertices*(quadCount + conics) + firstVer
tex); | |
1109 info.setVertexCount(kQuadNumVertices*n); | |
1110 info.setIndexCount(kIdxsPerQuad*n); | |
1111 batchTarget->draw(info); | |
1112 | |
1113 conics += n; | |
1114 } | |
1115 } | |
1116 | |
1117 struct BatchTracker { | |
1118 GrColor fColor; | |
1119 uint8_t fCoverage; | |
1120 SkRect fDevBounds; | |
1121 bool fUsesLocalCoords; | |
1122 bool fColorIgnored; | |
1123 bool fCoverageIgnored; | |
1124 }; | |
1125 | |
1126 GrBatchOpt fBatchOpt; | |
1127 BatchTracker fBatch; | |
1128 SkSTArray<1, Geometry, true> fGeoData; | |
1129 const GrIndexBuffer* fLinesIndexBuffer; | |
1130 const GrIndexBuffer* fQuadsIndexBuffer; | |
1131 }; | |
1132 | |
1133 bool GrAAHairLinePathRenderer::onDrawPath(GrDrawTarget* target, | 803 bool GrAAHairLinePathRenderer::onDrawPath(GrDrawTarget* target, |
1134 GrPipelineBuilder* pipelineBuilder, | 804 GrPipelineBuilder* pipelineBuilder, |
1135 GrColor color, | 805 GrColor color, |
1136 const SkMatrix& viewMatrix, | 806 const SkMatrix& viewMatrix, |
1137 const SkPath& path, | 807 const SkPath& path, |
1138 const SkStrokeRec& stroke, | 808 const SkStrokeRec& stroke, |
1139 bool) { | 809 bool antiAlias) { |
1140 SkScalar hairlineCoverage; | 810 SkScalar hairlineCoverage; |
1141 uint8_t newCoverage = 0xff; | 811 uint8_t newCoverage = 0xff; |
1142 if (IsStrokeHairlineOrEquivalent(stroke, viewMatrix, &hairlineCoverage)) { | 812 if (IsStrokeHairlineOrEquivalent(stroke, viewMatrix, &hairlineCoverage)) { |
1143 newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff); | 813 newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff); |
1144 } | 814 } |
1145 | 815 |
1146 SkIRect devClipBounds; | 816 SkIRect devClipBounds; |
1147 target->getClip()->getConservativeBounds(pipelineBuilder->getRenderTarget(),
&devClipBounds); | 817 target->getClip()->getConservativeBounds(pipelineBuilder->getRenderTarget(),
&devClipBounds); |
1148 | 818 |
1149 // This outset was determined experimentally by running skps and gms. It pr
obably could be a | 819 int lineCnt; |
1150 // bit tighter | 820 int quadCnt; |
1151 SkRect devRect = path.getBounds(); | 821 int conicCnt; |
1152 devRect.outset(7, 7); | 822 PREALLOC_PTARRAY(128) lines; |
1153 viewMatrix.mapRect(&devRect); | 823 PREALLOC_PTARRAY(128) quads; |
| 824 PREALLOC_PTARRAY(128) conics; |
| 825 IntArray qSubdivs; |
| 826 FloatArray cWeights; |
| 827 quadCnt = generate_lines_and_quads(path, viewMatrix, devClipBounds, |
| 828 &lines, &quads, &conics, &qSubdivs, &cWei
ghts); |
| 829 lineCnt = lines.count() / 2; |
| 830 conicCnt = conics.count() / 3; |
1154 | 831 |
1155 AAHairlineBatch::Geometry geometry; | 832 // createGeom transforms the geometry to device space when the matrix does n
ot have |
1156 geometry.fColor = color; | 833 // perspective. |
1157 geometry.fCoverage = newCoverage; | 834 SkMatrix vm = viewMatrix; |
1158 geometry.fViewMatrix = viewMatrix; | 835 SkMatrix invert = SkMatrix::I(); |
1159 geometry.fPath = path; | 836 if (!viewMatrix.hasPerspective()) { |
1160 SkDEBUGCODE(geometry.fDevBounds = devRect;) | 837 vm = SkMatrix::I(); |
1161 geometry.fDevClipBounds = devClipBounds; | 838 if (!viewMatrix.invert(&invert)) { |
| 839 return false; |
| 840 } |
| 841 } |
1162 | 842 |
1163 GrBatch* batch = AAHairlineBatch::Create(geometry, fLinesIndexBuffer, fQuads
IndexBuffer); | 843 // do lines first |
1164 target->drawBatch(pipelineBuilder, batch, &devRect); | 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(); |
1165 | 976 |
1166 return true; | 977 return true; |
1167 } | 978 } |
OLD | NEW |