xref: /aosp_15_r20/external/skia/src/gpu/ganesh/ops/AtlasPathRenderer.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2  * Copyright 2019 Google LLC.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef AtlasPathRenderer_DEFINED
9 #define AtlasPathRenderer_DEFINED
10 
11 #include "include/core/SkRefCnt.h"
12 #include "include/private/base/SkTArray.h"
13 #include "src/core/SkChecksum.h"
14 #include "src/core/SkIPoint16.h"
15 #include "src/core/SkTHash.h"
16 #include "src/gpu/ganesh/GrFragmentProcessor.h"
17 #include "src/gpu/ganesh/GrOnFlushResourceProvider.h"
18 #include "src/gpu/ganesh/PathRenderer.h"
19 #include "src/gpu/ganesh/ops/AtlasRenderTask.h"
20 
21 #include <cstdint>
22 #include <cstring>
23 #include <functional>
24 #include <memory>
25 
26 class GrDirectContext;
27 class GrOp;
28 class GrRecordingContext;
29 class GrStyledShape;
30 class GrSurfaceProxy;
31 class SkMatrix;
32 class SkPath;
33 enum class GrAAType : unsigned int;
34 struct SkIRect;
35 struct SkRect;
36 
37 namespace skgpu::ganesh {
38 
39 class SurfaceDrawContext;
40 
41 // Draws paths by first rendering their coverage mask into an offscreen atlas.
42 class AtlasPathRenderer final : public PathRenderer, public GrOnFlushCallbackObject {
43 public:
44     static bool IsSupported(GrRecordingContext*);
45 
46     // Returns a GrAtlasPathRenderer if it is supported, otherwise null.
47     static sk_sp<AtlasPathRenderer> Make(GrRecordingContext* rContext);
48 
name()49     const char* name() const override { return "GrAtlasPathRenderer"; }
50 
51     // Returns a fragment processor that modulates inputFP by the given deviceSpacePath's coverage,
52     // implemented using an internal atlas.
53     //
54     // Returns 'inputFP' wrapped in GrFPFailure() if the path was too large, or if the current atlas
55     // is full and already used by either opBeingClipped or inputFP. (Currently, "too large" means
56     // larger than fMaxAtlasSize in either dimension, more than 256^2 total pixels, or more than
57     // 128^2 total pixels if the surfaceDrawContext supports MSAA or DMSAA.)
58     //
59     // Also returns GrFPFailure() if the view matrix has perspective.
60     GrFPResult makeAtlasClipEffect(const skgpu::ganesh::SurfaceDrawContext*,
61                                    const GrOp* opBeingClipped,
62                                    std::unique_ptr<GrFragmentProcessor> inputFP,
63                                    const SkIRect& drawBounds,
64                                    const SkMatrix&,
65                                    const SkPath&);
66 
67 private:
68     // The atlas is not compatible with DDL. We can only use it on direct contexts.
69     AtlasPathRenderer(GrDirectContext*);
70 
onGetStencilSupport(const GrStyledShape &)71     StencilSupport onGetStencilSupport(const GrStyledShape&) const override {
72         return kNoSupport_StencilSupport;
73     }
74 
75     CanDrawPath onCanDrawPath(const CanDrawPathArgs&) const override;
76 
77     bool onDrawPath(const DrawPathArgs&) override;
78 
79     // Returns true if the given device-space path bounds are small enough to fit in an atlas and to
80     // benefit from atlasing. (Currently, "small enough" means no larger than fMaxAtlasSize in
81     // either dimension, no more than 256^2 total pixels, or no more than 128^2 total pixels if the
82     // fallbackAAType is kMSAA.)
83     bool pathFitsInAtlas(const SkRect& pathDevBounds, GrAAType fallbackAAType) const;
84 
85     // Returns true if the draw being set up already uses the given atlasProxy.
86     using DrawRefsAtlasCallback = std::function<bool(const GrSurfaceProxy* atlasProxy)>;
87 
88     // Adds the filled path to an atlas.
89     //
90     // pathFitsInAtlas() and is_visible() both must have returned true before making this call.
91     //
92     // Fails and returns false if the current atlas is full and already in use according to
93     // DrawRefsAtlasCallback.
94     bool addPathToAtlas(GrRecordingContext*,
95                         const SkMatrix&,
96                         const SkPath&,
97                         const SkRect& pathDevBounds,
98                         SkIRect* devIBounds,
99                         SkIPoint16* locationInAtlas,
100                         bool* transposedInAtlas,
101                         const DrawRefsAtlasCallback&);
102 
103     // Instantiates texture(s) for all atlases we've created since the last flush. Atlases that are
104     // the same size will be instantiated with the same backing texture.
105     bool preFlush(GrOnFlushResourceProvider*) override;
106 
107     float fAtlasMaxSize = 0;
108     float fAtlasMaxPathWidth = 0;
109     int fAtlasInitialSize = 0;
110 
111     // A collection of all atlases we've created and used since the last flush. We instantiate these
112     // at flush time during preFlush().
113     skia_private::STArray<4, sk_sp<AtlasRenderTask>> fAtlasRenderTasks;
114 
115     // This simple cache remembers the locations of cacheable path masks in the most recent atlas.
116     // Its main motivation is for clip paths.
117     struct AtlasPathKey {
118         void set(const SkMatrix&, const SkPath&);
119         bool operator==(const AtlasPathKey& k) const {
120             static_assert(sizeof(*this) == sizeof(uint32_t) * 8);
121             return !memcmp(this, &k, sizeof(*this));
122         }
123         uint32_t fPathGenID;
124         float fAffineMatrix[6];
125         uint32_t fFillRule;
126 
127         using Hash = SkForceDirectHash<AtlasPathKey>;
128     };
129 
130     skia_private::THashMap<AtlasPathKey, SkIPoint16, AtlasPathKey::Hash> fAtlasPathCache;
131 };
132 
133 }  // namespace skgpu::ganesh
134 
135 #endif // GrAtlasPathRenderer_DEFINED
136