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 #include <GrDrawOpTest.h> 10 #include "GrDefaultGeoProcFactory.h" 11 #include "GrMeshDrawOp.h" 12 #include "GrOpFlushState.h" 13 #include "GrResourceProvider.h" 14 #include "GrSimpleMeshDrawOpHelper.h" 15 #include "SkMatrixPriv.h" 16 #include "SkRegion.h" 17 18 static const int kVertsPerInstance = 4; 19 static const int kIndicesPerInstance = 6; 20 21 static sk_sp<GrGeometryProcessor> make_gp(const SkMatrix& viewMatrix) { 22 using namespace GrDefaultGeoProcFactory; 23 return GrDefaultGeoProcFactory::Make(Color::kPremulGrColorAttribute_Type, Coverage::kSolid_Type, 24 LocalCoords::kUsePosition_Type, viewMatrix); 25 } 26 27 static void tesselate_region(intptr_t vertices, 28 size_t vertexStride, 29 GrColor color, 30 const SkRegion& region) { 31 SkRegion::Iterator iter(region); 32 33 intptr_t verts = vertices; 34 while (!iter.done()) { 35 SkRect rect = SkRect::Make(iter.rect()); 36 SkPoint* position = (SkPoint*)verts; 37 position->setRectFan(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, vertexStride); 38 39 static const int kColorOffset = sizeof(SkPoint); 40 GrColor* vertColor = reinterpret_cast<GrColor*>(verts + kColorOffset); 41 for (int i = 0; i < kVertsPerInstance; i++) { 42 *vertColor = color; 43 vertColor = (GrColor*)((intptr_t)vertColor + vertexStride); 44 } 45 46 verts += vertexStride * kVertsPerInstance; 47 iter.next(); 48 } 49 } 50 51 namespace { 52 53 class RegionOp final : public GrMeshDrawOp { 54 private: 55 using Helper = GrSimpleMeshDrawOpHelper; 56 57 public: 58 DEFINE_OP_CLASS_ID 59 60 static std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkMatrix& viewMatrix, 61 const SkRegion& region, GrAAType aaType) { 62 return Helper::FactoryHelper<RegionOp>(std::move(paint), viewMatrix, region, aaType); 63 } 64 65 RegionOp(const Helper::MakeArgs& helperArgs, GrColor color, const SkMatrix& viewMatrix, 66 const SkRegion& region, GrAAType aaType) 67 : INHERITED(ClassID()), fHelper(helperArgs, aaType), fViewMatrix(viewMatrix) { 68 RegionInfo& info = fRegions.push_back(); 69 info.fColor = color; 70 info.fRegion = region; 71 72 SkRect bounds = SkRect::Make(region.getBounds()); 73 this->setTransformedBounds(bounds, viewMatrix, HasAABloat::kNo, IsZeroArea::kNo); 74 } 75 76 const char* name() const override { return "GrRegionOp"; } 77 78 SkString dumpInfo() const override { 79 SkString str; 80 str.appendf("# combined: %d\n", fRegions.count()); 81 for (int i = 0; i < fRegions.count(); ++i) { 82 const RegionInfo& info = fRegions[i]; 83 str.appendf("%d: Color: 0x%08x, Region with %d rects\n", i, info.fColor, 84 info.fRegion.computeRegionComplexity()); 85 } 86 str += fHelper.dumpInfo(); 87 str += INHERITED::dumpInfo(); 88 return str; 89 } 90 91 FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); } 92 93 RequiresDstTexture finalize(const GrCaps& caps, const GrAppliedClip* clip) override { 94 return fHelper.xpRequiresDstTexture(caps, clip, GrProcessorAnalysisCoverage::kNone, 95 &fRegions[0].fColor); 96 } 97 98 private: 99 void onPrepareDraws(Target* target) const override { 100 sk_sp<GrGeometryProcessor> gp = make_gp(fViewMatrix); 101 if (!gp) { 102 SkDebugf("Couldn't create GrGeometryProcessor\n"); 103 return; 104 } 105 SkASSERT(gp->getVertexStride() == sizeof(GrDefaultGeoProcFactory::PositionColorAttr)); 106 107 int numRegions = fRegions.count(); 108 int numRects = 0; 109 for (int i = 0; i < numRegions; i++) { 110 numRects += fRegions[i].fRegion.computeRegionComplexity(); 111 } 112 113 if (!numRects) { 114 return; 115 } 116 size_t vertexStride = gp->getVertexStride(); 117 sk_sp<const GrBuffer> indexBuffer(target->resourceProvider()->refQuadIndexBuffer()); 118 PatternHelper helper(GrPrimitiveType::kTriangles); 119 void* vertices = 120 helper.init(target, vertexStride, indexBuffer.get(), kVertsPerInstance, 121 kIndicesPerInstance, numRects); 122 if (!vertices || !indexBuffer) { 123 SkDebugf("Could not allocate vertices\n"); 124 return; 125 } 126 127 intptr_t verts = reinterpret_cast<intptr_t>(vertices); 128 for (int i = 0; i < numRegions; i++) { 129 tesselate_region(verts, vertexStride, fRegions[i].fColor, fRegions[i].fRegion); 130 int numRectsInRegion = fRegions[i].fRegion.computeRegionComplexity(); 131 verts += numRectsInRegion * kVertsPerInstance * vertexStride; 132 } 133 helper.recordDraw(target, gp.get(), fHelper.makePipeline(target)); 134 } 135 136 bool onCombineIfPossible(GrOp* t, const GrCaps& caps) override { 137 RegionOp* that = t->cast<RegionOp>(); 138 if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) { 139 return false; 140 } 141 142 if (fViewMatrix != that->fViewMatrix) { 143 return false; 144 } 145 146 fRegions.push_back_n(that->fRegions.count(), that->fRegions.begin()); 147 this->joinBounds(*that); 148 return true; 149 } 150 151 struct RegionInfo { 152 GrColor fColor; 153 SkRegion fRegion; 154 }; 155 156 Helper fHelper; 157 SkMatrix fViewMatrix; 158 SkSTArray<1, RegionInfo, true> fRegions; 159 160 typedef GrMeshDrawOp INHERITED; 161 }; 162 163 } // anonymous namespace 164 165 namespace GrRegionOp { 166 167 std::unique_ptr<GrDrawOp> Make(GrPaint&& paint, const SkMatrix& viewMatrix, const SkRegion& region, 168 GrAAType aaType) { 169 if (aaType != GrAAType::kNone && aaType != GrAAType::kMSAA) { 170 return nullptr; 171 } 172 return RegionOp::Make(std::move(paint), viewMatrix, region, aaType); 173 } 174 } 175 176 #if GR_TEST_UTILS 177 178 GR_DRAW_OP_TEST_DEFINE(RegionOp) { 179 SkRegion region; 180 int n = random->nextULessThan(200); 181 for (int i = 0; i < n; ++i) { 182 SkIPoint center; 183 center.fX = random->nextULessThan(1000); 184 center.fY = random->nextULessThan(1000); 185 int w = random->nextRangeU(10, 1000); 186 int h = random->nextRangeU(10, 1000); 187 SkIRect rect = {center.fX - w / 2, center.fY - h / 2, center.fX + w / 2, center.fY + h / 2}; 188 SkRegion::Op op; 189 if (i == 0) { 190 op = SkRegion::kReplace_Op; 191 } else { 192 // Pick an other than replace. 193 GR_STATIC_ASSERT(SkRegion::kLastOp == SkRegion::kReplace_Op); 194 op = (SkRegion::Op)random->nextULessThan(SkRegion::kLastOp); 195 } 196 region.op(rect, op); 197 } 198 SkMatrix viewMatrix = GrTest::TestMatrix(random); 199 GrAAType aaType = GrAAType::kNone; 200 if (GrFSAAType::kUnifiedMSAA == fsaaType && random->nextBool()) { 201 aaType = GrAAType::kMSAA; 202 } 203 return RegionOp::Make(std::move(paint), viewMatrix, region, aaType); 204 } 205 206 #endif 207