| 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 |