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