xref: /aosp_15_r20/external/skia/src/text/gpu/SubRunContainer.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2 * Copyright 2022 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 sktext_gpu_SubRunContainer_DEFINED
9 #define sktext_gpu_SubRunContainer_DEFINED
10 
11 #include "include/core/SkMatrix.h"
12 #include "include/core/SkRefCnt.h"
13 #include "include/core/SkSpan.h"
14 #include "src/text/gpu/SubRunAllocator.h"
15 
16 #include <cstddef>
17 #include <functional>
18 #include <iterator>
19 #include <memory>
20 #include <tuple>
21 #include <utility>
22 
23 class SkCanvas;
24 class SkPaint;
25 class SkReadBuffer;
26 class SkStrikeClient;
27 class SkWriteBuffer;
28 struct SkPoint;
29 struct SkStrikeDeviceInfo;
30 
31 namespace sktext {
32 class GlyphRunList;
33 class StrikeForGPUCacheInterface;
34 }
35 
36 namespace skgpu {
37 enum class MaskFormat : int;
38 }
39 
40 #if defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS)
41 #include "src/gpu/ganesh/GrColor.h"
42 #include "src/gpu/ganesh/ops/GrOp.h"
43 
44 class GrClip;
45 struct SkIRect;
46 namespace skgpu::ganesh {
47 class SurfaceDrawContext;
48 }
49 #endif
50 
51 namespace sktext::gpu {
52 class GlyphVector;
53 class Glyph;
54 class StrikeCache;
55 class VertexFiller;
56 
57 using RegenerateAtlasDelegate = std::function<std::tuple<bool, int>(GlyphVector*,
58                                                                     int begin,
59                                                                     int end,
60                                                                     skgpu::MaskFormat,
61                                                                     int padding)>;
62 
63 struct RendererData {
64     bool isSDF = false;
65     bool isLCD = false;
66     skgpu::MaskFormat maskFormat;
67 };
68 
69 // -- AtlasSubRun --------------------------------------------------------------------------------
70 // AtlasSubRun is the API that AtlasTextOp uses to generate vertex data for drawing.
71 //     There are three different ways AtlasSubRun is specialized.
72 //      * DirectMaskSubRun* - this is by far the most common type of SubRun. The mask pixels are
73 //        in 1:1 correspondence with the pixels on the device. The destination rectangles in this
74 //        SubRun are in device space. This SubRun handles color glyphs.
75 //      * TransformedMaskSubRun* - handles glyph where the image in the atlas needs to be
76 //        transformed to the screen. It is usually used for large color glyph which can't be
77 //        drawn with paths or scaled distance fields, but will be used to draw bitmap glyphs to
78 //        the screen, if the matrix does not map 1:1 to the screen. The destination rectangles
79 //        are in source space.
80 //      * SDFTSubRun* - scaled distance field text handles largish single color glyphs that still
81 //        can fit in the atlas; the sizes between direct SubRun, and path SubRun. The destination
82 //        rectangles are in source space.
83 class AtlasSubRun {
84 public:
85     virtual ~AtlasSubRun() = default;
86 
87     virtual SkSpan<const Glyph*> glyphs() const = 0;
88     virtual int glyphCount() const = 0;
89     virtual skgpu::MaskFormat maskFormat() const = 0;
90     virtual int glyphSrcPadding() const = 0;
91     virtual unsigned short instanceFlags() const = 0;
92 
93 #if defined(SK_GANESH) || defined(SK_USE_LEGACY_GANESH_TEXT_APIS)
94     virtual size_t vertexStride(const SkMatrix& drawMatrix) const = 0;
95 
96     virtual std::tuple<const GrClip*, GrOp::Owner> makeAtlasTextOp(
97             const GrClip*,
98             const SkMatrix& viewMatrix,
99             SkPoint drawOrigin,
100             const SkPaint&,
101             sk_sp<SkRefCnt>&& subRunStorage,
102             skgpu::ganesh::SurfaceDrawContext*) const = 0;
103 
104     virtual void fillVertexData(
105             void* vertexDst, int offset, int count,
106             GrColor color,
107             const SkMatrix& drawMatrix,
108             SkPoint drawOrigin,
109             SkIRect clip) const = 0;
110 #endif
111     // This call is not thread safe. It should only be called from a known single-threaded env.
112     virtual std::tuple<bool, int> regenerateAtlas(
113             int begin, int end, RegenerateAtlasDelegate) const = 0;
114 
115     virtual const VertexFiller& vertexFiller() const = 0;
116 
117     virtual void testingOnly_packedGlyphIDToGlyph(StrikeCache* cache) const = 0;
118 };
119 
120 using AtlasDrawDelegate = std::function<void(const sktext::gpu::AtlasSubRun* subRun,
121                                              SkPoint drawOrigin,
122                                              const SkPaint& paint,
123                                              sk_sp<SkRefCnt> subRunStorage,
124                                              sktext::gpu::RendererData)>;
125 
126 // -- SubRun -------------------------------------------------------------------------------------
127 // SubRun defines the most basic functionality of a SubRun; the ability to draw, and the
128 // ability to be in a list.
129 class SubRun;
130 using SubRunOwner = std::unique_ptr<SubRun, SubRunAllocator::Destroyer>;
131 class SubRun {
132 public:
133     virtual ~SubRun();
134 
135     virtual void draw(SkCanvas*, SkPoint drawOrigin, const SkPaint&, sk_sp<SkRefCnt> subRunStorage,
136                       const AtlasDrawDelegate&) const = 0;
137 
138     void flatten(SkWriteBuffer& buffer) const;
139     static SubRunOwner MakeFromBuffer(SkReadBuffer& buffer,
140                                       sktext::gpu::SubRunAllocator* alloc,
141                                       const SkStrikeClient* client);
142 
143     // Size hint for unflattening this run. If this is accurate, it will help with the allocation
144     // of the slug. If it's off then there may be more allocations needed to unflatten.
145     virtual int unflattenSize() const = 0;
146 
147     // Given an already cached subRun, can this subRun handle this combination paint, matrix, and
148     // position.
149     virtual bool canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const = 0;
150 
151     // Return the underlying atlas SubRun if it exists. Otherwise, return nullptr.
152     // * Don't use this API. It is only to support testing.
153     virtual const AtlasSubRun* testingOnly_atlasSubRun() const = 0;
154 
155 protected:
156     enum SubRunStreamTag : int;
157     virtual SubRunStreamTag subRunStreamTag() const = 0;
158     virtual void doFlatten(SkWriteBuffer& buffer) const = 0;
159 
160 private:
161     friend class SubRunList;
162     SubRunOwner fNext;
163 };
164 
165 // -- SubRunList -----------------------------------------------------------------------------------
166 class SubRunList {
167 public:
168     class Iterator {
169     public:
170         using value_type = SubRun;
171         using difference_type = ptrdiff_t;
172         using pointer = value_type*;
173         using reference = value_type&;
174         using iterator_category = std::input_iterator_tag;
Iterator(SubRun * subRun)175         Iterator(SubRun* subRun) : fPtr{subRun} { }
176         Iterator& operator++() { fPtr = fPtr->fNext.get(); return *this; }
177         Iterator operator++(int) { Iterator tmp(*this); operator++(); return tmp; }
178         bool operator==(const Iterator& rhs) const { return fPtr == rhs.fPtr; }
179         bool operator!=(const Iterator& rhs) const { return fPtr != rhs.fPtr; }
180         reference operator*() { return *fPtr; }
181 
182     private:
183         SubRun* fPtr;
184     };
185 
append(SubRunOwner subRun)186     void append(SubRunOwner subRun) {
187         SubRunOwner* newTail = &subRun->fNext;
188         *fTail = std::move(subRun);
189         fTail = newTail;
190     }
isEmpty()191     bool isEmpty() const { return fHead == nullptr; }
begin()192     Iterator begin() { return Iterator{ fHead.get()}; }
end()193     Iterator end() { return Iterator{nullptr}; }
begin()194     Iterator begin() const { return Iterator{ fHead.get()}; }
end()195     Iterator end() const { return Iterator{nullptr}; }
front()196     SubRun& front() const {return *fHead; }
197 
198 private:
199     SubRunOwner fHead{nullptr};
200     SubRunOwner* fTail{&fHead};
201 };
202 
203 // -- SubRunContainer ------------------------------------------------------------------------------
204 class SubRunContainer;
205 using SubRunContainerOwner = std::unique_ptr<SubRunContainer, SubRunAllocator::Destroyer>;
206 class SubRunContainer {
207 public:
208     explicit SubRunContainer(const SkMatrix& initialPositionMatrix);
209     SubRunContainer() = delete;
210     SubRunContainer(const SubRunContainer&) = delete;
211     SubRunContainer& operator=(const SubRunContainer&) = delete;
212 
213     // Delete the move operations because the SubRuns contain pointers to fInitialPositionMatrix.
214     SubRunContainer(SubRunContainer&&) = delete;
215     SubRunContainer& operator=(SubRunContainer&&) = delete;
216 
217     void flattenAllocSizeHint(SkWriteBuffer& buffer) const;
218     static int AllocSizeHintFromBuffer(SkReadBuffer& buffer);
219 
220     void flattenRuns(SkWriteBuffer& buffer) const;
221     static SubRunContainerOwner MakeFromBufferInAlloc(SkReadBuffer& buffer,
222                                                       const SkStrikeClient* client,
223                                                       SubRunAllocator* alloc);
224 
225     enum SubRunCreationBehavior {kAddSubRuns, kStrikeCalculationsOnly};
226     // The returned SubRunContainerOwner will never be null. If subRunCreation ==
227     // kStrikeCalculationsOnly, then the returned container will be empty.
228     [[nodiscard]] static SubRunContainerOwner MakeInAlloc(const GlyphRunList& glyphRunList,
229                                                           const SkMatrix& positionMatrix,
230                                                           const SkPaint& runPaint,
231                                                           SkStrikeDeviceInfo strikeDeviceInfo,
232                                                           StrikeForGPUCacheInterface* strikeCache,
233                                                           sktext::gpu::SubRunAllocator* alloc,
234                                                           SubRunCreationBehavior creationBehavior,
235                                                           const char* tag);
236 
237     static size_t EstimateAllocSize(const GlyphRunList& glyphRunList);
238 
239     void draw(SkCanvas*, SkPoint drawOrigin, const SkPaint&, const SkRefCnt* subRunStorage,
240               const AtlasDrawDelegate&) const;
241 
initialPosition()242     const SkMatrix& initialPosition() const { return fInitialPositionMatrix; }
isEmpty()243     bool isEmpty() const { return fSubRuns.isEmpty(); }
244     bool canReuse(const SkPaint& paint, const SkMatrix& positionMatrix) const;
245 
246 private:
247     friend class TextBlobTools;
248     const SkMatrix fInitialPositionMatrix;
249     SubRunList fSubRuns;
250 };
251 
252 // Returns the empty span if there is a problem reading the positions.
253 SkSpan<SkPoint> MakePointsFromBuffer(SkReadBuffer&, SubRunAllocator*);
254 
255 }  // namespace sktext::gpu
256 
257 #endif  // sktext_gpu_SubRunContainer_DEFINED
258