OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 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 "GrAARectRenderer.h" | 8 #include "GrAARectRenderer.h" |
9 #include "GrBatch.h" | 9 #include "GrBatch.h" |
10 #include "GrBatchTarget.h" | 10 #include "GrBatchTarget.h" |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
90 fBatch.fColor = fGeoData[0].fColor; | 90 fBatch.fColor = fGeoData[0].fColor; |
91 fBatch.fUsesLocalCoords = init.fUsesLocalCoords; | 91 fBatch.fUsesLocalCoords = init.fUsesLocalCoords; |
92 fBatch.fCoverageIgnored = init.fCoverageIgnored; | 92 fBatch.fCoverageIgnored = init.fCoverageIgnored; |
93 fBatch.fCanTweakAlphaForCoverage = init.fCanTweakAlphaForCoverage; | 93 fBatch.fCanTweakAlphaForCoverage = init.fCanTweakAlphaForCoverage; |
94 } | 94 } |
95 | 95 |
96 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline
) SK_OVERRIDE { | 96 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline
) SK_OVERRIDE { |
97 bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage(); | 97 bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage(); |
98 | 98 |
99 SkMatrix localMatrix; | 99 SkMatrix localMatrix; |
100 if (!this->viewMatrix().invert(&localMatrix)) { | 100 if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix))
{ |
101 SkDebugf("Cannot invert\n"); | 101 SkDebugf("Cannot invert\n"); |
102 return; | 102 return; |
103 } | 103 } |
104 | 104 |
105 const GrGeometryProcessor* gp = create_fill_rect_gp(canTweakAlphaForCove
rage, | 105 SkAutoTUnref<const GrGeometryProcessor> gp(create_fill_rect_gp(canTweakA
lphaForCoverage, |
106 localMatrix); | 106 localMatr
ix)); |
107 | 107 |
108 batchTarget->initDraw(gp, pipeline); | 108 batchTarget->initDraw(gp, pipeline); |
109 gp->unref(); | |
110 | 109 |
111 // TODO this is hacky, but the only way we have to initialize the GP is
to use the | 110 // TODO this is hacky, but the only way we have to initialize the GP is
to use the |
112 // GrPipelineInfo struct so we can generate the correct shader. Once we
have GrBatch | 111 // GrPipelineInfo struct so we can generate the correct shader. Once we
have GrBatch |
113 // everywhere we can remove this nastiness | 112 // everywhere we can remove this nastiness |
114 GrPipelineInfo init; | 113 GrPipelineInfo init; |
115 init.fColorIgnored = fBatch.fColorIgnored; | 114 init.fColorIgnored = fBatch.fColorIgnored; |
116 init.fOverrideColor = GrColor_ILLEGAL; | 115 init.fOverrideColor = GrColor_ILLEGAL; |
117 init.fCoverageIgnored = fBatch.fCoverageIgnored; | 116 init.fCoverageIgnored = fBatch.fCoverageIgnored; |
118 init.fUsesLocalCoords = this->usesLocalCoords(); | 117 init.fUsesLocalCoords = this->usesLocalCoords(); |
119 gp->initBatchTracker(batchTarget->currentBatchTracker(), init); | 118 gp->initBatchTracker(batchTarget->currentBatchTracker(), init); |
120 | 119 |
121 size_t vertexStride = gp->getVertexStride(); | 120 size_t vertexStride = gp->getVertexStride(); |
122 | 121 |
123 SkASSERT(canTweakAlphaForCoverage ? | 122 SkASSERT(canTweakAlphaForCoverage ? |
124 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAt
tr) : | 123 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAt
tr) : |
125 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCo
verageAttr)); | 124 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCo
verageAttr)); |
126 | 125 |
127 int instanceCount = fGeoData.count(); | 126 int instanceCount = fGeoData.count(); |
128 int vertexCount = kVertsPerAAFillRect * instanceCount; | 127 int vertexCount = kVertsPerAAFillRect * instanceCount; |
129 | 128 |
130 const GrVertexBuffer* vertexBuffer; | 129 const GrVertexBuffer* vertexBuffer; |
131 int firstVertex; | 130 int firstVertex; |
132 | 131 |
133 void *vertices = batchTarget->vertexPool()->makeSpace(vertexStride, | 132 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride, |
134 vertexCount, | 133 vertexCount, |
135 &vertexBuffer, | 134 &vertexBuffer, |
136 &firstVertex); | 135 &firstVertex); |
137 | 136 |
138 for (int i = 0; i < instanceCount; i++) { | 137 for (int i = 0; i < instanceCount; i++) { |
139 const Geometry& args = fGeoData[i]; | 138 const Geometry& args = fGeoData[i]; |
140 this->generateAAFillRectGeometry(vertices, | 139 this->generateAAFillRectGeometry(vertices, |
141 i * kVertsPerAAFillRect * vertexStride, | 140 i * kVertsPerAAFillRect * vertexStr
ide, |
142 vertexStride, | 141 vertexStride, |
143 args.fColor, | 142 args.fColor, |
144 args.fViewMatrix, | 143 args.fViewMatrix, |
145 args.fRect, | 144 args.fRect, |
146 args.fDevRect, | 145 args.fDevRect, |
147 canTweakAlphaForCoverage); | 146 canTweakAlphaForCoverage); |
148 } | 147 } |
149 | 148 |
150 GrDrawTarget::DrawInfo drawInfo; | 149 GrDrawTarget::DrawInfo drawInfo; |
151 drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType); | 150 drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType); |
152 drawInfo.setStartVertex(0); | 151 drawInfo.setStartVertex(0); |
153 drawInfo.setStartIndex(0); | 152 drawInfo.setStartIndex(0); |
154 drawInfo.setVerticesPerInstance(kVertsPerAAFillRect); | 153 drawInfo.setVerticesPerInstance(kVertsPerAAFillRect); |
155 drawInfo.setIndicesPerInstance(kIndicesPerAAFillRect); | 154 drawInfo.setIndicesPerInstance(kIndicesPerAAFillRect); |
156 drawInfo.adjustStartVertex(firstVertex); | 155 drawInfo.adjustStartVertex(firstVertex); |
157 drawInfo.setVertexBuffer(vertexBuffer); | 156 drawInfo.setVertexBuffer(vertexBuffer); |
(...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
527 // edge, while vertex number of inner edge is 4, the same as miter-stroke. | 526 // edge, while vertex number of inner edge is 4, the same as miter-stroke. |
528 if (!miterStroke) { | 527 if (!miterStroke) { |
529 devOutside.inset(0, ry); | 528 devOutside.inset(0, ry); |
530 devOutsideAssist.outset(0, ry); | 529 devOutsideAssist.outset(0, ry); |
531 } | 530 } |
532 | 531 |
533 this->geometryStrokeAARect(target, pipelineBuilder, color, viewMatrix, devOu
tside, | 532 this->geometryStrokeAARect(target, pipelineBuilder, color, viewMatrix, devOu
tside, |
534 devOutsideAssist, devInside, miterStroke); | 533 devOutsideAssist, devInside, miterStroke); |
535 } | 534 } |
536 | 535 |
537 static const GrGeometryProcessor* create_rect_gp(const GrPipelineBuilder& pipeln
eBuilder, | 536 class AAStrokeRectBatch : public GrBatch { |
538 GrColor color, | 537 public: |
539 CoverageAttribType* type, | 538 // TODO support AA rotated stroke rects by copying around view matrices |
540 const SkMatrix& localMatrix) { | 539 struct Geometry { |
541 uint32_t flags = GrDefaultGeoProcFactory::kColor_GPType; | 540 GrColor fColor; |
542 const GrGeometryProcessor* gp; | 541 SkRect fDevOutside; |
543 if (pipelneBuilder.canTweakAlphaForCoverage()) { | 542 SkRect fDevOutsideAssist; |
544 gp = GrDefaultGeoProcFactory::Create(flags, color, SkMatrix::I(), localM
atrix); | 543 SkRect fDevInside; |
545 SkASSERT(gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::Positi
onColorAttr)); | 544 bool fMiterStroke; |
546 *type = kUseColor_CoverageAttribType; | 545 }; |
547 } else { | 546 |
548 flags |= GrDefaultGeoProcFactory::kCoverage_GPType; | 547 static GrBatch* Create(const Geometry& geometry, const SkMatrix& viewMatrix, |
549 gp = GrDefaultGeoProcFactory::Create(flags, color, SkMatrix::I(), localM
atrix, | 548 const GrIndexBuffer* indexBuffer) { |
550 GrColorIsOpaque(color)); | 549 return SkNEW_ARGS(AAStrokeRectBatch, (geometry, viewMatrix, indexBuffer)
); |
551 SkASSERT(gp->getVertexStride()==sizeof(GrDefaultGeoProcFactory::Position
ColorCoverageAttr)); | 550 } |
552 *type = kUseCoverage_CoverageAttribType; | 551 |
553 } | 552 const char* name() const SK_OVERRIDE { return "AAStrokeRect"; } |
554 return gp; | 553 |
555 } | 554 void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE { |
| 555 // When this is called on a batch, there is only one geometry bundle |
| 556 out->setKnownFourComponents(fGeoData[0].fColor); |
| 557 } |
| 558 |
| 559 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRID
E { |
| 560 out->setUnknownSingleComponent(); |
| 561 } |
| 562 |
| 563 void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE { |
| 564 // Handle any color overrides |
| 565 if (init.fColorIgnored) { |
| 566 fGeoData[0].fColor = GrColor_ILLEGAL; |
| 567 } else if (GrColor_ILLEGAL != init.fOverrideColor) { |
| 568 fGeoData[0].fColor = init.fOverrideColor; |
| 569 } |
| 570 |
| 571 // setup batch properties |
| 572 fBatch.fColorIgnored = init.fColorIgnored; |
| 573 fBatch.fColor = fGeoData[0].fColor; |
| 574 fBatch.fUsesLocalCoords = init.fUsesLocalCoords; |
| 575 fBatch.fCoverageIgnored = init.fCoverageIgnored; |
| 576 fBatch.fMiterStroke = fGeoData[0].fMiterStroke; |
| 577 fBatch.fCanTweakAlphaForCoverage = init.fCanTweakAlphaForCoverage; |
| 578 } |
| 579 |
| 580 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline
) SK_OVERRIDE { |
| 581 bool canTweakAlphaForCoverage = this->canTweakAlphaForCoverage(); |
| 582 |
| 583 // Local matrix is ignored if we don't have local coords. If we have lo
calcoords we only |
| 584 // batch with identical view matrices |
| 585 SkMatrix localMatrix; |
| 586 if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix))
{ |
| 587 SkDebugf("Cannot invert\n"); |
| 588 return; |
| 589 } |
| 590 |
| 591 SkAutoTUnref<const GrGeometryProcessor>gp(create_fill_rect_gp(canTweakAl
phaForCoverage, |
| 592 localMatri
x)); |
| 593 |
| 594 batchTarget->initDraw(gp, pipeline); |
| 595 |
| 596 // TODO this is hacky, but the only way we have to initialize the GP is
to use the |
| 597 // GrPipelineInfo struct so we can generate the correct shader. Once we
have GrBatch |
| 598 // everywhere we can remove this nastiness |
| 599 GrPipelineInfo init; |
| 600 init.fColorIgnored = fBatch.fColorIgnored; |
| 601 init.fOverrideColor = GrColor_ILLEGAL; |
| 602 init.fCoverageIgnored = fBatch.fCoverageIgnored; |
| 603 init.fUsesLocalCoords = this->usesLocalCoords(); |
| 604 gp->initBatchTracker(batchTarget->currentBatchTracker(), init); |
| 605 |
| 606 size_t vertexStride = gp->getVertexStride(); |
| 607 |
| 608 SkASSERT(canTweakAlphaForCoverage ? |
| 609 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorAt
tr) : |
| 610 vertexStride == sizeof(GrDefaultGeoProcFactory::PositionColorCo
verageAttr)); |
| 611 |
| 612 int innerVertexNum = 4; |
| 613 int outerVertexNum = this->miterStroke() ? 4 : 8; |
| 614 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2; |
| 615 |
| 616 int instanceCount = fGeoData.count(); |
| 617 int vertexCount = totalVertexNum * instanceCount; |
| 618 |
| 619 const GrVertexBuffer* vertexBuffer; |
| 620 int firstVertex; |
| 621 |
| 622 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride, |
| 623 vertexCount, |
| 624 &vertexBuffer, |
| 625 &firstVertex); |
| 626 |
| 627 for (int i = 0; i < instanceCount; i++) { |
| 628 const Geometry& args = fGeoData[i]; |
| 629 this->generateAAStrokeRectGeometry(vertices, |
| 630 i * totalVertexNum * vertexStride
, |
| 631 vertexStride, |
| 632 outerVertexNum, |
| 633 innerVertexNum, |
| 634 args.fColor, |
| 635 args.fDevOutside, |
| 636 args.fDevOutsideAssist, |
| 637 args.fDevInside, |
| 638 args.fMiterStroke, |
| 639 canTweakAlphaForCoverage); |
| 640 } |
| 641 |
| 642 GrDrawTarget::DrawInfo drawInfo; |
| 643 drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType); |
| 644 drawInfo.setStartVertex(0); |
| 645 drawInfo.setStartIndex(0); |
| 646 drawInfo.setVerticesPerInstance(totalVertexNum); |
| 647 drawInfo.setIndicesPerInstance(aa_stroke_rect_index_count(this->miterStr
oke())); |
| 648 drawInfo.adjustStartVertex(firstVertex); |
| 649 drawInfo.setVertexBuffer(vertexBuffer); |
| 650 drawInfo.setIndexBuffer(fIndexBuffer); |
| 651 |
| 652 int maxInstancesPerDraw = kNumBevelStrokeRectsInIndexBuffer; |
| 653 |
| 654 while (instanceCount) { |
| 655 drawInfo.setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw)
); |
| 656 drawInfo.setVertexCount(drawInfo.instanceCount() * drawInfo.vertices
PerInstance()); |
| 657 drawInfo.setIndexCount(drawInfo.instanceCount() * drawInfo.indicesPe
rInstance()); |
| 658 |
| 659 batchTarget->draw(drawInfo); |
| 660 |
| 661 drawInfo.setStartVertex(drawInfo.startVertex() + drawInfo.vertexCoun
t()); |
| 662 instanceCount -= drawInfo.instanceCount(); |
| 663 } |
| 664 } |
| 665 |
| 666 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; } |
| 667 |
| 668 private: |
| 669 AAStrokeRectBatch(const Geometry& geometry, const SkMatrix& viewMatrix, |
| 670 const GrIndexBuffer* indexBuffer) |
| 671 : fIndexBuffer(indexBuffer) { |
| 672 this->initClassID<AAStrokeRectBatch>(); |
| 673 fBatch.fViewMatrix = viewMatrix; |
| 674 fGeoData.push_back(geometry); |
| 675 } |
| 676 |
| 677 GrColor color() const { return fBatch.fColor; } |
| 678 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } |
| 679 bool canTweakAlphaForCoverage() const { return fBatch.fCanTweakAlphaForCover
age; } |
| 680 bool colorIgnored() const { return fBatch.fColorIgnored; } |
| 681 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; } |
| 682 bool miterStroke() const { return fBatch.fMiterStroke; } |
| 683 |
| 684 bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE { |
| 685 AAStrokeRectBatch* that = t->cast<AAStrokeRectBatch>(); |
| 686 |
| 687 // TODO batch across miterstroke changes |
| 688 if (this->miterStroke() != that->miterStroke()) { |
| 689 return false; |
| 690 } |
| 691 |
| 692 // We apply the viewmatrix to the rect points on the cpu. However, if t
he pipeline uses |
| 693 // local coords then we won't be able to batch. We could actually uploa
d the viewmatrix |
| 694 // using vertex attributes in these cases, but haven't investigated that |
| 695 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->vi
ewMatrix())) { |
| 696 return false; |
| 697 } |
| 698 |
| 699 // In the event of two batches, one who can tweak, one who cannot, we ju
st fall back to |
| 700 // not tweaking |
| 701 if (this->canTweakAlphaForCoverage() != that->canTweakAlphaForCoverage()
) { |
| 702 fBatch.fCanTweakAlphaForCoverage = false; |
| 703 } |
| 704 |
| 705 if (this->color() != that->color()) { |
| 706 fBatch.fColor = GrColor_ILLEGAL; |
| 707 } |
| 708 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin())
; |
| 709 return true; |
| 710 } |
| 711 |
| 712 void generateAAStrokeRectGeometry(void* vertices, |
| 713 size_t offset, |
| 714 size_t vertexStride, |
| 715 int outerVertexNum, |
| 716 int innerVertexNum, |
| 717 GrColor color, |
| 718 const SkRect& devOutside, |
| 719 const SkRect& devOutsideAssist, |
| 720 const SkRect& devInside, |
| 721 bool miterStroke, |
| 722 bool tweakAlphaForCoverage) const { |
| 723 intptr_t verts = reinterpret_cast<intptr_t>(vertices) + offset; |
| 724 |
| 725 // We create vertices for four nested rectangles. There are two ramps fr
om 0 to full |
| 726 // coverage, one on the exterior of the stroke and the other on the inte
rior. |
| 727 // The following pointers refer to the four rects, from outermost to inn
ermost. |
| 728 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts); |
| 729 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * v
ertexStride); |
| 730 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum
* vertexStride); |
| 731 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + |
| 732 (2 * outerVertexNum + inne
rVertexNum) * |
| 733 vertexStride); |
| 734 |
| 735 #ifndef SK_IGNORE_THIN_STROKED_RECT_FIX |
| 736 // TODO: this only really works if the X & Y margins are the same all ar
ound |
| 737 // the rect (or if they are all >= 1.0). |
| 738 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.f
Right); |
| 739 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft); |
| 740 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop); |
| 741 if (miterStroke) { |
| 742 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devI
nside.fBottom); |
| 743 } else { |
| 744 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom
- |
| 745 devInside.fBottom); |
| 746 } |
| 747 SkASSERT(inset >= 0); |
| 748 #else |
| 749 SkScalar inset = SK_ScalarHalf; |
| 750 #endif |
| 751 |
| 752 if (miterStroke) { |
| 753 // outermost |
| 754 set_inset_fan(fan0Pos, vertexStride, devOutside, -SK_ScalarHalf, -SK
_ScalarHalf); |
| 755 // inner two |
| 756 set_inset_fan(fan1Pos, vertexStride, devOutside, inset, inset); |
| 757 set_inset_fan(fan2Pos, vertexStride, devInside, -inset, -inset); |
| 758 // innermost |
| 759 set_inset_fan(fan3Pos, vertexStride, devInside, SK_ScalarHalf, SK
_ScalarHalf); |
| 760 } else { |
| 761 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vert
exStride); |
| 762 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + |
| 763 (outerVertexNum
+ 4) * |
| 764 vertexStride); |
| 765 // outermost |
| 766 set_inset_fan(fan0Pos, vertexStride, devOutside, -SK_ScalarHalf, -SK
_ScalarHalf); |
| 767 set_inset_fan(fan0AssistPos, vertexStride, devOutsideAssist, -SK_Sca
larHalf, |
| 768 -SK_ScalarHalf); |
| 769 // outer one of the inner two |
| 770 set_inset_fan(fan1Pos, vertexStride, devOutside, inset, inset); |
| 771 set_inset_fan(fan1AssistPos, vertexStride, devOutsideAssist, inset,
inset); |
| 772 // inner one of the inner two |
| 773 set_inset_fan(fan2Pos, vertexStride, devInside, -inset, -inset); |
| 774 // innermost |
| 775 set_inset_fan(fan3Pos, vertexStride, devInside, SK_ScalarHalf, SK
_ScalarHalf); |
| 776 } |
| 777 |
| 778 // Make verts point to vertex color and then set all the color and cover
age vertex attrs |
| 779 // values. The outermost rect has 0 coverage |
| 780 verts += sizeof(SkPoint); |
| 781 for (int i = 0; i < outerVertexNum; ++i) { |
| 782 if (tweakAlphaForCoverage) { |
| 783 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0; |
| 784 } else { |
| 785 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color; |
| 786 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrCo
lor)) = 0; |
| 787 } |
| 788 } |
| 789 |
| 790 // scale is the coverage for the the inner two rects. |
| 791 int scale; |
| 792 if (inset < SK_ScalarHalf) { |
| 793 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf))
; |
| 794 SkASSERT(scale >= 0 && scale <= 255); |
| 795 } else { |
| 796 scale = 0xff; |
| 797 } |
| 798 |
| 799 float innerCoverage = GrNormalizeByteToFloat(scale); |
| 800 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale
); |
| 801 |
| 802 verts += outerVertexNum * vertexStride; |
| 803 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) { |
| 804 if (tweakAlphaForCoverage) { |
| 805 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = scaledCo
lor; |
| 806 } else { |
| 807 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color; |
| 808 *reinterpret_cast<float*>(verts + i * vertexStride + sizeof(GrCo
lor)) = |
| 809 innerCoverage; |
| 810 } |
| 811 } |
| 812 |
| 813 // The innermost rect has 0 coverage |
| 814 verts += (outerVertexNum + innerVertexNum) * vertexStride; |
| 815 for (int i = 0; i < innerVertexNum; ++i) { |
| 816 if (tweakAlphaForCoverage) { |
| 817 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = 0; |
| 818 } else { |
| 819 *reinterpret_cast<GrColor*>(verts + i * vertexStride) = color; |
| 820 *reinterpret_cast<GrColor*>(verts + i * vertexStride + sizeof(Gr
Color)) = 0; |
| 821 } |
| 822 } |
| 823 } |
| 824 |
| 825 struct BatchTracker { |
| 826 SkMatrix fViewMatrix; |
| 827 GrColor fColor; |
| 828 bool fUsesLocalCoords; |
| 829 bool fColorIgnored; |
| 830 bool fCoverageIgnored; |
| 831 bool fMiterStroke; |
| 832 bool fCanTweakAlphaForCoverage; |
| 833 }; |
| 834 |
| 835 BatchTracker fBatch; |
| 836 const GrIndexBuffer* fIndexBuffer; |
| 837 SkSTArray<1, Geometry, true> fGeoData; |
| 838 }; |
556 | 839 |
557 | 840 |
558 void GrAARectRenderer::geometryStrokeAARect(GrDrawTarget* target, | 841 void GrAARectRenderer::geometryStrokeAARect(GrDrawTarget* target, |
559 GrPipelineBuilder* pipelineBuilder, | 842 GrPipelineBuilder* pipelineBuilder, |
560 GrColor color, | 843 GrColor color, |
561 const SkMatrix& viewMatrix, | 844 const SkMatrix& viewMatrix, |
562 const SkRect& devOutside, | 845 const SkRect& devOutside, |
563 const SkRect& devOutsideAssist, | 846 const SkRect& devOutsideAssist, |
564 const SkRect& devInside, | 847 const SkRect& devInside, |
565 bool miterStroke) { | 848 bool miterStroke) { |
566 SkMatrix localMatrix; | |
567 if (!viewMatrix.invert(&localMatrix)) { | |
568 SkDebugf("Cannot invert\n"); | |
569 return; | |
570 } | |
571 | |
572 CoverageAttribType type; | |
573 SkAutoTUnref<const GrGeometryProcessor> gp(create_rect_gp(*pipelineBuilder,
color, &type, | |
574 localMatrix)); | |
575 | |
576 int innerVertexNum = 4; | |
577 int outerVertexNum = miterStroke ? 4 : 8; | |
578 int totalVertexNum = (outerVertexNum + innerVertexNum) * 2; | |
579 | |
580 size_t vstride = gp->getVertexStride(); | |
581 GrDrawTarget::AutoReleaseGeometry geo(target, totalVertexNum, vstride, 0); | |
582 if (!geo.succeeded()) { | |
583 SkDebugf("Failed to get space for vertices!\n"); | |
584 return; | |
585 } | |
586 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(miterStroke); | 849 GrIndexBuffer* indexBuffer = this->aaStrokeRectIndexBuffer(miterStroke); |
587 if (NULL == indexBuffer) { | 850 if (NULL == indexBuffer) { |
588 SkDebugf("Failed to create index buffer!\n"); | 851 SkDebugf("Failed to create index buffer!\n"); |
589 return; | 852 return; |
590 } | 853 } |
591 | 854 |
592 intptr_t verts = reinterpret_cast<intptr_t>(geo.vertices()); | 855 AAStrokeRectBatch::Geometry geometry; |
593 | 856 geometry.fColor = color; |
594 // We create vertices for four nested rectangles. There are two ramps from 0
to full | 857 geometry.fDevOutside = devOutside; |
595 // coverage, one on the exterior of the stroke and the other on the interior
. | 858 geometry.fDevOutsideAssist = devOutsideAssist; |
596 // The following pointers refer to the four rects, from outermost to innermo
st. | 859 geometry.fDevInside = devInside; |
597 SkPoint* fan0Pos = reinterpret_cast<SkPoint*>(verts); | 860 geometry.fMiterStroke = miterStroke; |
598 SkPoint* fan1Pos = reinterpret_cast<SkPoint*>(verts + outerVertexNum * vstri
de); | 861 |
599 SkPoint* fan2Pos = reinterpret_cast<SkPoint*>(verts + 2 * outerVertexNum * v
stride); | 862 SkAutoTUnref<GrBatch> batch(AAStrokeRectBatch::Create(geometry, viewMatrix,
indexBuffer)); |
600 SkPoint* fan3Pos = reinterpret_cast<SkPoint*>(verts + (2 * outerVertexNum +
innerVertexNum) * vstride); | 863 target->drawBatch(pipelineBuilder, batch); |
601 | |
602 #ifndef SK_IGNORE_THIN_STROKED_RECT_FIX | |
603 // TODO: this only really works if the X & Y margins are the same all around | |
604 // the rect (or if they are all >= 1.0). | |
605 SkScalar inset = SkMinScalar(SK_Scalar1, devOutside.fRight - devInside.fRigh
t); | |
606 inset = SkMinScalar(inset, devInside.fLeft - devOutside.fLeft); | |
607 inset = SkMinScalar(inset, devInside.fTop - devOutside.fTop); | |
608 if (miterStroke) { | |
609 inset = SK_ScalarHalf * SkMinScalar(inset, devOutside.fBottom - devInsid
e.fBottom); | |
610 } else { | |
611 inset = SK_ScalarHalf * SkMinScalar(inset, devOutsideAssist.fBottom - de
vInside.fBottom); | |
612 } | |
613 SkASSERT(inset >= 0); | |
614 #else | |
615 SkScalar inset = SK_ScalarHalf; | |
616 #endif | |
617 | |
618 if (miterStroke) { | |
619 // outermost | |
620 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHa
lf); | |
621 // inner two | |
622 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset); | |
623 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset); | |
624 // innermost | |
625 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHa
lf); | |
626 } else { | |
627 SkPoint* fan0AssistPos = reinterpret_cast<SkPoint*>(verts + 4 * vstride)
; | |
628 SkPoint* fan1AssistPos = reinterpret_cast<SkPoint*>(verts + (outerVertex
Num + 4) * vstride); | |
629 // outermost | |
630 set_inset_fan(fan0Pos, vstride, devOutside, -SK_ScalarHalf, -SK_ScalarHa
lf); | |
631 set_inset_fan(fan0AssistPos, vstride, devOutsideAssist, -SK_ScalarHalf,
-SK_ScalarHalf); | |
632 // outer one of the inner two | |
633 set_inset_fan(fan1Pos, vstride, devOutside, inset, inset); | |
634 set_inset_fan(fan1AssistPos, vstride, devOutsideAssist, inset, inset); | |
635 // inner one of the inner two | |
636 set_inset_fan(fan2Pos, vstride, devInside, -inset, -inset); | |
637 // innermost | |
638 set_inset_fan(fan3Pos, vstride, devInside, SK_ScalarHalf, SK_ScalarHa
lf); | |
639 } | |
640 | |
641 // Make verts point to vertex color and then set all the color and coverage
vertex attrs values. | |
642 // The outermost rect has 0 coverage | |
643 verts += sizeof(SkPoint); | |
644 for (int i = 0; i < outerVertexNum; ++i) { | |
645 if (kUseCoverage_CoverageAttribType == type) { | |
646 *reinterpret_cast<GrColor*>(verts + i * vstride) = color; | |
647 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = 0
; | |
648 } else { | |
649 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0; | |
650 } | |
651 } | |
652 | |
653 // scale is the coverage for the the inner two rects. | |
654 int scale; | |
655 if (inset < SK_ScalarHalf) { | |
656 scale = SkScalarFloorToInt(512.0f * inset / (inset + SK_ScalarHalf)); | |
657 SkASSERT(scale >= 0 && scale <= 255); | |
658 } else { | |
659 scale = 0xff; | |
660 } | |
661 | |
662 float innerCoverage = GrNormalizeByteToFloat(scale); | |
663 GrColor scaledColor = (0xff == scale) ? color : SkAlphaMulQ(color, scale); | |
664 | |
665 verts += outerVertexNum * vstride; | |
666 for (int i = 0; i < outerVertexNum + innerVertexNum; ++i) { | |
667 if (kUseCoverage_CoverageAttribType == type) { | |
668 *reinterpret_cast<GrColor*>(verts + i * vstride) = color; | |
669 *reinterpret_cast<float*>(verts + i * vstride + sizeof(GrColor)) = i
nnerCoverage; | |
670 } else { | |
671 *reinterpret_cast<GrColor*>(verts + i * vstride) = scaledColor; | |
672 } | |
673 } | |
674 | |
675 // The innermost rect has 0 coverage | |
676 verts += (outerVertexNum + innerVertexNum) * vstride; | |
677 for (int i = 0; i < innerVertexNum; ++i) { | |
678 if (kUseCoverage_CoverageAttribType == type) { | |
679 *reinterpret_cast<GrColor*>(verts + i * vstride) = color; | |
680 *reinterpret_cast<GrColor*>(verts + i * vstride + sizeof(GrColor)) =
0; | |
681 } else { | |
682 *reinterpret_cast<GrColor*>(verts + i * vstride) = 0; | |
683 } | |
684 } | |
685 | |
686 target->setIndexSourceToBuffer(indexBuffer); | |
687 target->drawIndexedInstances(pipelineBuilder, | |
688 gp, | |
689 kTriangles_GrPrimitiveType, | |
690 1, | |
691 totalVertexNum, | |
692 aa_stroke_rect_index_count(miterStroke)); | |
693 target->resetIndexSource(); | |
694 } | 864 } |
695 | 865 |
696 void GrAARectRenderer::fillAANestedRects(GrDrawTarget* target, | 866 void GrAARectRenderer::fillAANestedRects(GrDrawTarget* target, |
697 GrPipelineBuilder* pipelineBuilder, | 867 GrPipelineBuilder* pipelineBuilder, |
698 GrColor color, | 868 GrColor color, |
699 const SkMatrix& viewMatrix, | 869 const SkMatrix& viewMatrix, |
700 const SkRect rects[2]) { | 870 const SkRect rects[2]) { |
701 SkASSERT(viewMatrix.rectStaysRect()); | 871 SkASSERT(viewMatrix.rectStaysRect()); |
702 SkASSERT(!rects[1].isEmpty()); | 872 SkASSERT(!rects[1].isEmpty()); |
703 | 873 |
704 SkRect devOutside, devOutsideAssist, devInside; | 874 SkRect devOutside, devOutsideAssist, devInside; |
705 viewMatrix.mapRect(&devOutside, rects[0]); | 875 viewMatrix.mapRect(&devOutside, rects[0]); |
706 // can't call mapRect for devInside since it calls sort | 876 // can't call mapRect for devInside since it calls sort |
707 viewMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2); | 877 viewMatrix.mapPoints((SkPoint*)&devInside, (const SkPoint*)&rects[1], 2); |
708 | 878 |
709 if (devInside.isEmpty()) { | 879 if (devInside.isEmpty()) { |
710 this->fillAARect(target, pipelineBuilder, color, viewMatrix, devOutside, | 880 this->fillAARect(target, pipelineBuilder, color, viewMatrix, devOutside, |
711 devOutside); | 881 devOutside); |
712 return; | 882 return; |
713 } | 883 } |
714 | 884 |
715 this->geometryStrokeAARect(target, pipelineBuilder, color, viewMatrix, devOu
tside, | 885 this->geometryStrokeAARect(target, pipelineBuilder, color, viewMatrix, devOu
tside, |
716 devOutsideAssist, devInside, true); | 886 devOutsideAssist, devInside, true); |
717 } | 887 } |
OLD | NEW |