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