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