1/* 2 * Copyright 2016 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "GrRegionOp.h" 9 10#include "GrDefaultGeoProcFactory.h" 11#include "GrMeshDrawOp.h" 12#include "GrOpFlushState.h" 13#include "GrResourceProvider.h" 14#include "SkMatrixPriv.h" 15#include "SkRegion.h" 16 17static const int kVertsPerInstance = 4; 18static const int kIndicesPerInstance = 6; 19 20static sk_sp<GrGeometryProcessor> make_gp(const SkMatrix& viewMatrix) { 21 using namespace GrDefaultGeoProcFactory; 22 return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type, Coverage::kSolid_Type, 23 LocalCoords::kUsePosition_Type, viewMatrix); 24} 25 26static void tesselate_region(intptr_t vertices, 27 size_t vertexStride, 28 GrColor color, 29 const SkRegion& region) { 30 SkRegion::Iterator iter(region); 31 32 intptr_t verts = vertices; 33 while (!iter.done()) { 34 SkRect rect = SkRect::Make(iter.rect()); 35 SkPoint* position = (SkPoint*)verts; 36 position->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride); 37 38 static const int kColorOffset = sizeof(SkPoint); 39 GrColor* vertColor = reinterpret_cast<GrColor*>(verts + kColorOffset); 40 for (int i = 0; i < kVertsPerInstance; i++) { 41 *vertColor = color; 42 vertColor = (GrColor*)((intptr_t)vertColor + vertexStride); 43 } 44 45 verts += vertexStride * kVertsPerInstance; 46 iter.next(); 47 } 48} 49 50class RegionOp final : public GrMeshDrawOp { 51public: 52 DEFINE_OP_CLASS_ID 53 54 RegionOp(GrColor color, const SkMatrix& viewMatrix, const SkRegion& region) 55 : INHERITED(ClassID()), fViewMatrix(viewMatrix) { 56 RegionInfo& info = fRegions.push_back(); 57 info.fColor = color; 58 info.fRegion = region; 59 60 SkRect bounds = SkRect::Make(region.getBounds()); 61 this->setTransformedBounds(bounds, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo); 62 } 63 64 const char* name() const override { return "GrRegionOp"; } 65 66 SkString dumpInfo() const override { 67 SkString str; 68 str.appendf("# combined: %d\n", fRegions.count()); 69 for (int i = 0; i < fRegions.count(); ++i) { 70 const RegionInfo& info = fRegions[i]; 71 str.appendf("%d: Color: 0x%08x, Region with %d rects\n", i, info.fColor, 72 info.fRegion.computeRegionComplexity()); 73 } 74 str.append(DumpPipelineInfo(*this->pipeline())); 75 str.append(INHERITED::dumpInfo()); 76 return str; 77 } 78 79private: 80 void getFragmentProcessorAnalysisInputs(GrPipelineAnalysisColor* color, 81 GrPipelineAnalysisCoverage* coverage) const override { 82 color->setToConstant(fRegions[0].fColor); 83 *coverage = GrPipelineAnalysisCoverage::kNone; 84 } 85 86 void applyPipelineOptimizations(const GrPipelineOptimizations& optimizations) override { 87 optimizations.getOverrideColorIfSet(&fRegions[0].fColor); 88 } 89 90 void onPrepareDraws(Target* target) const override { 91 sk_sp<GrGeometryProcessor> gp = make_gp(fViewMatrix); 92 if (!gp) { 93 SkDebugf("Couldn't create GrGeometryProcessor\n"); 94 return; 95 } 96 SkASSERT(gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::PositionColorAttr)); 97 98 int numRegions = fRegions.count(); 99 int numRects = 0; 100 for (int i = 0; i < numRegions; i++) { 101 numRects += fRegions[i].fRegion.computeRegionComplexity(); 102 } 103 104 size_t vertexStride = gp->getVertexStride(); 105 sk_sp<const GrBuffer> indexBuffer(target->resourceProvider()->refQuadIndexBuffer()); 106 InstancedHelper helper; 107 void* vertices = 108 helper.init(target, kTriangles_GrPrimitiveType, vertexStride, indexBuffer.get(), 109 kVertsPerInstance, kIndicesPerInstance, numRects); 110 if (!vertices || !indexBuffer) { 111 SkDebugf("Could not allocate vertices\n"); 112 return; 113 } 114 115 intptr_t verts = reinterpret_cast<intptr_t>(vertices); 116 for (int i = 0; i < numRegions; i++) { 117 tesselate_region(verts, vertexStride, fRegions[i].fColor, fRegions[i].fRegion); 118 int numRectsInRegion = fRegions[i].fRegion.computeRegionComplexity(); 119 verts += numRectsInRegion * kVertsPerInstance * vertexStride; 120 } 121 helper.recordDraw(target, gp.get()); 122 } 123 124 bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { 125 RegionOp* that = t->cast<RegionOp>(); 126 if (!GrPipeline::CanCombine(*this->pipeline(), this->bounds(), *that->pipeline(), 127 that->bounds(), caps)) { 128 return false; 129 } 130 131 if (fViewMatrix != that->fViewMatrix) { 132 return false; 133 } 134 135 fRegions.push_back_n(that->fRegions.count(), that->fRegions.begin()); 136 this->joinBounds(*that); 137 return true; 138 } 139 140 struct RegionInfo { 141 GrColor fColor; 142 SkRegion fRegion; 143 }; 144 145 SkMatrix fViewMatrix; 146 SkSTArray<1, RegionInfo, true> fRegions; 147 148 typedef GrMeshDrawOp INHERITED; 149}; 150 151namespace GrRegionOp { 152 153std::unique_ptr<GrMeshDrawOp> Make(GrColor color, const SkMatrix& viewMatrix, 154 const SkRegion& region) { 155 return std::unique_ptr<GrMeshDrawOp>(new RegionOp(color, viewMatrix, region)); 156} 157} 158