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