xref: /aosp_15_r20/external/skia/src/gpu/ganesh/ops/SmallPathRenderer.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2014 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2017 ARM Ltd.
4*c8dee2aaSAndroid Build Coastguard Worker  *
5*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
6*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
7*c8dee2aaSAndroid Build Coastguard Worker  */
8*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/SmallPathRenderer.h"
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPixmap.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint3.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSamplingOptions.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrRecordingContext.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/SkColorData.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAssert.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMalloc.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMath.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkPoint_impl.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/gpu/ganesh/GrTypesPriv.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkAutoMalloc.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkAutoPixmapStorage.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkDistanceFieldGen.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkDraw.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMatrixPriv.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkRasterClip.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/AtlasTypes.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/BufferWriter.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrAppliedClip.h"
39*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrAuditTrail.h"
40*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrBuffer.h"
41*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrCaps.h"
42*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrColorSpaceXform.h"
43*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrDeferredUpload.h"
44*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrDistanceFieldGenFromVector.h"
45*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrDrawOpAtlas.h"
46*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrDrawOpTest.h"
47*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrGeometryProcessor.h"
48*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrMeshDrawTarget.h"
49*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrOpFlushState.h"
50*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrPaint.h"
51*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProcessorAnalysis.h"
52*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProcessorSet.h"
53*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrRecordingContextPriv.h"
54*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrResourceProvider.h"
55*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSamplerState.h"
56*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrShaderCaps.h"
57*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSimpleMesh.h"
58*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrStyle.h"
59*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSurfaceProxyView.h"
60*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/SurfaceDrawContext.h"
61*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/effects/GrBitmapTextGeoProc.h"
62*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/effects/GrDistanceFieldGeoProc.h"
63*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/geometry/GrStyledShape.h"
64*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrMeshDrawOp.h"
65*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrOp.h"
66*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrSimpleMeshDrawOpHelperWithStencil.h"
67*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/SmallPathAtlasMgr.h"
68*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/SmallPathShapeData.h"
69*c8dee2aaSAndroid Build Coastguard Worker 
70*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
71*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h"
72*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrTestUtils.h"
73*c8dee2aaSAndroid Build Coastguard Worker #endif
74*c8dee2aaSAndroid Build Coastguard Worker 
75*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
76*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
77*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
78*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
79*c8dee2aaSAndroid Build Coastguard Worker 
80*c8dee2aaSAndroid Build Coastguard Worker class GrDstProxyView;
81*c8dee2aaSAndroid Build Coastguard Worker class GrProgramInfo;
82*c8dee2aaSAndroid Build Coastguard Worker class GrSurfaceProxy;
83*c8dee2aaSAndroid Build Coastguard Worker class SkArenaAlloc;
84*c8dee2aaSAndroid Build Coastguard Worker enum class GrXferBarrierFlags;
85*c8dee2aaSAndroid Build Coastguard Worker struct GrUserStencilSettings;
86*c8dee2aaSAndroid Build Coastguard Worker 
87*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
88*c8dee2aaSAndroid Build Coastguard Worker 
89*c8dee2aaSAndroid Build Coastguard Worker #if !defined(SK_ENABLE_OPTIMIZE_SIZE)
90*c8dee2aaSAndroid Build Coastguard Worker 
91*c8dee2aaSAndroid Build Coastguard Worker using MaskFormat = skgpu::MaskFormat;
92*c8dee2aaSAndroid Build Coastguard Worker 
93*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::ganesh {
94*c8dee2aaSAndroid Build Coastguard Worker 
95*c8dee2aaSAndroid Build Coastguard Worker namespace {
96*c8dee2aaSAndroid Build Coastguard Worker 
97*c8dee2aaSAndroid Build Coastguard Worker // mip levels
98*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kIdealMinMIP = 12;
99*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kMaxMIP = 162;
100*c8dee2aaSAndroid Build Coastguard Worker 
101*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kMaxDim = 73;
102*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kMinSize = SK_ScalarHalf;
103*c8dee2aaSAndroid Build Coastguard Worker static constexpr SkScalar kMaxSize = 2*kMaxMIP;
104*c8dee2aaSAndroid Build Coastguard Worker 
105*c8dee2aaSAndroid Build Coastguard Worker ////////////////////////////////////////////////////////////////////////////////
106*c8dee2aaSAndroid Build Coastguard Worker 
107*c8dee2aaSAndroid Build Coastguard Worker // padding around path bounds to allow for antialiased pixels
108*c8dee2aaSAndroid Build Coastguard Worker static const int kAntiAliasPad = 1;
109*c8dee2aaSAndroid Build Coastguard Worker 
110*c8dee2aaSAndroid Build Coastguard Worker class SmallPathOp final : public GrMeshDrawOp {
111*c8dee2aaSAndroid Build Coastguard Worker private:
112*c8dee2aaSAndroid Build Coastguard Worker     using Helper = GrSimpleMeshDrawOpHelperWithStencil;
113*c8dee2aaSAndroid Build Coastguard Worker 
114*c8dee2aaSAndroid Build Coastguard Worker public:
115*c8dee2aaSAndroid Build Coastguard Worker     DEFINE_OP_CLASS_ID
116*c8dee2aaSAndroid Build Coastguard Worker 
Make(GrRecordingContext * context,GrPaint && paint,const GrStyledShape & shape,const SkMatrix & viewMatrix,bool gammaCorrect,const GrUserStencilSettings * stencilSettings)117*c8dee2aaSAndroid Build Coastguard Worker     static GrOp::Owner Make(GrRecordingContext* context,
118*c8dee2aaSAndroid Build Coastguard Worker                             GrPaint&& paint,
119*c8dee2aaSAndroid Build Coastguard Worker                             const GrStyledShape& shape,
120*c8dee2aaSAndroid Build Coastguard Worker                             const SkMatrix& viewMatrix,
121*c8dee2aaSAndroid Build Coastguard Worker                             bool gammaCorrect,
122*c8dee2aaSAndroid Build Coastguard Worker                             const GrUserStencilSettings* stencilSettings) {
123*c8dee2aaSAndroid Build Coastguard Worker         return Helper::FactoryHelper<SmallPathOp>(context, std::move(paint), shape, viewMatrix,
124*c8dee2aaSAndroid Build Coastguard Worker                                                   gammaCorrect, stencilSettings);
125*c8dee2aaSAndroid Build Coastguard Worker     }
126*c8dee2aaSAndroid Build Coastguard Worker 
SmallPathOp(GrProcessorSet * processorSet,const SkPMColor4f & color,const GrStyledShape & shape,const SkMatrix & viewMatrix,bool gammaCorrect,const GrUserStencilSettings * stencilSettings)127*c8dee2aaSAndroid Build Coastguard Worker     SmallPathOp(GrProcessorSet* processorSet, const SkPMColor4f& color, const GrStyledShape& shape,
128*c8dee2aaSAndroid Build Coastguard Worker                 const SkMatrix& viewMatrix, bool gammaCorrect,
129*c8dee2aaSAndroid Build Coastguard Worker                 const GrUserStencilSettings* stencilSettings)
130*c8dee2aaSAndroid Build Coastguard Worker             : INHERITED(ClassID())
131*c8dee2aaSAndroid Build Coastguard Worker             , fHelper(processorSet, GrAAType::kCoverage, stencilSettings) {
132*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(shape.hasUnstyledKey());
133*c8dee2aaSAndroid Build Coastguard Worker         // Compute bounds
134*c8dee2aaSAndroid Build Coastguard Worker         this->setTransformedBounds(shape.bounds(), viewMatrix, HasAABloat::kYes, IsHairline::kNo);
135*c8dee2aaSAndroid Build Coastguard Worker 
136*c8dee2aaSAndroid Build Coastguard Worker #if defined(SK_BUILD_FOR_ANDROID) && !defined(SK_BUILD_FOR_ANDROID_FRAMEWORK)
137*c8dee2aaSAndroid Build Coastguard Worker         fUsesDistanceField = true;
138*c8dee2aaSAndroid Build Coastguard Worker #else
139*c8dee2aaSAndroid Build Coastguard Worker         // only use distance fields on desktop and Android framework to save space in the atlas
140*c8dee2aaSAndroid Build Coastguard Worker         fUsesDistanceField = this->bounds().width() > kMaxMIP || this->bounds().height() > kMaxMIP;
141*c8dee2aaSAndroid Build Coastguard Worker #endif
142*c8dee2aaSAndroid Build Coastguard Worker         // always use distance fields if in perspective
143*c8dee2aaSAndroid Build Coastguard Worker         fUsesDistanceField = fUsesDistanceField || viewMatrix.hasPerspective();
144*c8dee2aaSAndroid Build Coastguard Worker 
145*c8dee2aaSAndroid Build Coastguard Worker         fShapes.emplace_back(Entry{color, shape, viewMatrix});
146*c8dee2aaSAndroid Build Coastguard Worker 
147*c8dee2aaSAndroid Build Coastguard Worker         fGammaCorrect = gammaCorrect;
148*c8dee2aaSAndroid Build Coastguard Worker     }
149*c8dee2aaSAndroid Build Coastguard Worker 
name() const150*c8dee2aaSAndroid Build Coastguard Worker     const char* name() const override { return "SmallPathOp"; }
151*c8dee2aaSAndroid Build Coastguard Worker 
visitProxies(const GrVisitProxyFunc & func) const152*c8dee2aaSAndroid Build Coastguard Worker     void visitProxies(const GrVisitProxyFunc& func) const override {
153*c8dee2aaSAndroid Build Coastguard Worker         fHelper.visitProxies(func);
154*c8dee2aaSAndroid Build Coastguard Worker     }
155*c8dee2aaSAndroid Build Coastguard Worker 
fixedFunctionFlags() const156*c8dee2aaSAndroid Build Coastguard Worker     FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
157*c8dee2aaSAndroid Build Coastguard Worker 
finalize(const GrCaps & caps,const GrAppliedClip * clip,GrClampType clampType)158*c8dee2aaSAndroid Build Coastguard Worker     GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip,
159*c8dee2aaSAndroid Build Coastguard Worker                                       GrClampType clampType) override {
160*c8dee2aaSAndroid Build Coastguard Worker         return fHelper.finalizeProcessors(caps, clip, clampType,
161*c8dee2aaSAndroid Build Coastguard Worker                                           GrProcessorAnalysisCoverage::kSingleChannel,
162*c8dee2aaSAndroid Build Coastguard Worker                                           &fShapes.front().fColor, &fWideColor);
163*c8dee2aaSAndroid Build Coastguard Worker     }
164*c8dee2aaSAndroid Build Coastguard Worker 
165*c8dee2aaSAndroid Build Coastguard Worker private:
166*c8dee2aaSAndroid Build Coastguard Worker     struct FlushInfo {
167*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<const GrBuffer> fVertexBuffer;
168*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<const GrBuffer> fIndexBuffer;
169*c8dee2aaSAndroid Build Coastguard Worker         GrGeometryProcessor*  fGeometryProcessor;
170*c8dee2aaSAndroid Build Coastguard Worker         const GrSurfaceProxy** fPrimProcProxies;
171*c8dee2aaSAndroid Build Coastguard Worker         int fVertexOffset;
172*c8dee2aaSAndroid Build Coastguard Worker         int fInstancesToFlush;
173*c8dee2aaSAndroid Build Coastguard Worker     };
174*c8dee2aaSAndroid Build Coastguard Worker 
programInfo()175*c8dee2aaSAndroid Build Coastguard Worker     GrProgramInfo* programInfo() override {
176*c8dee2aaSAndroid Build Coastguard Worker         // TODO [PI]: implement
177*c8dee2aaSAndroid Build Coastguard Worker         return nullptr;
178*c8dee2aaSAndroid Build Coastguard Worker     }
179*c8dee2aaSAndroid Build Coastguard Worker 
onCreateProgramInfo(const GrCaps *,SkArenaAlloc *,const GrSurfaceProxyView & writeView,bool usesMSAASurface,GrAppliedClip &&,const GrDstProxyView &,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)180*c8dee2aaSAndroid Build Coastguard Worker     void onCreateProgramInfo(const GrCaps*,
181*c8dee2aaSAndroid Build Coastguard Worker                              SkArenaAlloc*,
182*c8dee2aaSAndroid Build Coastguard Worker                              const GrSurfaceProxyView& writeView,
183*c8dee2aaSAndroid Build Coastguard Worker                              bool usesMSAASurface,
184*c8dee2aaSAndroid Build Coastguard Worker                              GrAppliedClip&&,
185*c8dee2aaSAndroid Build Coastguard Worker                              const GrDstProxyView&,
186*c8dee2aaSAndroid Build Coastguard Worker                              GrXferBarrierFlags renderPassXferBarriers,
187*c8dee2aaSAndroid Build Coastguard Worker                              GrLoadOp colorLoadOp) override {
188*c8dee2aaSAndroid Build Coastguard Worker         // We cannot surface the SmallPathOp's programInfo at record time. As currently
189*c8dee2aaSAndroid Build Coastguard Worker         // implemented, the GP is modified at flush time based on the number of pages in the
190*c8dee2aaSAndroid Build Coastguard Worker         // atlas.
191*c8dee2aaSAndroid Build Coastguard Worker     }
192*c8dee2aaSAndroid Build Coastguard Worker 
onPrePrepareDraws(GrRecordingContext *,const GrSurfaceProxyView & writeView,GrAppliedClip *,const GrDstProxyView &,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)193*c8dee2aaSAndroid Build Coastguard Worker     void onPrePrepareDraws(GrRecordingContext*,
194*c8dee2aaSAndroid Build Coastguard Worker                            const GrSurfaceProxyView& writeView,
195*c8dee2aaSAndroid Build Coastguard Worker                            GrAppliedClip*,
196*c8dee2aaSAndroid Build Coastguard Worker                            const GrDstProxyView&,
197*c8dee2aaSAndroid Build Coastguard Worker                            GrXferBarrierFlags renderPassXferBarriers,
198*c8dee2aaSAndroid Build Coastguard Worker                            GrLoadOp colorLoadOp) override {
199*c8dee2aaSAndroid Build Coastguard Worker         // TODO [PI]: implement
200*c8dee2aaSAndroid Build Coastguard Worker     }
201*c8dee2aaSAndroid Build Coastguard Worker 
onPrepareDraws(GrMeshDrawTarget * target)202*c8dee2aaSAndroid Build Coastguard Worker     void onPrepareDraws(GrMeshDrawTarget* target) override {
203*c8dee2aaSAndroid Build Coastguard Worker         int instanceCount = fShapes.size();
204*c8dee2aaSAndroid Build Coastguard Worker 
205*c8dee2aaSAndroid Build Coastguard Worker         auto atlasMgr = target->smallPathAtlasManager();
206*c8dee2aaSAndroid Build Coastguard Worker         if (!atlasMgr) {
207*c8dee2aaSAndroid Build Coastguard Worker             return;
208*c8dee2aaSAndroid Build Coastguard Worker         }
209*c8dee2aaSAndroid Build Coastguard Worker 
210*c8dee2aaSAndroid Build Coastguard Worker         static constexpr int kMaxTextures = GrDistanceFieldPathGeoProc::kMaxTextures;
211*c8dee2aaSAndroid Build Coastguard Worker         static_assert(GrBitmapTextGeoProc::kMaxTextures == kMaxTextures);
212*c8dee2aaSAndroid Build Coastguard Worker 
213*c8dee2aaSAndroid Build Coastguard Worker         FlushInfo flushInfo;
214*c8dee2aaSAndroid Build Coastguard Worker         flushInfo.fPrimProcProxies = target->allocPrimProcProxyPtrs(kMaxTextures);
215*c8dee2aaSAndroid Build Coastguard Worker 
216*c8dee2aaSAndroid Build Coastguard Worker         int numActiveProxies;
217*c8dee2aaSAndroid Build Coastguard Worker         const GrSurfaceProxyView* views = atlasMgr->getViews(&numActiveProxies);
218*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < numActiveProxies; ++i) {
219*c8dee2aaSAndroid Build Coastguard Worker             // This op does not know its atlas proxies when it is added to a OpsTasks, so the
220*c8dee2aaSAndroid Build Coastguard Worker             // proxies don't get added during the visitProxies call. Thus we add them here.
221*c8dee2aaSAndroid Build Coastguard Worker             flushInfo.fPrimProcProxies[i] = views[i].proxy();
222*c8dee2aaSAndroid Build Coastguard Worker             target->sampledProxyArray()->push_back(views[i].proxy());
223*c8dee2aaSAndroid Build Coastguard Worker         }
224*c8dee2aaSAndroid Build Coastguard Worker 
225*c8dee2aaSAndroid Build Coastguard Worker         // Setup GrGeometryProcessor
226*c8dee2aaSAndroid Build Coastguard Worker         const SkMatrix& ctm = fShapes[0].fViewMatrix;
227*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix invert;
228*c8dee2aaSAndroid Build Coastguard Worker         if (fHelper.usesLocalCoords()) {
229*c8dee2aaSAndroid Build Coastguard Worker             if (!ctm.invert(&invert)) {
230*c8dee2aaSAndroid Build Coastguard Worker                 return;
231*c8dee2aaSAndroid Build Coastguard Worker             }
232*c8dee2aaSAndroid Build Coastguard Worker         }
233*c8dee2aaSAndroid Build Coastguard Worker         if (fUsesDistanceField) {
234*c8dee2aaSAndroid Build Coastguard Worker             uint32_t flags = 0;
235*c8dee2aaSAndroid Build Coastguard Worker             // Still need to key off of ctm to pick the right shader for the transformed quad
236*c8dee2aaSAndroid Build Coastguard Worker             flags |= ctm.isScaleTranslate() ? kScaleOnly_DistanceFieldEffectFlag : 0;
237*c8dee2aaSAndroid Build Coastguard Worker             flags |= ctm.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
238*c8dee2aaSAndroid Build Coastguard Worker             flags |= fGammaCorrect ? kGammaCorrect_DistanceFieldEffectFlag : 0;
239*c8dee2aaSAndroid Build Coastguard Worker             flags |= fWideColor ? kWideColor_DistanceFieldEffectFlag : 0;
240*c8dee2aaSAndroid Build Coastguard Worker             // We always use Point3 for position
241*c8dee2aaSAndroid Build Coastguard Worker             flags |= kPerspective_DistanceFieldEffectFlag;
242*c8dee2aaSAndroid Build Coastguard Worker 
243*c8dee2aaSAndroid Build Coastguard Worker             flushInfo.fGeometryProcessor = GrDistanceFieldPathGeoProc::Make(
244*c8dee2aaSAndroid Build Coastguard Worker                     target->allocator(), *target->caps().shaderCaps(),
245*c8dee2aaSAndroid Build Coastguard Worker                     views, numActiveProxies, GrSamplerState::Filter::kLinear,
246*c8dee2aaSAndroid Build Coastguard Worker                     invert, flags);
247*c8dee2aaSAndroid Build Coastguard Worker         } else {
248*c8dee2aaSAndroid Build Coastguard Worker             flushInfo.fGeometryProcessor = GrBitmapTextGeoProc::Make(
249*c8dee2aaSAndroid Build Coastguard Worker                     target->allocator(), *target->caps().shaderCaps(), this->color(), fWideColor,
250*c8dee2aaSAndroid Build Coastguard Worker                     /*colorSpaceXform=*/nullptr, views, numActiveProxies,
251*c8dee2aaSAndroid Build Coastguard Worker                     GrSamplerState::Filter::kNearest, MaskFormat::kA8, invert, false);
252*c8dee2aaSAndroid Build Coastguard Worker         }
253*c8dee2aaSAndroid Build Coastguard Worker 
254*c8dee2aaSAndroid Build Coastguard Worker         // allocate vertices
255*c8dee2aaSAndroid Build Coastguard Worker         const size_t kVertexStride = flushInfo.fGeometryProcessor->vertexStride();
256*c8dee2aaSAndroid Build Coastguard Worker 
257*c8dee2aaSAndroid Build Coastguard Worker         // We need to make sure we don't overflow a 32 bit int when we request space in the
258*c8dee2aaSAndroid Build Coastguard Worker         // makeVertexSpace call below.
259*c8dee2aaSAndroid Build Coastguard Worker         if (instanceCount > SK_MaxS32 / GrResourceProvider::NumVertsPerNonAAQuad()) {
260*c8dee2aaSAndroid Build Coastguard Worker             return;
261*c8dee2aaSAndroid Build Coastguard Worker         }
262*c8dee2aaSAndroid Build Coastguard Worker         VertexWriter vertices = target->makeVertexWriter(
263*c8dee2aaSAndroid Build Coastguard Worker             kVertexStride, GrResourceProvider::NumVertsPerNonAAQuad() * instanceCount,
264*c8dee2aaSAndroid Build Coastguard Worker             &flushInfo.fVertexBuffer, &flushInfo.fVertexOffset);
265*c8dee2aaSAndroid Build Coastguard Worker 
266*c8dee2aaSAndroid Build Coastguard Worker         flushInfo.fIndexBuffer = target->resourceProvider()->refNonAAQuadIndexBuffer();
267*c8dee2aaSAndroid Build Coastguard Worker         if (!vertices || !flushInfo.fIndexBuffer) {
268*c8dee2aaSAndroid Build Coastguard Worker             SkDebugf("Could not allocate vertices\n");
269*c8dee2aaSAndroid Build Coastguard Worker             return;
270*c8dee2aaSAndroid Build Coastguard Worker         }
271*c8dee2aaSAndroid Build Coastguard Worker 
272*c8dee2aaSAndroid Build Coastguard Worker         flushInfo.fInstancesToFlush = 0;
273*c8dee2aaSAndroid Build Coastguard Worker         for (int i = 0; i < instanceCount; i++) {
274*c8dee2aaSAndroid Build Coastguard Worker             const Entry& args = fShapes[i];
275*c8dee2aaSAndroid Build Coastguard Worker 
276*c8dee2aaSAndroid Build Coastguard Worker             skgpu::ganesh::SmallPathShapeData* shapeData;
277*c8dee2aaSAndroid Build Coastguard Worker             if (fUsesDistanceField) {
278*c8dee2aaSAndroid Build Coastguard Worker                 // get mip level
279*c8dee2aaSAndroid Build Coastguard Worker                 SkScalar maxScale;
280*c8dee2aaSAndroid Build Coastguard Worker                 const SkRect& bounds = args.fShape.bounds();
281*c8dee2aaSAndroid Build Coastguard Worker                 if (args.fViewMatrix.hasPerspective()) {
282*c8dee2aaSAndroid Build Coastguard Worker                     // approximate the scale since we can't get it from the matrix
283*c8dee2aaSAndroid Build Coastguard Worker                     SkRect xformedBounds;
284*c8dee2aaSAndroid Build Coastguard Worker                     args.fViewMatrix.mapRect(&xformedBounds, bounds);
285*c8dee2aaSAndroid Build Coastguard Worker                     maxScale = SkScalarAbs(std::max(xformedBounds.width() / bounds.width(),
286*c8dee2aaSAndroid Build Coastguard Worker                                                   xformedBounds.height() / bounds.height()));
287*c8dee2aaSAndroid Build Coastguard Worker                 } else {
288*c8dee2aaSAndroid Build Coastguard Worker                     maxScale = SkScalarAbs(args.fViewMatrix.getMaxScale());
289*c8dee2aaSAndroid Build Coastguard Worker                 }
290*c8dee2aaSAndroid Build Coastguard Worker                 SkScalar maxDim = std::max(bounds.width(), bounds.height());
291*c8dee2aaSAndroid Build Coastguard Worker                 // We try to create the DF at a 2^n scaled path resolution (1/2, 1, 2, 4, etc.)
292*c8dee2aaSAndroid Build Coastguard Worker                 // In the majority of cases this will yield a crisper rendering.
293*c8dee2aaSAndroid Build Coastguard Worker                 SkScalar mipScale = 1.0f;
294*c8dee2aaSAndroid Build Coastguard Worker                 // Our mipscale is the maxScale clamped to the next highest power of 2
295*c8dee2aaSAndroid Build Coastguard Worker                 if (maxScale <= SK_ScalarHalf) {
296*c8dee2aaSAndroid Build Coastguard Worker                     SkScalar log = SkScalarFloorToScalar(SkScalarLog2(SkScalarInvert(maxScale)));
297*c8dee2aaSAndroid Build Coastguard Worker                     mipScale = SkScalarPow(2, -log);
298*c8dee2aaSAndroid Build Coastguard Worker                 } else if (maxScale > SK_Scalar1) {
299*c8dee2aaSAndroid Build Coastguard Worker                     SkScalar log = SkScalarCeilToScalar(SkScalarLog2(maxScale));
300*c8dee2aaSAndroid Build Coastguard Worker                     mipScale = SkScalarPow(2, log);
301*c8dee2aaSAndroid Build Coastguard Worker                 }
302*c8dee2aaSAndroid Build Coastguard Worker                 // Log2 isn't very precise at values close to a power of 2,
303*c8dee2aaSAndroid Build Coastguard Worker                 // so add a little tolerance here. A little bit of scaling up is fine.
304*c8dee2aaSAndroid Build Coastguard Worker                 SkASSERT(maxScale <= mipScale + SK_ScalarNearlyZero);
305*c8dee2aaSAndroid Build Coastguard Worker 
306*c8dee2aaSAndroid Build Coastguard Worker                 SkScalar mipSize = mipScale*SkScalarAbs(maxDim);
307*c8dee2aaSAndroid Build Coastguard Worker                 // For sizes less than kIdealMinMIP we want to use as large a distance field as we can
308*c8dee2aaSAndroid Build Coastguard Worker                 // so we can preserve as much detail as possible. However, we can't scale down more
309*c8dee2aaSAndroid Build Coastguard Worker                 // than a 1/4 of the size without artifacts. So the idea is that we pick the mipsize
310*c8dee2aaSAndroid Build Coastguard Worker                 // just bigger than the ideal, and then scale down until we are no more than 4x the
311*c8dee2aaSAndroid Build Coastguard Worker                 // original mipsize.
312*c8dee2aaSAndroid Build Coastguard Worker                 if (mipSize < kIdealMinMIP) {
313*c8dee2aaSAndroid Build Coastguard Worker                     SkScalar newMipSize = mipSize;
314*c8dee2aaSAndroid Build Coastguard Worker                     do {
315*c8dee2aaSAndroid Build Coastguard Worker                         newMipSize *= 2;
316*c8dee2aaSAndroid Build Coastguard Worker                     } while (newMipSize < kIdealMinMIP);
317*c8dee2aaSAndroid Build Coastguard Worker                     while (newMipSize > 4 * mipSize) {
318*c8dee2aaSAndroid Build Coastguard Worker                         newMipSize *= 0.25f;
319*c8dee2aaSAndroid Build Coastguard Worker                     }
320*c8dee2aaSAndroid Build Coastguard Worker                     mipSize = newMipSize;
321*c8dee2aaSAndroid Build Coastguard Worker                 }
322*c8dee2aaSAndroid Build Coastguard Worker 
323*c8dee2aaSAndroid Build Coastguard Worker                 SkScalar desiredDimension = std::min(mipSize, kMaxMIP);
324*c8dee2aaSAndroid Build Coastguard Worker                 int ceilDesiredDimension = SkScalarCeilToInt(desiredDimension);
325*c8dee2aaSAndroid Build Coastguard Worker 
326*c8dee2aaSAndroid Build Coastguard Worker                 // check to see if df path is cached
327*c8dee2aaSAndroid Build Coastguard Worker                 shapeData = atlasMgr->findOrCreate(args.fShape, ceilDesiredDimension);
328*c8dee2aaSAndroid Build Coastguard Worker                 if (!shapeData->fAtlasLocator.plotLocator().isValid()) {
329*c8dee2aaSAndroid Build Coastguard Worker                     SkScalar scale = desiredDimension / maxDim;
330*c8dee2aaSAndroid Build Coastguard Worker 
331*c8dee2aaSAndroid Build Coastguard Worker                     if (!this->addDFPathToAtlas(target,
332*c8dee2aaSAndroid Build Coastguard Worker                                                 &flushInfo,
333*c8dee2aaSAndroid Build Coastguard Worker                                                 atlasMgr,
334*c8dee2aaSAndroid Build Coastguard Worker                                                 shapeData,
335*c8dee2aaSAndroid Build Coastguard Worker                                                 args.fShape,
336*c8dee2aaSAndroid Build Coastguard Worker                                                 ceilDesiredDimension,
337*c8dee2aaSAndroid Build Coastguard Worker                                                 scale)) {
338*c8dee2aaSAndroid Build Coastguard Worker                         atlasMgr->deleteCacheEntry(shapeData);
339*c8dee2aaSAndroid Build Coastguard Worker                         continue;
340*c8dee2aaSAndroid Build Coastguard Worker                     }
341*c8dee2aaSAndroid Build Coastguard Worker                 }
342*c8dee2aaSAndroid Build Coastguard Worker             } else {
343*c8dee2aaSAndroid Build Coastguard Worker                 // check to see if bitmap path is cached
344*c8dee2aaSAndroid Build Coastguard Worker                 shapeData = atlasMgr->findOrCreate(args.fShape, args.fViewMatrix);
345*c8dee2aaSAndroid Build Coastguard Worker                 if (!shapeData->fAtlasLocator.plotLocator().isValid()) {
346*c8dee2aaSAndroid Build Coastguard Worker                     if (!this->addBMPathToAtlas(target,
347*c8dee2aaSAndroid Build Coastguard Worker                                                 &flushInfo,
348*c8dee2aaSAndroid Build Coastguard Worker                                                 atlasMgr,
349*c8dee2aaSAndroid Build Coastguard Worker                                                 shapeData,
350*c8dee2aaSAndroid Build Coastguard Worker                                                 args.fShape,
351*c8dee2aaSAndroid Build Coastguard Worker                                                 args.fViewMatrix)) {
352*c8dee2aaSAndroid Build Coastguard Worker                         atlasMgr->deleteCacheEntry(shapeData);
353*c8dee2aaSAndroid Build Coastguard Worker                         continue;
354*c8dee2aaSAndroid Build Coastguard Worker                     }
355*c8dee2aaSAndroid Build Coastguard Worker                 }
356*c8dee2aaSAndroid Build Coastguard Worker             }
357*c8dee2aaSAndroid Build Coastguard Worker 
358*c8dee2aaSAndroid Build Coastguard Worker             auto uploadTarget = target->deferredUploadTarget();
359*c8dee2aaSAndroid Build Coastguard Worker             atlasMgr->setUseToken(shapeData, uploadTarget->tokenTracker()->nextDrawToken());
360*c8dee2aaSAndroid Build Coastguard Worker 
361*c8dee2aaSAndroid Build Coastguard Worker             this->writePathVertices(vertices, VertexColor(args.fColor, fWideColor),
362*c8dee2aaSAndroid Build Coastguard Worker                                     args.fViewMatrix, shapeData);
363*c8dee2aaSAndroid Build Coastguard Worker             flushInfo.fInstancesToFlush++;
364*c8dee2aaSAndroid Build Coastguard Worker         }
365*c8dee2aaSAndroid Build Coastguard Worker 
366*c8dee2aaSAndroid Build Coastguard Worker         this->flush(target, &flushInfo);
367*c8dee2aaSAndroid Build Coastguard Worker     }
368*c8dee2aaSAndroid Build Coastguard Worker 
addToAtlasWithRetry(GrMeshDrawTarget * target,FlushInfo * flushInfo,skgpu::ganesh::SmallPathAtlasMgr * atlasMgr,int width,int height,const void * image,const SkRect & bounds,int srcInset,skgpu::ganesh::SmallPathShapeData * shapeData) const369*c8dee2aaSAndroid Build Coastguard Worker     bool addToAtlasWithRetry(GrMeshDrawTarget* target,
370*c8dee2aaSAndroid Build Coastguard Worker                              FlushInfo* flushInfo,
371*c8dee2aaSAndroid Build Coastguard Worker                              skgpu::ganesh::SmallPathAtlasMgr* atlasMgr,
372*c8dee2aaSAndroid Build Coastguard Worker                              int width,
373*c8dee2aaSAndroid Build Coastguard Worker                              int height,
374*c8dee2aaSAndroid Build Coastguard Worker                              const void* image,
375*c8dee2aaSAndroid Build Coastguard Worker                              const SkRect& bounds,
376*c8dee2aaSAndroid Build Coastguard Worker                              int srcInset,
377*c8dee2aaSAndroid Build Coastguard Worker                              skgpu::ganesh::SmallPathShapeData* shapeData) const {
378*c8dee2aaSAndroid Build Coastguard Worker         auto resourceProvider = target->resourceProvider();
379*c8dee2aaSAndroid Build Coastguard Worker         auto uploadTarget = target->deferredUploadTarget();
380*c8dee2aaSAndroid Build Coastguard Worker 
381*c8dee2aaSAndroid Build Coastguard Worker         auto code = atlasMgr->addToAtlas(resourceProvider, uploadTarget, width, height,
382*c8dee2aaSAndroid Build Coastguard Worker                                          image, &shapeData->fAtlasLocator);
383*c8dee2aaSAndroid Build Coastguard Worker         if (GrDrawOpAtlas::ErrorCode::kError == code) {
384*c8dee2aaSAndroid Build Coastguard Worker             return false;
385*c8dee2aaSAndroid Build Coastguard Worker         }
386*c8dee2aaSAndroid Build Coastguard Worker 
387*c8dee2aaSAndroid Build Coastguard Worker         if (GrDrawOpAtlas::ErrorCode::kTryAgain == code) {
388*c8dee2aaSAndroid Build Coastguard Worker             this->flush(target, flushInfo);
389*c8dee2aaSAndroid Build Coastguard Worker 
390*c8dee2aaSAndroid Build Coastguard Worker             code = atlasMgr->addToAtlas(resourceProvider, uploadTarget, width, height,
391*c8dee2aaSAndroid Build Coastguard Worker                                         image, &shapeData->fAtlasLocator);
392*c8dee2aaSAndroid Build Coastguard Worker         }
393*c8dee2aaSAndroid Build Coastguard Worker 
394*c8dee2aaSAndroid Build Coastguard Worker         shapeData->fAtlasLocator.insetSrc(srcInset);
395*c8dee2aaSAndroid Build Coastguard Worker         shapeData->fBounds = bounds;
396*c8dee2aaSAndroid Build Coastguard Worker 
397*c8dee2aaSAndroid Build Coastguard Worker         return GrDrawOpAtlas::ErrorCode::kSucceeded == code;
398*c8dee2aaSAndroid Build Coastguard Worker     }
399*c8dee2aaSAndroid Build Coastguard Worker 
addDFPathToAtlas(GrMeshDrawTarget * target,FlushInfo * flushInfo,skgpu::ganesh::SmallPathAtlasMgr * atlasMgr,skgpu::ganesh::SmallPathShapeData * shapeData,const GrStyledShape & shape,uint32_t dimension,SkScalar scale) const400*c8dee2aaSAndroid Build Coastguard Worker     bool addDFPathToAtlas(GrMeshDrawTarget* target,
401*c8dee2aaSAndroid Build Coastguard Worker                           FlushInfo* flushInfo,
402*c8dee2aaSAndroid Build Coastguard Worker                           skgpu::ganesh::SmallPathAtlasMgr* atlasMgr,
403*c8dee2aaSAndroid Build Coastguard Worker                           skgpu::ganesh::SmallPathShapeData* shapeData,
404*c8dee2aaSAndroid Build Coastguard Worker                           const GrStyledShape& shape,
405*c8dee2aaSAndroid Build Coastguard Worker                           uint32_t dimension,
406*c8dee2aaSAndroid Build Coastguard Worker                           SkScalar scale) const {
407*c8dee2aaSAndroid Build Coastguard Worker         const SkRect& bounds = shape.bounds();
408*c8dee2aaSAndroid Build Coastguard Worker 
409*c8dee2aaSAndroid Build Coastguard Worker         // generate bounding rect for bitmap draw
410*c8dee2aaSAndroid Build Coastguard Worker         SkRect scaledBounds = bounds;
411*c8dee2aaSAndroid Build Coastguard Worker         // scale to mip level size
412*c8dee2aaSAndroid Build Coastguard Worker         scaledBounds.fLeft *= scale;
413*c8dee2aaSAndroid Build Coastguard Worker         scaledBounds.fTop *= scale;
414*c8dee2aaSAndroid Build Coastguard Worker         scaledBounds.fRight *= scale;
415*c8dee2aaSAndroid Build Coastguard Worker         scaledBounds.fBottom *= scale;
416*c8dee2aaSAndroid Build Coastguard Worker         // subtract out integer portion of origin
417*c8dee2aaSAndroid Build Coastguard Worker         // (SDF created will be placed with fractional offset burnt in)
418*c8dee2aaSAndroid Build Coastguard Worker         SkScalar dx = SkScalarFloorToScalar(scaledBounds.fLeft);
419*c8dee2aaSAndroid Build Coastguard Worker         SkScalar dy = SkScalarFloorToScalar(scaledBounds.fTop);
420*c8dee2aaSAndroid Build Coastguard Worker         scaledBounds.offset(-dx, -dy);
421*c8dee2aaSAndroid Build Coastguard Worker         // get integer boundary
422*c8dee2aaSAndroid Build Coastguard Worker         SkIRect devPathBounds;
423*c8dee2aaSAndroid Build Coastguard Worker         scaledBounds.roundOut(&devPathBounds);
424*c8dee2aaSAndroid Build Coastguard Worker         // place devBounds at origin with padding to allow room for antialiasing
425*c8dee2aaSAndroid Build Coastguard Worker         int width = devPathBounds.width() + 2 * kAntiAliasPad;
426*c8dee2aaSAndroid Build Coastguard Worker         int height = devPathBounds.height() + 2 * kAntiAliasPad;
427*c8dee2aaSAndroid Build Coastguard Worker         devPathBounds = SkIRect::MakeWH(width, height);
428*c8dee2aaSAndroid Build Coastguard Worker         SkScalar translateX = kAntiAliasPad - dx;
429*c8dee2aaSAndroid Build Coastguard Worker         SkScalar translateY = kAntiAliasPad - dy;
430*c8dee2aaSAndroid Build Coastguard Worker 
431*c8dee2aaSAndroid Build Coastguard Worker         // draw path to bitmap
432*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix drawMatrix;
433*c8dee2aaSAndroid Build Coastguard Worker         drawMatrix.setScale(scale, scale);
434*c8dee2aaSAndroid Build Coastguard Worker         drawMatrix.postTranslate(translateX, translateY);
435*c8dee2aaSAndroid Build Coastguard Worker 
436*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(devPathBounds.fLeft == 0);
437*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(devPathBounds.fTop == 0);
438*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(devPathBounds.width() > 0);
439*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(devPathBounds.height() > 0);
440*c8dee2aaSAndroid Build Coastguard Worker 
441*c8dee2aaSAndroid Build Coastguard Worker         // setup signed distance field storage
442*c8dee2aaSAndroid Build Coastguard Worker         SkIRect dfBounds = devPathBounds.makeOutset(SK_DistanceFieldPad, SK_DistanceFieldPad);
443*c8dee2aaSAndroid Build Coastguard Worker         width = dfBounds.width();
444*c8dee2aaSAndroid Build Coastguard Worker         height = dfBounds.height();
445*c8dee2aaSAndroid Build Coastguard Worker         // TODO We should really generate this directly into the plot somehow
446*c8dee2aaSAndroid Build Coastguard Worker         SkAutoSMalloc<1024> dfStorage(width * height * sizeof(unsigned char));
447*c8dee2aaSAndroid Build Coastguard Worker 
448*c8dee2aaSAndroid Build Coastguard Worker         SkPath path;
449*c8dee2aaSAndroid Build Coastguard Worker         shape.asPath(&path);
450*c8dee2aaSAndroid Build Coastguard Worker         // Generate signed distance field directly from SkPath
451*c8dee2aaSAndroid Build Coastguard Worker         bool succeed = GrGenerateDistanceFieldFromPath((unsigned char*)dfStorage.get(),
452*c8dee2aaSAndroid Build Coastguard Worker                                                        path, drawMatrix, width, height,
453*c8dee2aaSAndroid Build Coastguard Worker                                                        width * sizeof(unsigned char));
454*c8dee2aaSAndroid Build Coastguard Worker         if (!succeed) {
455*c8dee2aaSAndroid Build Coastguard Worker             // setup bitmap backing
456*c8dee2aaSAndroid Build Coastguard Worker             SkAutoPixmapStorage dst;
457*c8dee2aaSAndroid Build Coastguard Worker             if (!dst.tryAlloc(SkImageInfo::MakeA8(devPathBounds.width(), devPathBounds.height()))) {
458*c8dee2aaSAndroid Build Coastguard Worker                 return false;
459*c8dee2aaSAndroid Build Coastguard Worker             }
460*c8dee2aaSAndroid Build Coastguard Worker             sk_bzero(dst.writable_addr(), dst.computeByteSize());
461*c8dee2aaSAndroid Build Coastguard Worker 
462*c8dee2aaSAndroid Build Coastguard Worker             // rasterize path
463*c8dee2aaSAndroid Build Coastguard Worker             SkPaint paint;
464*c8dee2aaSAndroid Build Coastguard Worker             paint.setStyle(SkPaint::kFill_Style);
465*c8dee2aaSAndroid Build Coastguard Worker             paint.setAntiAlias(true);
466*c8dee2aaSAndroid Build Coastguard Worker 
467*c8dee2aaSAndroid Build Coastguard Worker             SkDraw draw;
468*c8dee2aaSAndroid Build Coastguard Worker 
469*c8dee2aaSAndroid Build Coastguard Worker             SkRasterClip rasterClip;
470*c8dee2aaSAndroid Build Coastguard Worker             rasterClip.setRect(devPathBounds);
471*c8dee2aaSAndroid Build Coastguard Worker             draw.fRC = &rasterClip;
472*c8dee2aaSAndroid Build Coastguard Worker             draw.fCTM = &drawMatrix;
473*c8dee2aaSAndroid Build Coastguard Worker             draw.fDst = dst;
474*c8dee2aaSAndroid Build Coastguard Worker 
475*c8dee2aaSAndroid Build Coastguard Worker             draw.drawPathCoverage(path, paint);
476*c8dee2aaSAndroid Build Coastguard Worker 
477*c8dee2aaSAndroid Build Coastguard Worker             // Generate signed distance field
478*c8dee2aaSAndroid Build Coastguard Worker             SkGenerateDistanceFieldFromA8Image((unsigned char*)dfStorage.get(),
479*c8dee2aaSAndroid Build Coastguard Worker                                                (const unsigned char*)dst.addr(),
480*c8dee2aaSAndroid Build Coastguard Worker                                                dst.width(), dst.height(), dst.rowBytes());
481*c8dee2aaSAndroid Build Coastguard Worker         }
482*c8dee2aaSAndroid Build Coastguard Worker 
483*c8dee2aaSAndroid Build Coastguard Worker         SkRect drawBounds = SkRect::Make(devPathBounds).makeOffset(-translateX, -translateY);
484*c8dee2aaSAndroid Build Coastguard Worker         drawBounds.fLeft /= scale;
485*c8dee2aaSAndroid Build Coastguard Worker         drawBounds.fTop /= scale;
486*c8dee2aaSAndroid Build Coastguard Worker         drawBounds.fRight /= scale;
487*c8dee2aaSAndroid Build Coastguard Worker         drawBounds.fBottom /= scale;
488*c8dee2aaSAndroid Build Coastguard Worker 
489*c8dee2aaSAndroid Build Coastguard Worker         return this->addToAtlasWithRetry(target, flushInfo, atlasMgr,
490*c8dee2aaSAndroid Build Coastguard Worker                                          width, height, dfStorage.get(),
491*c8dee2aaSAndroid Build Coastguard Worker                                          drawBounds, SK_DistanceFieldPad, shapeData);
492*c8dee2aaSAndroid Build Coastguard Worker     }
493*c8dee2aaSAndroid Build Coastguard Worker 
addBMPathToAtlas(GrMeshDrawTarget * target,FlushInfo * flushInfo,skgpu::ganesh::SmallPathAtlasMgr * atlasMgr,skgpu::ganesh::SmallPathShapeData * shapeData,const GrStyledShape & shape,const SkMatrix & ctm) const494*c8dee2aaSAndroid Build Coastguard Worker     bool addBMPathToAtlas(GrMeshDrawTarget* target,
495*c8dee2aaSAndroid Build Coastguard Worker                           FlushInfo* flushInfo,
496*c8dee2aaSAndroid Build Coastguard Worker                           skgpu::ganesh::SmallPathAtlasMgr* atlasMgr,
497*c8dee2aaSAndroid Build Coastguard Worker                           skgpu::ganesh::SmallPathShapeData* shapeData,
498*c8dee2aaSAndroid Build Coastguard Worker                           const GrStyledShape& shape,
499*c8dee2aaSAndroid Build Coastguard Worker                           const SkMatrix& ctm) const {
500*c8dee2aaSAndroid Build Coastguard Worker         const SkRect& bounds = shape.bounds();
501*c8dee2aaSAndroid Build Coastguard Worker         if (bounds.isEmpty()) {
502*c8dee2aaSAndroid Build Coastguard Worker             return false;
503*c8dee2aaSAndroid Build Coastguard Worker         }
504*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix drawMatrix(ctm);
505*c8dee2aaSAndroid Build Coastguard Worker         SkScalar tx = ctm.getTranslateX();
506*c8dee2aaSAndroid Build Coastguard Worker         SkScalar ty = ctm.getTranslateY();
507*c8dee2aaSAndroid Build Coastguard Worker         tx -= SkScalarFloorToScalar(tx);
508*c8dee2aaSAndroid Build Coastguard Worker         ty -= SkScalarFloorToScalar(ty);
509*c8dee2aaSAndroid Build Coastguard Worker         drawMatrix.set(SkMatrix::kMTransX, tx);
510*c8dee2aaSAndroid Build Coastguard Worker         drawMatrix.set(SkMatrix::kMTransY, ty);
511*c8dee2aaSAndroid Build Coastguard Worker         SkRect shapeDevBounds;
512*c8dee2aaSAndroid Build Coastguard Worker         drawMatrix.mapRect(&shapeDevBounds, bounds);
513*c8dee2aaSAndroid Build Coastguard Worker         SkScalar dx = SkScalarFloorToScalar(shapeDevBounds.fLeft);
514*c8dee2aaSAndroid Build Coastguard Worker         SkScalar dy = SkScalarFloorToScalar(shapeDevBounds.fTop);
515*c8dee2aaSAndroid Build Coastguard Worker 
516*c8dee2aaSAndroid Build Coastguard Worker         // get integer boundary
517*c8dee2aaSAndroid Build Coastguard Worker         SkIRect devPathBounds;
518*c8dee2aaSAndroid Build Coastguard Worker         shapeDevBounds.roundOut(&devPathBounds);
519*c8dee2aaSAndroid Build Coastguard Worker         // place devBounds at origin with padding to allow room for antialiasing
520*c8dee2aaSAndroid Build Coastguard Worker         int width = devPathBounds.width() + 2 * kAntiAliasPad;
521*c8dee2aaSAndroid Build Coastguard Worker         int height = devPathBounds.height() + 2 * kAntiAliasPad;
522*c8dee2aaSAndroid Build Coastguard Worker         devPathBounds = SkIRect::MakeWH(width, height);
523*c8dee2aaSAndroid Build Coastguard Worker         SkScalar translateX = kAntiAliasPad - dx;
524*c8dee2aaSAndroid Build Coastguard Worker         SkScalar translateY = kAntiAliasPad - dy;
525*c8dee2aaSAndroid Build Coastguard Worker 
526*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(devPathBounds.fLeft == 0);
527*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(devPathBounds.fTop == 0);
528*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(devPathBounds.width() > 0);
529*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(devPathBounds.height() > 0);
530*c8dee2aaSAndroid Build Coastguard Worker 
531*c8dee2aaSAndroid Build Coastguard Worker         SkPath path;
532*c8dee2aaSAndroid Build Coastguard Worker         shape.asPath(&path);
533*c8dee2aaSAndroid Build Coastguard Worker         // setup bitmap backing
534*c8dee2aaSAndroid Build Coastguard Worker         SkAutoPixmapStorage dst;
535*c8dee2aaSAndroid Build Coastguard Worker         if (!dst.tryAlloc(SkImageInfo::MakeA8(devPathBounds.width(), devPathBounds.height()))) {
536*c8dee2aaSAndroid Build Coastguard Worker             return false;
537*c8dee2aaSAndroid Build Coastguard Worker         }
538*c8dee2aaSAndroid Build Coastguard Worker         sk_bzero(dst.writable_addr(), dst.computeByteSize());
539*c8dee2aaSAndroid Build Coastguard Worker 
540*c8dee2aaSAndroid Build Coastguard Worker         // rasterize path
541*c8dee2aaSAndroid Build Coastguard Worker         SkPaint paint;
542*c8dee2aaSAndroid Build Coastguard Worker         paint.setStyle(SkPaint::kFill_Style);
543*c8dee2aaSAndroid Build Coastguard Worker         paint.setAntiAlias(true);
544*c8dee2aaSAndroid Build Coastguard Worker 
545*c8dee2aaSAndroid Build Coastguard Worker         SkDraw draw;
546*c8dee2aaSAndroid Build Coastguard Worker 
547*c8dee2aaSAndroid Build Coastguard Worker         SkRasterClip rasterClip;
548*c8dee2aaSAndroid Build Coastguard Worker         rasterClip.setRect(devPathBounds);
549*c8dee2aaSAndroid Build Coastguard Worker         drawMatrix.postTranslate(translateX, translateY);
550*c8dee2aaSAndroid Build Coastguard Worker         draw.fRC = &rasterClip;
551*c8dee2aaSAndroid Build Coastguard Worker         draw.fCTM = &drawMatrix;
552*c8dee2aaSAndroid Build Coastguard Worker         draw.fDst = dst;
553*c8dee2aaSAndroid Build Coastguard Worker 
554*c8dee2aaSAndroid Build Coastguard Worker         draw.drawPathCoverage(path, paint);
555*c8dee2aaSAndroid Build Coastguard Worker 
556*c8dee2aaSAndroid Build Coastguard Worker         SkRect drawBounds = SkRect::Make(devPathBounds).makeOffset(-translateX, -translateY);
557*c8dee2aaSAndroid Build Coastguard Worker 
558*c8dee2aaSAndroid Build Coastguard Worker         return this->addToAtlasWithRetry(target, flushInfo, atlasMgr,
559*c8dee2aaSAndroid Build Coastguard Worker                                          dst.width(), dst.height(), dst.addr(),
560*c8dee2aaSAndroid Build Coastguard Worker                                          drawBounds, 0, shapeData);
561*c8dee2aaSAndroid Build Coastguard Worker     }
562*c8dee2aaSAndroid Build Coastguard Worker 
writePathVertices(VertexWriter & vertices,const VertexColor & color,const SkMatrix & ctm,const skgpu::ganesh::SmallPathShapeData * shapeData) const563*c8dee2aaSAndroid Build Coastguard Worker     void writePathVertices(VertexWriter& vertices,
564*c8dee2aaSAndroid Build Coastguard Worker                            const VertexColor& color,
565*c8dee2aaSAndroid Build Coastguard Worker                            const SkMatrix& ctm,
566*c8dee2aaSAndroid Build Coastguard Worker                            const skgpu::ganesh::SmallPathShapeData* shapeData) const {
567*c8dee2aaSAndroid Build Coastguard Worker         SkRect translatedBounds(shapeData->fBounds);
568*c8dee2aaSAndroid Build Coastguard Worker         if (!fUsesDistanceField) {
569*c8dee2aaSAndroid Build Coastguard Worker             translatedBounds.offset(SkScalarFloorToScalar(ctm.get(SkMatrix::kMTransX)),
570*c8dee2aaSAndroid Build Coastguard Worker                                     SkScalarFloorToScalar(ctm.get(SkMatrix::kMTransY)));
571*c8dee2aaSAndroid Build Coastguard Worker         }
572*c8dee2aaSAndroid Build Coastguard Worker 
573*c8dee2aaSAndroid Build Coastguard Worker         // set up texture coordinates
574*c8dee2aaSAndroid Build Coastguard Worker         auto texCoords = VertexWriter::TriStripFromUVs(shapeData->fAtlasLocator.getUVs());
575*c8dee2aaSAndroid Build Coastguard Worker 
576*c8dee2aaSAndroid Build Coastguard Worker         if (fUsesDistanceField) {
577*c8dee2aaSAndroid Build Coastguard Worker             SkPoint pts[4];
578*c8dee2aaSAndroid Build Coastguard Worker             SkPoint3 out[4];
579*c8dee2aaSAndroid Build Coastguard Worker             translatedBounds.toQuad(pts);
580*c8dee2aaSAndroid Build Coastguard Worker             ctm.mapHomogeneousPoints(out, pts, 4);
581*c8dee2aaSAndroid Build Coastguard Worker 
582*c8dee2aaSAndroid Build Coastguard Worker             vertices << out[0] << color << texCoords.l << texCoords.t;
583*c8dee2aaSAndroid Build Coastguard Worker             vertices << out[3] << color << texCoords.l << texCoords.b;
584*c8dee2aaSAndroid Build Coastguard Worker             vertices << out[1] << color << texCoords.r << texCoords.t;
585*c8dee2aaSAndroid Build Coastguard Worker             vertices << out[2] << color << texCoords.r << texCoords.b;
586*c8dee2aaSAndroid Build Coastguard Worker         } else {
587*c8dee2aaSAndroid Build Coastguard Worker             vertices.writeQuad(VertexWriter::TriStripFromRect(translatedBounds),
588*c8dee2aaSAndroid Build Coastguard Worker                                color,
589*c8dee2aaSAndroid Build Coastguard Worker                                texCoords);
590*c8dee2aaSAndroid Build Coastguard Worker         }
591*c8dee2aaSAndroid Build Coastguard Worker     }
592*c8dee2aaSAndroid Build Coastguard Worker 
flush(GrMeshDrawTarget * target,FlushInfo * flushInfo) const593*c8dee2aaSAndroid Build Coastguard Worker     void flush(GrMeshDrawTarget* target, FlushInfo* flushInfo) const {
594*c8dee2aaSAndroid Build Coastguard Worker         auto atlasMgr = target->smallPathAtlasManager();
595*c8dee2aaSAndroid Build Coastguard Worker         if (!atlasMgr) {
596*c8dee2aaSAndroid Build Coastguard Worker             return;
597*c8dee2aaSAndroid Build Coastguard Worker         }
598*c8dee2aaSAndroid Build Coastguard Worker 
599*c8dee2aaSAndroid Build Coastguard Worker         int numActiveProxies;
600*c8dee2aaSAndroid Build Coastguard Worker         const GrSurfaceProxyView* views = atlasMgr->getViews(&numActiveProxies);
601*c8dee2aaSAndroid Build Coastguard Worker 
602*c8dee2aaSAndroid Build Coastguard Worker         GrGeometryProcessor* gp = flushInfo->fGeometryProcessor;
603*c8dee2aaSAndroid Build Coastguard Worker         if (gp->numTextureSamplers() != numActiveProxies) {
604*c8dee2aaSAndroid Build Coastguard Worker             for (int i = gp->numTextureSamplers(); i < numActiveProxies; ++i) {
605*c8dee2aaSAndroid Build Coastguard Worker                 flushInfo->fPrimProcProxies[i] = views[i].proxy();
606*c8dee2aaSAndroid Build Coastguard Worker                 // This op does not know its atlas proxies when it is added to a OpsTasks, so the
607*c8dee2aaSAndroid Build Coastguard Worker                 // proxies don't get added during the visitProxies call. Thus we add them here.
608*c8dee2aaSAndroid Build Coastguard Worker                 target->sampledProxyArray()->push_back(views[i].proxy());
609*c8dee2aaSAndroid Build Coastguard Worker             }
610*c8dee2aaSAndroid Build Coastguard Worker             // During preparation the number of atlas pages has increased.
611*c8dee2aaSAndroid Build Coastguard Worker             // Update the proxies used in the GP to match.
612*c8dee2aaSAndroid Build Coastguard Worker             if (fUsesDistanceField) {
613*c8dee2aaSAndroid Build Coastguard Worker                 reinterpret_cast<GrDistanceFieldPathGeoProc*>(gp)->addNewViews(
614*c8dee2aaSAndroid Build Coastguard Worker                         views, numActiveProxies, GrSamplerState::Filter::kLinear);
615*c8dee2aaSAndroid Build Coastguard Worker             } else {
616*c8dee2aaSAndroid Build Coastguard Worker                 reinterpret_cast<GrBitmapTextGeoProc*>(gp)->addNewViews(
617*c8dee2aaSAndroid Build Coastguard Worker                         views, numActiveProxies, GrSamplerState::Filter::kNearest);
618*c8dee2aaSAndroid Build Coastguard Worker             }
619*c8dee2aaSAndroid Build Coastguard Worker         }
620*c8dee2aaSAndroid Build Coastguard Worker 
621*c8dee2aaSAndroid Build Coastguard Worker         if (flushInfo->fInstancesToFlush) {
622*c8dee2aaSAndroid Build Coastguard Worker             GrSimpleMesh* mesh = target->allocMesh();
623*c8dee2aaSAndroid Build Coastguard Worker             mesh->setIndexedPatterned(flushInfo->fIndexBuffer,
624*c8dee2aaSAndroid Build Coastguard Worker                                       GrResourceProvider::NumIndicesPerNonAAQuad(),
625*c8dee2aaSAndroid Build Coastguard Worker                                       flushInfo->fInstancesToFlush,
626*c8dee2aaSAndroid Build Coastguard Worker                                       GrResourceProvider::MaxNumNonAAQuads(),
627*c8dee2aaSAndroid Build Coastguard Worker                                       flushInfo->fVertexBuffer,
628*c8dee2aaSAndroid Build Coastguard Worker                                       GrResourceProvider::NumVertsPerNonAAQuad(),
629*c8dee2aaSAndroid Build Coastguard Worker                                       flushInfo->fVertexOffset);
630*c8dee2aaSAndroid Build Coastguard Worker             target->recordDraw(flushInfo->fGeometryProcessor, mesh, 1, flushInfo->fPrimProcProxies,
631*c8dee2aaSAndroid Build Coastguard Worker                                GrPrimitiveType::kTriangles);
632*c8dee2aaSAndroid Build Coastguard Worker             flushInfo->fVertexOffset += GrResourceProvider::NumVertsPerNonAAQuad() *
633*c8dee2aaSAndroid Build Coastguard Worker                                         flushInfo->fInstancesToFlush;
634*c8dee2aaSAndroid Build Coastguard Worker             flushInfo->fInstancesToFlush = 0;
635*c8dee2aaSAndroid Build Coastguard Worker         }
636*c8dee2aaSAndroid Build Coastguard Worker     }
637*c8dee2aaSAndroid Build Coastguard Worker 
onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)638*c8dee2aaSAndroid Build Coastguard Worker     void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
639*c8dee2aaSAndroid Build Coastguard Worker         auto pipeline = fHelper.createPipeline(flushState);
640*c8dee2aaSAndroid Build Coastguard Worker 
641*c8dee2aaSAndroid Build Coastguard Worker         flushState->executeDrawsAndUploadsForMeshDrawOp(this, chainBounds, pipeline,
642*c8dee2aaSAndroid Build Coastguard Worker                                                         fHelper.stencilSettings());
643*c8dee2aaSAndroid Build Coastguard Worker     }
644*c8dee2aaSAndroid Build Coastguard Worker 
color() const645*c8dee2aaSAndroid Build Coastguard Worker     const SkPMColor4f& color() const { return fShapes[0].fColor; }
usesDistanceField() const646*c8dee2aaSAndroid Build Coastguard Worker     bool usesDistanceField() const { return fUsesDistanceField; }
647*c8dee2aaSAndroid Build Coastguard Worker 
onCombineIfPossible(GrOp * t,SkArenaAlloc *,const GrCaps & caps)648*c8dee2aaSAndroid Build Coastguard Worker     CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override {
649*c8dee2aaSAndroid Build Coastguard Worker         SmallPathOp* that = t->cast<SmallPathOp>();
650*c8dee2aaSAndroid Build Coastguard Worker         if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
651*c8dee2aaSAndroid Build Coastguard Worker             return CombineResult::kCannotCombine;
652*c8dee2aaSAndroid Build Coastguard Worker         }
653*c8dee2aaSAndroid Build Coastguard Worker 
654*c8dee2aaSAndroid Build Coastguard Worker         if (this->usesDistanceField() != that->usesDistanceField()) {
655*c8dee2aaSAndroid Build Coastguard Worker             return CombineResult::kCannotCombine;
656*c8dee2aaSAndroid Build Coastguard Worker         }
657*c8dee2aaSAndroid Build Coastguard Worker 
658*c8dee2aaSAndroid Build Coastguard Worker         const SkMatrix& thisCtm = this->fShapes[0].fViewMatrix;
659*c8dee2aaSAndroid Build Coastguard Worker         const SkMatrix& thatCtm = that->fShapes[0].fViewMatrix;
660*c8dee2aaSAndroid Build Coastguard Worker 
661*c8dee2aaSAndroid Build Coastguard Worker         if (this->usesDistanceField()) {
662*c8dee2aaSAndroid Build Coastguard Worker             // Need to make sure local matrices are identical
663*c8dee2aaSAndroid Build Coastguard Worker             if (fHelper.usesLocalCoords() && !SkMatrixPriv::CheapEqual(thisCtm, thatCtm)) {
664*c8dee2aaSAndroid Build Coastguard Worker                 return CombineResult::kCannotCombine;
665*c8dee2aaSAndroid Build Coastguard Worker             }
666*c8dee2aaSAndroid Build Coastguard Worker 
667*c8dee2aaSAndroid Build Coastguard Worker             // Depending on the ctm we may have a different shader for SDF paths
668*c8dee2aaSAndroid Build Coastguard Worker             if (thisCtm.isScaleTranslate() != thatCtm.isScaleTranslate() ||
669*c8dee2aaSAndroid Build Coastguard Worker                 thisCtm.isSimilarity() != thatCtm.isSimilarity()) {
670*c8dee2aaSAndroid Build Coastguard Worker                 return CombineResult::kCannotCombine;
671*c8dee2aaSAndroid Build Coastguard Worker             }
672*c8dee2aaSAndroid Build Coastguard Worker         } else {
673*c8dee2aaSAndroid Build Coastguard Worker             if (thisCtm.hasPerspective() != thatCtm.hasPerspective()) {
674*c8dee2aaSAndroid Build Coastguard Worker                 return CombineResult::kCannotCombine;
675*c8dee2aaSAndroid Build Coastguard Worker             }
676*c8dee2aaSAndroid Build Coastguard Worker 
677*c8dee2aaSAndroid Build Coastguard Worker             // We can position on the cpu unless we're in perspective,
678*c8dee2aaSAndroid Build Coastguard Worker             // but also need to make sure local matrices are identical
679*c8dee2aaSAndroid Build Coastguard Worker             if ((thisCtm.hasPerspective() || fHelper.usesLocalCoords()) &&
680*c8dee2aaSAndroid Build Coastguard Worker                 !SkMatrixPriv::CheapEqual(thisCtm, thatCtm)) {
681*c8dee2aaSAndroid Build Coastguard Worker                 return CombineResult::kCannotCombine;
682*c8dee2aaSAndroid Build Coastguard Worker             }
683*c8dee2aaSAndroid Build Coastguard Worker         }
684*c8dee2aaSAndroid Build Coastguard Worker 
685*c8dee2aaSAndroid Build Coastguard Worker         fShapes.push_back_n(that->fShapes.size(), that->fShapes.begin());
686*c8dee2aaSAndroid Build Coastguard Worker         fWideColor |= that->fWideColor;
687*c8dee2aaSAndroid Build Coastguard Worker         return CombineResult::kMerged;
688*c8dee2aaSAndroid Build Coastguard Worker     }
689*c8dee2aaSAndroid Build Coastguard Worker 
690*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
onDumpInfo() const691*c8dee2aaSAndroid Build Coastguard Worker     SkString onDumpInfo() const override {
692*c8dee2aaSAndroid Build Coastguard Worker         SkString string;
693*c8dee2aaSAndroid Build Coastguard Worker         for (const auto& geo : fShapes) {
694*c8dee2aaSAndroid Build Coastguard Worker             string.appendf("Color: 0x%08x\n", geo.fColor.toBytes_RGBA());
695*c8dee2aaSAndroid Build Coastguard Worker         }
696*c8dee2aaSAndroid Build Coastguard Worker         string += fHelper.dumpInfo();
697*c8dee2aaSAndroid Build Coastguard Worker         return string;
698*c8dee2aaSAndroid Build Coastguard Worker     }
699*c8dee2aaSAndroid Build Coastguard Worker #endif
700*c8dee2aaSAndroid Build Coastguard Worker 
701*c8dee2aaSAndroid Build Coastguard Worker     bool fUsesDistanceField;
702*c8dee2aaSAndroid Build Coastguard Worker 
703*c8dee2aaSAndroid Build Coastguard Worker     struct Entry {
704*c8dee2aaSAndroid Build Coastguard Worker         SkPMColor4f   fColor;
705*c8dee2aaSAndroid Build Coastguard Worker         GrStyledShape fShape;
706*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix      fViewMatrix;
707*c8dee2aaSAndroid Build Coastguard Worker     };
708*c8dee2aaSAndroid Build Coastguard Worker 
709*c8dee2aaSAndroid Build Coastguard Worker     STArray<1, Entry> fShapes;
710*c8dee2aaSAndroid Build Coastguard Worker     Helper fHelper;
711*c8dee2aaSAndroid Build Coastguard Worker     bool fGammaCorrect;
712*c8dee2aaSAndroid Build Coastguard Worker     bool fWideColor;
713*c8dee2aaSAndroid Build Coastguard Worker 
714*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = GrMeshDrawOp;
715*c8dee2aaSAndroid Build Coastguard Worker };
716*c8dee2aaSAndroid Build Coastguard Worker 
717*c8dee2aaSAndroid Build Coastguard Worker } // anonymous namespace
718*c8dee2aaSAndroid Build Coastguard Worker 
719*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
720*c8dee2aaSAndroid Build Coastguard Worker 
onCanDrawPath(const CanDrawPathArgs & args) const721*c8dee2aaSAndroid Build Coastguard Worker PathRenderer::CanDrawPath SmallPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
722*c8dee2aaSAndroid Build Coastguard Worker     if (!args.fCaps->shaderCaps()->fShaderDerivativeSupport) {
723*c8dee2aaSAndroid Build Coastguard Worker         return CanDrawPath::kNo;
724*c8dee2aaSAndroid Build Coastguard Worker     }
725*c8dee2aaSAndroid Build Coastguard Worker     // If the shape has no key then we won't get any reuse.
726*c8dee2aaSAndroid Build Coastguard Worker     if (!args.fShape->hasUnstyledKey()) {
727*c8dee2aaSAndroid Build Coastguard Worker         return CanDrawPath::kNo;
728*c8dee2aaSAndroid Build Coastguard Worker     }
729*c8dee2aaSAndroid Build Coastguard Worker     // This only supports filled paths, however, the caller may apply the style to make a filled
730*c8dee2aaSAndroid Build Coastguard Worker     // path and try again.
731*c8dee2aaSAndroid Build Coastguard Worker     if (!args.fShape->style().isSimpleFill()) {
732*c8dee2aaSAndroid Build Coastguard Worker         return CanDrawPath::kNo;
733*c8dee2aaSAndroid Build Coastguard Worker     }
734*c8dee2aaSAndroid Build Coastguard Worker     // This does non-inverse coverage-based antialiased fills.
735*c8dee2aaSAndroid Build Coastguard Worker     if (GrAAType::kCoverage != args.fAAType) {
736*c8dee2aaSAndroid Build Coastguard Worker         return CanDrawPath::kNo;
737*c8dee2aaSAndroid Build Coastguard Worker     }
738*c8dee2aaSAndroid Build Coastguard Worker     // TODO: Support inverse fill
739*c8dee2aaSAndroid Build Coastguard Worker     if (args.fShape->inverseFilled()) {
740*c8dee2aaSAndroid Build Coastguard Worker         return CanDrawPath::kNo;
741*c8dee2aaSAndroid Build Coastguard Worker     }
742*c8dee2aaSAndroid Build Coastguard Worker 
743*c8dee2aaSAndroid Build Coastguard Worker     SkScalar scaleFactors[2] = { 1, 1 };
744*c8dee2aaSAndroid Build Coastguard Worker     // TODO: handle perspective distortion
745*c8dee2aaSAndroid Build Coastguard Worker     if (!args.fViewMatrix->hasPerspective() && !args.fViewMatrix->getMinMaxScales(scaleFactors)) {
746*c8dee2aaSAndroid Build Coastguard Worker         return CanDrawPath::kNo;
747*c8dee2aaSAndroid Build Coastguard Worker     }
748*c8dee2aaSAndroid Build Coastguard Worker     // For affine transformations, too much shear can produce artifacts.
749*c8dee2aaSAndroid Build Coastguard Worker     if (!scaleFactors[0] || scaleFactors[1]/scaleFactors[0] > 4) {
750*c8dee2aaSAndroid Build Coastguard Worker         return CanDrawPath::kNo;
751*c8dee2aaSAndroid Build Coastguard Worker     }
752*c8dee2aaSAndroid Build Coastguard Worker     // Only support paths with bounds within kMaxDim by kMaxDim,
753*c8dee2aaSAndroid Build Coastguard Worker     // scaled to have bounds within kMaxSize by kMaxSize.
754*c8dee2aaSAndroid Build Coastguard Worker     // The goal is to accelerate rendering of lots of small paths that may be scaling.
755*c8dee2aaSAndroid Build Coastguard Worker     SkRect bounds = args.fShape->styledBounds();
756*c8dee2aaSAndroid Build Coastguard Worker     SkScalar minDim = std::min(bounds.width(), bounds.height());
757*c8dee2aaSAndroid Build Coastguard Worker     SkScalar maxDim = std::max(bounds.width(), bounds.height());
758*c8dee2aaSAndroid Build Coastguard Worker     SkScalar minSize = minDim * SkScalarAbs(scaleFactors[0]);
759*c8dee2aaSAndroid Build Coastguard Worker     SkScalar maxSize = maxDim * SkScalarAbs(scaleFactors[1]);
760*c8dee2aaSAndroid Build Coastguard Worker     if (maxDim > kMaxDim || kMinSize > minSize || maxSize > kMaxSize) {
761*c8dee2aaSAndroid Build Coastguard Worker         return CanDrawPath::kNo;
762*c8dee2aaSAndroid Build Coastguard Worker     }
763*c8dee2aaSAndroid Build Coastguard Worker 
764*c8dee2aaSAndroid Build Coastguard Worker     return CanDrawPath::kYes;
765*c8dee2aaSAndroid Build Coastguard Worker }
766*c8dee2aaSAndroid Build Coastguard Worker 
onDrawPath(const DrawPathArgs & args)767*c8dee2aaSAndroid Build Coastguard Worker bool SmallPathRenderer::onDrawPath(const DrawPathArgs& args) {
768*c8dee2aaSAndroid Build Coastguard Worker     GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
769*c8dee2aaSAndroid Build Coastguard Worker                               "SmallPathRenderer::onDrawPath");
770*c8dee2aaSAndroid Build Coastguard Worker 
771*c8dee2aaSAndroid Build Coastguard Worker     // we've already bailed on inverse filled paths, so this is safe
772*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(!args.fShape->isEmpty());
773*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(args.fShape->hasUnstyledKey());
774*c8dee2aaSAndroid Build Coastguard Worker 
775*c8dee2aaSAndroid Build Coastguard Worker     GrOp::Owner op = SmallPathOp::Make(
776*c8dee2aaSAndroid Build Coastguard Worker             args.fContext, std::move(args.fPaint), *args.fShape, *args.fViewMatrix,
777*c8dee2aaSAndroid Build Coastguard Worker             args.fGammaCorrect, args.fUserStencilSettings);
778*c8dee2aaSAndroid Build Coastguard Worker     args.fSurfaceDrawContext->addDrawOp(args.fClip, std::move(op));
779*c8dee2aaSAndroid Build Coastguard Worker 
780*c8dee2aaSAndroid Build Coastguard Worker     return true;
781*c8dee2aaSAndroid Build Coastguard Worker }
782*c8dee2aaSAndroid Build Coastguard Worker 
783*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skgpu::ganesh
784*c8dee2aaSAndroid Build Coastguard Worker 
785*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
786*c8dee2aaSAndroid Build Coastguard Worker 
GR_DRAW_OP_TEST_DEFINE(SmallPathOp)787*c8dee2aaSAndroid Build Coastguard Worker GR_DRAW_OP_TEST_DEFINE(SmallPathOp) {
788*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix viewMatrix = GrTest::TestMatrix(random);
789*c8dee2aaSAndroid Build Coastguard Worker     bool gammaCorrect = random->nextBool();
790*c8dee2aaSAndroid Build Coastguard Worker 
791*c8dee2aaSAndroid Build Coastguard Worker     // This path renderer only allows fill styles.
792*c8dee2aaSAndroid Build Coastguard Worker     GrStyledShape shape(GrTest::TestPath(random), GrStyle::SimpleFill());
793*c8dee2aaSAndroid Build Coastguard Worker     return skgpu::ganesh::SmallPathOp::Make(context,
794*c8dee2aaSAndroid Build Coastguard Worker                                             std::move(paint),
795*c8dee2aaSAndroid Build Coastguard Worker                                             shape,
796*c8dee2aaSAndroid Build Coastguard Worker                                             viewMatrix,
797*c8dee2aaSAndroid Build Coastguard Worker                                             gammaCorrect,
798*c8dee2aaSAndroid Build Coastguard Worker                                             GrGetRandomStencil(random, context));
799*c8dee2aaSAndroid Build Coastguard Worker }
800*c8dee2aaSAndroid Build Coastguard Worker 
801*c8dee2aaSAndroid Build Coastguard Worker #endif // defined(GPU_TEST_UTILS)
802*c8dee2aaSAndroid Build Coastguard Worker 
803*c8dee2aaSAndroid Build Coastguard Worker #endif // SK_ENABLE_OPTIMIZE_SIZE
804