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