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