1 | /* |
2 | * Copyright 2015 Google Inc. |
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 GrTextBlob_DEFINED |
9 | #define GrTextBlob_DEFINED |
10 | |
11 | #include <limits> |
12 | |
13 | #include "include/core/SkPoint3.h" |
14 | #include "include/core/SkRefCnt.h" |
15 | #include "src/core/SkGlyphRunPainter.h" |
16 | #include "src/core/SkIPoint16.h" |
17 | #include "src/core/SkMaskFilterBase.h" |
18 | #include "src/core/SkOpts.h" |
19 | #include "src/core/SkRectPriv.h" |
20 | #include "src/core/SkStrikeSpec.h" |
21 | #include "src/core/SkTLazy.h" |
22 | #include "src/gpu/GrColor.h" |
23 | #include "src/gpu/GrDrawOpAtlas.h" |
24 | #include "src/gpu/ops/GrMeshDrawOp.h" |
25 | #include "src/gpu/text/GrStrikeCache.h" |
26 | |
27 | class GrAtlasManager; |
28 | class GrAtlasTextOp; |
29 | class GrDeferredUploadTarget; |
30 | class GrDrawOp; |
31 | class GrGlyph; |
32 | class GrStrikeCache; |
33 | class GrSubRun; |
34 | |
35 | class SkMatrixProvider; |
36 | class SkSurfaceProps; |
37 | class SkTextBlob; |
38 | class SkTextBlobRunIterator; |
39 | |
40 | |
41 | // A GrTextBlob contains a fully processed SkTextBlob, suitable for nearly immediate drawing |
42 | // on the GPU. These are initially created with valid positions and colors, but invalid |
43 | // texture coordinates. |
44 | // |
45 | // A GrTextBlob contains a number of SubRuns that are created in the blob's arena. Each SubRun |
46 | // tracks its own GrGlyph* and vertex data. The memory is organized in the arena in the following |
47 | // way so that the pointers for the GrGlyph* and vertex data are known before creating the SubRun. |
48 | // |
49 | // GrGlyph*... | vertexData... | SubRun | GrGlyph*... | vertexData... | SubRun etc. |
50 | // |
51 | // In these classes, I'm trying to follow the convention about matrices and origins. |
52 | // * draw Matrix|Origin - describes the current draw command. |
53 | // * initial Matrix|Origin - describes the matrix and origin the GrTextBlob was created with. |
54 | // * current Matrix|Origin - describes the matrix and origin that are currently in the SubRun's |
55 | // vertex data. |
56 | // |
57 | // |
58 | class GrTextBlob final : public SkNVRefCnt<GrTextBlob>, public SkGlyphRunPainterInterface { |
59 | public: |
60 | struct Key { |
61 | Key(); |
62 | uint32_t fUniqueID; |
63 | // Color may affect the gamma of the mask we generate, but in a fairly limited way. |
64 | // Each color is assigned to on of a fixed number of buckets based on its |
65 | // luminance. For each luminance bucket there is a "canonical color" that |
66 | // represents the bucket. This functionality is currently only supported for A8 |
67 | SkColor fCanonicalColor; |
68 | SkPaint::Style fStyle; |
69 | SkPixelGeometry fPixelGeometry; |
70 | bool fHasBlur; |
71 | uint32_t fScalerContextFlags; |
72 | |
73 | bool operator==(const Key& other) const; |
74 | }; |
75 | |
76 | SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrTextBlob); |
77 | |
78 | // Change memory management to handle the data after GrTextBlob, but in the same allocation |
79 | // of memory. Only allow placement new. |
80 | void operator delete(void* p); |
81 | void* operator new(size_t); |
82 | void* operator new(size_t, void* p); |
83 | |
84 | ~GrTextBlob() override; |
85 | |
86 | // Make an empty GrTextBlob, with all the invariants set to make the right decisions when |
87 | // adding SubRuns. |
88 | static sk_sp<GrTextBlob> Make(const SkGlyphRunList& glyphRunList, |
89 | const SkMatrix& drawMatrix); |
90 | |
91 | // Key manipulation functions |
92 | void setupKey(const GrTextBlob::Key& key, |
93 | const SkMaskFilterBase::BlurRec& blurRec, |
94 | const SkPaint& paint); |
95 | static const Key& GetKey(const GrTextBlob& blob); |
96 | static uint32_t Hash(const Key& key); |
97 | |
98 | bool hasDistanceField() const; |
99 | bool hasBitmap() const; |
100 | bool hasPerspective() const; |
101 | |
102 | void setHasDistanceField(); |
103 | void setHasBitmap(); |
104 | void setMinAndMaxScale(SkScalar scaledMin, SkScalar scaledMax); |
105 | |
106 | bool canReuse(const SkPaint& paint, const SkMaskFilterBase::BlurRec& blurRec, |
107 | const SkMatrix& drawMatrix, SkPoint drawOrigin); |
108 | |
109 | const Key& key() const; |
110 | size_t size() const; |
111 | |
112 | template<typename AddSingleMaskFormat> |
113 | void addMultiMaskFormat( |
114 | AddSingleMaskFormat addSingle, |
115 | const SkZip<SkGlyphVariant, SkPoint>& drawables, |
116 | const SkStrikeSpec& strikeSpec, |
117 | SkPoint residual); |
118 | |
119 | const SkTInternalLList<GrSubRun>& subRunList() const { return fSubRunList; } |
120 | |
121 | private: |
122 | enum TextType { |
123 | kHasDistanceField_TextType = 0x1, |
124 | kHasBitmap_TextType = 0x2, |
125 | }; |
126 | |
127 | struct StrokeInfo { |
128 | SkScalar fFrameWidth; |
129 | SkScalar fMiterLimit; |
130 | SkPaint::Join fJoin; |
131 | }; |
132 | |
133 | GrTextBlob(size_t allocSize, |
134 | const SkMatrix& drawMatrix, |
135 | SkPoint origin, |
136 | SkColor initialLuminance); |
137 | |
138 | void insertSubRun(GrSubRun* subRun); |
139 | |
140 | // Methods to satisfy SkGlyphRunPainterInterface |
141 | void processDeviceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables, |
142 | const SkStrikeSpec& strikeSpec, |
143 | SkPoint residual) override; |
144 | void processSourcePaths(const SkZip<SkGlyphVariant, SkPoint>& drawables, |
145 | const SkFont& runFont, |
146 | const SkStrikeSpec& strikeSpec) override; |
147 | void processSourceSDFT(const SkZip<SkGlyphVariant, SkPoint>& drawables, |
148 | const SkStrikeSpec& strikeSpec, |
149 | const SkFont& runFont, |
150 | SkScalar minScale, |
151 | SkScalar maxScale) override; |
152 | void processSourceMasks(const SkZip<SkGlyphVariant, SkPoint>& drawables, |
153 | const SkStrikeSpec& strikeSpec) override; |
154 | |
155 | // Overall size of this struct plus vertices and glyphs at the end. |
156 | const size_t fSize; |
157 | |
158 | // The initial view matrix. This is used for moving additional draws of this |
159 | // same text blob. We record the initial view matrix and initial offsets(x,y), because we |
160 | // record vertex bounds relative to these numbers. When blobs are reused with new matrices, |
161 | // we need to return to source space so we can update the vertex bounds appropriately. |
162 | const SkMatrix fInitialMatrix; |
163 | |
164 | // Initial position of this blob. Used for calculating position differences when reusing this |
165 | // blob. |
166 | const SkPoint fInitialOrigin; |
167 | |
168 | const SkColor fInitialLuminance; |
169 | |
170 | SkMaskFilterBase::BlurRec fBlurRec; |
171 | StrokeInfo fStrokeInfo; |
172 | Key fKey; |
173 | |
174 | // We can reuse distance field text, but only if the new view matrix would not result in |
175 | // a mip change. Because there can be multiple runs in a blob, we track the overall |
176 | // maximum minimum scale, and minimum maximum scale, we can support before we need to regen |
177 | SkScalar fMaxMinScale{-SK_ScalarMax}; |
178 | SkScalar fMinMaxScale{SK_ScalarMax}; |
179 | |
180 | uint8_t fTextType{0}; |
181 | |
182 | SkTInternalLList<GrSubRun> fSubRunList; |
183 | SkArenaAlloc fAlloc; |
184 | }; |
185 | |
186 | // -- GrSubRun ------------------------------------------------------------------------------------- |
187 | class GrSubRun { |
188 | public: |
189 | virtual ~GrSubRun() = default; |
190 | virtual void draw(const GrClip* clip, |
191 | const SkMatrixProvider& viewMatrix, |
192 | const SkGlyphRunList& glyphRunList, |
193 | GrRenderTargetContext* rtc) const = 0; |
194 | |
195 | private: |
196 | SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrSubRun); |
197 | }; |
198 | |
199 | // -- GrPathSubRun --------------------------------------------------------------------------------- |
200 | class GrPathSubRun final : public GrSubRun { |
201 | struct PathGlyph; |
202 | |
203 | public: |
204 | GrPathSubRun(bool isAntiAliased, const SkStrikeSpec& strikeSpec, SkSpan<PathGlyph> paths); |
205 | |
206 | void draw(const GrClip* clip, |
207 | const SkMatrixProvider& viewMatrix, |
208 | const SkGlyphRunList& glyphRunList, |
209 | GrRenderTargetContext* rtc) const override; |
210 | |
211 | static GrSubRun* Make(const SkZip<SkGlyphVariant, SkPoint>& drawables, |
212 | bool isAntiAliased, |
213 | const SkStrikeSpec& strikeSpec, |
214 | SkArenaAlloc* alloc); |
215 | |
216 | private: |
217 | struct PathGlyph { |
218 | PathGlyph(const SkPath& path, SkPoint origin); |
219 | SkPath fPath; |
220 | SkPoint fOrigin; |
221 | }; |
222 | |
223 | const bool fIsAntiAliased; |
224 | const SkStrikeSpec fStrikeSpec; |
225 | const SkSpan<const PathGlyph> fPaths; |
226 | }; |
227 | |
228 | // -- GrAtlasSubRun -------------------------------------------------------------------------------- |
229 | class GrAtlasSubRun : public GrSubRun { |
230 | public: |
231 | static constexpr int kVerticesPerGlyph = 4; |
232 | virtual size_t vertexStride() const = 0; |
233 | virtual int glyphCount() const = 0; |
234 | |
235 | virtual std::tuple<const GrClip*, std::unique_ptr<GrDrawOp>> |
236 | makeAtlasTextOp(const GrClip* clip, |
237 | const SkMatrixProvider& viewMatrix, |
238 | const SkGlyphRunList& glyphRunList, |
239 | GrRenderTargetContext* rtc) const = 0; |
240 | virtual void fillVertexData( |
241 | void* vertexDst, int offset, int count, |
242 | GrColor color, const SkMatrix& drawMatrix, SkPoint drawOrigin, |
243 | SkIRect clip) const = 0; |
244 | |
245 | virtual void testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache* cache) = 0; |
246 | |
247 | // This call is not thread safe. It should only be called from GrDrawOp::onPrepare which |
248 | // is single threaded. |
249 | virtual std::tuple<bool, int> regenerateAtlas( |
250 | int begin, int end, GrMeshDrawOp::Target* target) const = 0; |
251 | |
252 | protected: |
253 | struct AtlasPt { |
254 | uint16_t u; |
255 | uint16_t v; |
256 | }; |
257 | |
258 | // Normal text mask, SDFT, or color. |
259 | struct Mask2DVertex { |
260 | SkPoint devicePos; |
261 | GrColor color; |
262 | AtlasPt atlasPos; |
263 | }; |
264 | struct ARGB2DVertex { |
265 | ARGB2DVertex(SkPoint d, GrColor, AtlasPt a) : devicePos{d}, atlasPos{a} {} |
266 | SkPoint devicePos; |
267 | AtlasPt atlasPos; |
268 | }; |
269 | |
270 | // Perspective SDFT or SDFT forced to 3D or perspective color. |
271 | struct Mask3DVertex { |
272 | SkPoint3 devicePos; |
273 | GrColor color; |
274 | AtlasPt atlasPos; |
275 | }; |
276 | struct ARGB3DVertex { |
277 | ARGB3DVertex(SkPoint3 d, GrColor, AtlasPt a) : devicePos{d}, atlasPos{a} {} |
278 | SkPoint3 devicePos; |
279 | AtlasPt atlasPos; |
280 | }; |
281 | }; |
282 | |
283 | // -- GrGlyphVector -------------------------------------------------------------------------------- |
284 | class GrGlyphVector { |
285 | union Variant { |
286 | // Initially, filled with packed id, but changed to GrGlyph* in the onPrepare stage. |
287 | SkPackedGlyphID packedGlyphID; |
288 | GrGlyph* grGlyph; |
289 | }; |
290 | |
291 | public: |
292 | static GrGlyphVector Make( |
293 | const SkStrikeSpec& spec, SkSpan<SkGlyphVariant> glyphs, SkArenaAlloc* alloc); |
294 | SkSpan<const GrGlyph*> glyphs() const; |
295 | |
296 | SkScalar strikeToSourceRatio() const { return fStrikeSpec.strikeToSourceRatio(); } |
297 | |
298 | void packedGlyphIDToGrGlyph(GrStrikeCache* cache); |
299 | |
300 | std::tuple<bool, int> regenerateAtlas( |
301 | int begin, int end, |
302 | GrMaskFormat maskFormat, |
303 | int srcPadding, |
304 | GrMeshDrawOp::Target *target, |
305 | bool bilerpPadding = false); |
306 | |
307 | static size_t GlyphVectorSize(size_t count) { |
308 | return sizeof(Variant) * count; |
309 | } |
310 | |
311 | private: |
312 | GrGlyphVector(const SkStrikeSpec& spec, SkSpan<Variant> glyphs); |
313 | |
314 | const SkStrikeSpec fStrikeSpec; |
315 | SkSpan<Variant> fGlyphs; |
316 | sk_sp<GrTextStrike> fStrike{nullptr}; |
317 | uint64_t fAtlasGeneration{GrDrawOpAtlas::kInvalidAtlasGeneration}; |
318 | GrDrawOpAtlas::BulkUseTokenUpdater fBulkUseToken; |
319 | }; |
320 | |
321 | // -- GrDirectMaskSubRun --------------------------------------------------------------------------- |
322 | class GrDirectMaskSubRun final : public GrAtlasSubRun { |
323 | public: |
324 | using VertexData = SkIPoint; |
325 | |
326 | GrDirectMaskSubRun(GrMaskFormat format, |
327 | SkPoint residual, |
328 | GrTextBlob* blob, |
329 | const SkRect& bounds, |
330 | SkSpan<const VertexData> vertexData, |
331 | GrGlyphVector glyphs); |
332 | |
333 | static GrSubRun* Make(const SkZip<SkGlyphVariant, SkPoint>& drawables, |
334 | const SkStrikeSpec& strikeSpec, |
335 | GrMaskFormat format, |
336 | SkPoint residual, |
337 | GrTextBlob* blob, |
338 | SkArenaAlloc* alloc); |
339 | |
340 | void draw(const GrClip* clip, |
341 | const SkMatrixProvider& viewMatrix, |
342 | const SkGlyphRunList& glyphRunList, |
343 | GrRenderTargetContext* rtc) const override; |
344 | |
345 | size_t vertexStride() const override; |
346 | |
347 | int glyphCount() const override; |
348 | |
349 | std::tuple<const GrClip*, std::unique_ptr<GrDrawOp>> |
350 | makeAtlasTextOp(const GrClip* clip, |
351 | const SkMatrixProvider& viewMatrix, |
352 | const SkGlyphRunList& glyphRunList, |
353 | GrRenderTargetContext* rtc) const override; |
354 | |
355 | void testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) override; |
356 | |
357 | std::tuple<bool, int> |
358 | regenerateAtlas(int begin, int end, GrMeshDrawOp::Target* target) const override; |
359 | |
360 | void fillVertexData(void* vertexDst, int offset, int count, GrColor color, |
361 | const SkMatrix& drawMatrix, SkPoint drawOrigin, |
362 | SkIRect clip) const override; |
363 | private: |
364 | |
365 | // The rectangle that surrounds all the glyph bounding boxes in device space. |
366 | SkRect deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const; |
367 | |
368 | const GrMaskFormat fMaskFormat; |
369 | const SkPoint fResidual; |
370 | GrTextBlob* const fBlob; |
371 | // The vertex bounds in device space. The bounds are the joined rectangles of all the glyphs. |
372 | const SkRect fVertexBounds; |
373 | const SkSpan<const VertexData> fVertexData; |
374 | |
375 | // The regenerateAtlas method mutates fGlyphs. It should be called from onPrepare which must |
376 | // be single threaded. |
377 | mutable GrGlyphVector fGlyphs; |
378 | }; |
379 | |
380 | // -- GrTransformedMaskSubRun ---------------------------------------------------------------------- |
381 | class GrTransformedMaskSubRun final : public GrAtlasSubRun { |
382 | public: |
383 | struct VertexData { |
384 | const SkPoint pos; |
385 | // The rectangle of the glyphs in strike space. But, for kDirectMask this also implies a |
386 | // device space rect. |
387 | GrIRect16 rect; |
388 | }; |
389 | |
390 | // SubRun for masks |
391 | GrTransformedMaskSubRun(GrMaskFormat format, |
392 | GrTextBlob* blob, |
393 | const SkRect& bounds, |
394 | SkSpan<const VertexData> vertexData, |
395 | GrGlyphVector glyphs); |
396 | |
397 | static GrSubRun* Make(const SkZip<SkGlyphVariant, SkPoint>& drawables, |
398 | const SkStrikeSpec& strikeSpec, |
399 | GrMaskFormat format, |
400 | SkPoint residual, |
401 | GrTextBlob* blob, |
402 | SkArenaAlloc* alloc); |
403 | |
404 | void draw(const GrClip* clip, |
405 | const SkMatrixProvider& viewMatrix, |
406 | const SkGlyphRunList& glyphRunList, |
407 | GrRenderTargetContext* rtc) const override; |
408 | |
409 | std::tuple<const GrClip*, std::unique_ptr<GrDrawOp>> |
410 | makeAtlasTextOp(const GrClip* clip, |
411 | const SkMatrixProvider& viewMatrix, |
412 | const SkGlyphRunList& glyphRunList, |
413 | GrRenderTargetContext* rtc) const override; |
414 | |
415 | void testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) override; |
416 | |
417 | std::tuple<bool, int> regenerateAtlas( |
418 | int begin, int end, GrMeshDrawOp::Target* target) const override; |
419 | |
420 | void fillVertexData( |
421 | void* vertexDst, int offset, int count, |
422 | GrColor color, const SkMatrix& drawMatrix, SkPoint drawOrigin, |
423 | SkIRect clip) const override; |
424 | |
425 | size_t vertexStride() const override; |
426 | int glyphCount() const override; |
427 | |
428 | private: |
429 | bool hasW() const; |
430 | // The rectangle that surrounds all the glyph bounding boxes in device space. |
431 | SkRect deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const; |
432 | |
433 | const GrMaskFormat fMaskFormat; |
434 | GrTextBlob* fBlob; |
435 | |
436 | // The bounds in source space. The bounds are the joined rectangles of all the glyphs. |
437 | const SkRect fVertexBounds; |
438 | const SkSpan<const VertexData> fVertexData; |
439 | |
440 | // The regenerateAtlas method mutates fGlyphs. It should be called from onPrepare which must |
441 | // be single threaded. |
442 | mutable GrGlyphVector fGlyphs; |
443 | }; |
444 | |
445 | // -- GrSDFTSubRun --------------------------------------------------------------------------------- |
446 | // Hold data to draw Scaled Distance Field Text sub runs. |
447 | class GrSDFTSubRun final : public GrAtlasSubRun { |
448 | public: |
449 | struct VertexData { |
450 | const SkPoint pos; |
451 | // The rectangle of the glyphs in strike space. |
452 | GrIRect16 rect; |
453 | }; |
454 | |
455 | GrSDFTSubRun(GrMaskFormat format, |
456 | GrTextBlob* blob, |
457 | SkRect vertexBounds, |
458 | SkSpan<const VertexData> vertexData, |
459 | GrGlyphVector glyphs, |
460 | bool useLCDText, |
461 | bool antiAliased); |
462 | |
463 | static GrSubRun* Make(const SkZip<SkGlyphVariant, SkPoint>& drawables, |
464 | const SkFont& runFont, |
465 | const SkStrikeSpec& strikeSpec, |
466 | GrTextBlob* blob, |
467 | SkArenaAlloc* alloc); |
468 | |
469 | void draw(const GrClip* clip, |
470 | const SkMatrixProvider& viewMatrix, |
471 | const SkGlyphRunList& glyphRunList, |
472 | GrRenderTargetContext* rtc) const override; |
473 | |
474 | std::tuple<const GrClip*, std::unique_ptr<GrDrawOp>> |
475 | makeAtlasTextOp(const GrClip* clip, |
476 | const SkMatrixProvider& viewMatrix, |
477 | const SkGlyphRunList& glyphRunList, |
478 | GrRenderTargetContext* rtc) const override; |
479 | |
480 | void testingOnly_packedGlyphIDToGrGlyph(GrStrikeCache *cache) override; |
481 | |
482 | std::tuple<bool, int> regenerateAtlas( |
483 | int begin, int end, GrMeshDrawOp::Target* target) const override; |
484 | |
485 | void fillVertexData( |
486 | void* vertexDst, int offset, int count, |
487 | GrColor color, const SkMatrix& drawMatrix, SkPoint drawOrigin, |
488 | SkIRect clip) const override; |
489 | |
490 | size_t vertexStride() const override; |
491 | int glyphCount() const override; |
492 | |
493 | private: |
494 | bool hasW() const; |
495 | |
496 | // The rectangle that surrounds all the glyph bounding boxes in device space. |
497 | SkRect deviceRect(const SkMatrix& drawMatrix, SkPoint drawOrigin) const; |
498 | |
499 | const GrMaskFormat fMaskFormat; |
500 | GrTextBlob* fBlob; |
501 | |
502 | // The bounds in source space. The bounds are the joined rectangles of all the glyphs. |
503 | const SkRect fVertexBounds; |
504 | const SkSpan<const VertexData> fVertexData; |
505 | |
506 | // The regenerateAtlas method mutates fGlyphs. It should be called from onPrepare which must |
507 | // be single threaded. |
508 | mutable GrGlyphVector fGlyphs; |
509 | |
510 | const bool fUseLCDText; |
511 | const bool fAntiAliased; |
512 | }; |
513 | |
514 | #endif // GrTextBlob_DEFINED |
515 | |