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