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