blob: 0f995769304864e04eaaddcee790249d7e933136 [file] [log] [blame]
joshualitt374b2f72015-07-21 08:05:03 -07001/*
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 GrAtlasTextBlob_DEFINED
9#define GrAtlasTextBlob_DEFINED
10
11#include "GrBatchAtlas.h"
12#include "GrBatchFontCache.h"
joshualitt259fbf12015-07-21 11:39:34 -070013#include "GrColor.h"
joshualitt2e2202e2015-12-10 11:22:08 -080014#include "GrMemoryPool.h"
joshualitt374b2f72015-07-21 08:05:03 -070015#include "SkDescriptor.h"
16#include "SkMaskFilter.h"
joshualitt259fbf12015-07-21 11:39:34 -070017#include "SkSurfaceProps.h"
joshualitt374b2f72015-07-21 08:05:03 -070018#include "SkTInternalLList.h"
19
joshualitt2e2202e2015-12-10 11:22:08 -080020struct GrDistanceFieldAdjustTable;
21class GrTextContext;
22class SkDrawFilter;
23class SkTextBlob;
24class SkTextBlobRunIterator;
25
joshualitt259fbf12015-07-21 11:39:34 -070026// With this flag enabled, the GrAtlasTextContext will, as a sanity check, regenerate every blob
27// that comes in to verify the integrity of its cache
28//#define CACHE_SANITY_CHECK // VERY SLOW
29
joshualitt374b2f72015-07-21 08:05:03 -070030/*
31 * A GrAtlasTextBlob contains a fully processed SkTextBlob, suitable for nearly immediate drawing
32 * on the GPU. These are initially created with valid positions and colors, but invalid
33 * texture coordinates. The GrAtlasTextBlob itself has a few Blob-wide properties, and also
34 * consists of a number of runs. Runs inside a blob are flushed individually so they can be
35 * reordered.
36 *
37 * The only thing(aside from a memcopy) required to flush a GrAtlasTextBlob is to ensure that
38 * the GrAtlas will not evict anything the Blob needs.
39 *
40 * Note: This struct should really be named GrCachedAtasTextBlob, but that is too verbose.
joshualitt259fbf12015-07-21 11:39:34 -070041 *
42 * *WARNING* If you add new fields to this struct, then you may need to to update AssertEqual
joshualitt374b2f72015-07-21 08:05:03 -070043 */
joshualitt2e2202e2015-12-10 11:22:08 -080044class GrAtlasTextBlob : public SkNVRefCnt<GrAtlasTextBlob> {
45public:
joshualitt374b2f72015-07-21 08:05:03 -070046 SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrAtlasTextBlob);
47
48 /*
49 * Each Run inside of the blob can have its texture coordinates regenerated if required.
50 * To determine if regeneration is necessary, fAtlasGeneration is used. If there have been
51 * any evictions inside of the atlas, then we will simply regenerate Runs. We could track
52 * this at a more fine grained level, but its not clear if this is worth it, as evictions
53 * should be fairly rare.
54 *
55 * One additional point, each run can contain glyphs with any of the three mask formats.
56 * We call these SubRuns. Because a subrun must be a contiguous range, we have to create
57 * a new subrun each time the mask format changes in a run. In theory, a run can have as
58 * many SubRuns as it has glyphs, ie if a run alternates between color emoji and A8. In
59 * practice, the vast majority of runs have only a single subrun.
60 *
61 * Finally, for runs where the entire thing is too large for the GrAtlasTextContext to
62 * handle, we have a bit to mark the run as flusahable via rendering as paths. It is worth
63 * pointing. It would be a bit expensive to figure out ahead of time whether or not a run
64 * can flush in this manner, so we always allocate vertices for the run, regardless of
65 * whether or not it is too large. The benefit of this strategy is that we can always reuse
66 * a blob allocation regardless of viewmatrix changes. We could store positions for these
67 * glyphs. However, its not clear if this is a win because we'd still have to either go the
68 * glyph cache to get the path at flush time, or hold onto the path in the cache, which
69 * would greatly increase the memory of these cached items.
70 */
71 struct Run {
72 Run()
joshualittf9e658b2015-12-09 09:26:44 -080073 : fInitialized(false)
joshualitt374b2f72015-07-21 08:05:03 -070074 , fDrawAsPaths(false) {
75 fVertexBounds.setLargestInverted();
76 // To ensure we always have one subrun, we push back a fresh run here
77 fSubRunInfo.push_back();
78 }
79 struct SubRunInfo {
80 SubRunInfo()
81 : fAtlasGeneration(GrBatchAtlas::kInvalidAtlasGeneration)
82 , fVertexStartIndex(0)
83 , fVertexEndIndex(0)
84 , fGlyphStartIndex(0)
85 , fGlyphEndIndex(0)
joshualittf9e658b2015-12-09 09:26:44 -080086 , fColor(GrColor_ILLEGAL)
jvanverthce79a3a2015-09-10 06:31:38 -070087 , fMaskFormat(kA8_GrMaskFormat)
88 , fDrawAsDistanceFields(false)
89 , fUseLCDText(false) {}
joshualitt7e97b0b2015-07-31 15:18:08 -070090 SubRunInfo(const SubRunInfo& that)
91 : fBulkUseToken(that.fBulkUseToken)
92 , fStrike(SkSafeRef(that.fStrike.get()))
93 , fAtlasGeneration(that.fAtlasGeneration)
94 , fVertexStartIndex(that.fVertexStartIndex)
95 , fVertexEndIndex(that.fVertexEndIndex)
96 , fGlyphStartIndex(that.fGlyphStartIndex)
97 , fGlyphEndIndex(that.fGlyphEndIndex)
joshualittf9e658b2015-12-09 09:26:44 -080098 , fColor(that.fColor)
joshualitt7e97b0b2015-07-31 15:18:08 -070099 , fMaskFormat(that.fMaskFormat)
100 , fDrawAsDistanceFields(that.fDrawAsDistanceFields)
101 , fUseLCDText(that.fUseLCDText) {
102 }
joshualitt3660d532015-12-07 11:32:50 -0800103
joshualitt18b072d2015-12-07 12:26:12 -0800104 // TODO when this object is more internal, drop the privacy
joshualitt3660d532015-12-07 11:32:50 -0800105 void resetBulkUseToken() { fBulkUseToken.reset(); }
106 GrBatchAtlas::BulkUseTokenUpdater* bulkUseToken() { return &fBulkUseToken; }
107 void setStrike(GrBatchTextStrike* strike) { fStrike.reset(SkRef(strike)); }
108 GrBatchTextStrike* strike() const { return fStrike.get(); }
109
110 void setAtlasGeneration(uint64_t atlasGeneration) { fAtlasGeneration = atlasGeneration;}
111 uint64_t atlasGeneration() const { return fAtlasGeneration; }
112
113 size_t byteCount() const { return fVertexEndIndex - fVertexStartIndex; }
joshualitt3660d532015-12-07 11:32:50 -0800114 size_t vertexStartIndex() const { return fVertexStartIndex; }
joshualitt3660d532015-12-07 11:32:50 -0800115 size_t vertexEndIndex() const { return fVertexEndIndex; }
116 void appendVertices(size_t vertexStride) {
117 fVertexEndIndex += vertexStride * kVerticesPerGlyph;
118 }
119
120 uint32_t glyphCount() const { return fGlyphEndIndex - fGlyphStartIndex; }
joshualitt3660d532015-12-07 11:32:50 -0800121 uint32_t glyphStartIndex() const { return fGlyphStartIndex; }
joshualitt3660d532015-12-07 11:32:50 -0800122 uint32_t glyphEndIndex() const { return fGlyphEndIndex; }
123 void glyphAppended() { fGlyphEndIndex++; }
joshualittf9e658b2015-12-09 09:26:44 -0800124 void setColor(GrColor color) { fColor = color; }
125 GrColor color() const { return fColor; }
joshualitt3660d532015-12-07 11:32:50 -0800126 void setMaskFormat(GrMaskFormat format) { fMaskFormat = format; }
127 GrMaskFormat maskFormat() const { return fMaskFormat; }
128
joshualitt18b072d2015-12-07 12:26:12 -0800129 void setAsSuccessor(const SubRunInfo& prev) {
130 fGlyphStartIndex = prev.glyphEndIndex();
131 fGlyphEndIndex = prev.glyphEndIndex();
132
133 fVertexStartIndex = prev.vertexEndIndex();
134 fVertexEndIndex = prev.vertexEndIndex();
135 }
136
joshualitt3660d532015-12-07 11:32:50 -0800137 // df properties
138 void setUseLCDText(bool useLCDText) { fUseLCDText = useLCDText; }
139 bool hasUseLCDText() const { return fUseLCDText; }
140 void setDrawAsDistanceFields() { fDrawAsDistanceFields = true; }
141 bool drawAsDistanceFields() const { return fDrawAsDistanceFields; }
142
143 private:
joshualitt374b2f72015-07-21 08:05:03 -0700144 GrBatchAtlas::BulkUseTokenUpdater fBulkUseToken;
joshualitt7e97b0b2015-07-31 15:18:08 -0700145 SkAutoTUnref<GrBatchTextStrike> fStrike;
joshualitt374b2f72015-07-21 08:05:03 -0700146 uint64_t fAtlasGeneration;
147 size_t fVertexStartIndex;
148 size_t fVertexEndIndex;
149 uint32_t fGlyphStartIndex;
150 uint32_t fGlyphEndIndex;
joshualittf9e658b2015-12-09 09:26:44 -0800151 GrColor fColor;
joshualitt374b2f72015-07-21 08:05:03 -0700152 GrMaskFormat fMaskFormat;
153 bool fDrawAsDistanceFields; // df property
154 bool fUseLCDText; // df property
155 };
156
157 SubRunInfo& push_back() {
158 // Forward glyph / vertex information to seed the new sub run
joshualitt374b2f72015-07-21 08:05:03 -0700159 SubRunInfo& newSubRun = fSubRunInfo.push_back();
joshualitt18b072d2015-12-07 12:26:12 -0800160 const SubRunInfo& prevSubRun = fSubRunInfo.fromBack(1);
joshualitte43e3bd2015-07-29 11:10:38 -0700161
joshualitt18b072d2015-12-07 12:26:12 -0800162 newSubRun.setAsSuccessor(prevSubRun);
joshualitt374b2f72015-07-21 08:05:03 -0700163 return newSubRun;
164 }
165 static const int kMinSubRuns = 1;
joshualitt374b2f72015-07-21 08:05:03 -0700166 SkAutoTUnref<SkTypeface> fTypeface;
167 SkRect fVertexBounds;
168 SkSTArray<kMinSubRuns, SubRunInfo> fSubRunInfo;
169 SkAutoDescriptor fDescriptor;
joshualitt3660d532015-12-07 11:32:50 -0800170
171 // Distance field text cannot draw coloremoji, and so has to fall back. However,
172 // though the distance field text and the coloremoji may share the same run, they
173 // will have different descriptors. If fOverrideDescriptor is non-nullptr, then it
174 // will be used in place of the run's descriptor to regen texture coords
joshualitt374b2f72015-07-21 08:05:03 -0700175 SkAutoTDelete<SkAutoDescriptor> fOverrideDescriptor; // df properties
joshualitt374b2f72015-07-21 08:05:03 -0700176 bool fInitialized;
177 bool fDrawAsPaths;
178 };
179
180 struct BigGlyph {
joshualitt0fe04a22015-08-25 12:05:50 -0700181 BigGlyph(const SkPath& path, SkScalar vx, SkScalar vy, SkScalar scale, bool applyVM)
joshualitt374b2f72015-07-21 08:05:03 -0700182 : fPath(path)
183 , fVx(vx)
joshualitt0fe04a22015-08-25 12:05:50 -0700184 , fVy(vy)
185 , fScale(scale)
186 , fApplyVM(applyVM) {}
joshualitt374b2f72015-07-21 08:05:03 -0700187 SkPath fPath;
188 SkScalar fVx;
189 SkScalar fVy;
joshualitt0fe04a22015-08-25 12:05:50 -0700190 SkScalar fScale;
191 bool fApplyVM;
joshualitt374b2f72015-07-21 08:05:03 -0700192 };
193
194 struct Key {
195 Key() {
196 sk_bzero(this, sizeof(Key));
197 }
198 uint32_t fUniqueID;
199 // Color may affect the gamma of the mask we generate, but in a fairly limited way.
200 // Each color is assigned to on of a fixed number of buckets based on its
201 // luminance. For each luminance bucket there is a "canonical color" that
202 // represents the bucket. This functionality is currently only supported for A8
203 SkColor fCanonicalColor;
204 SkPaint::Style fStyle;
205 SkPixelGeometry fPixelGeometry;
206 bool fHasBlur;
207
208 bool operator==(const Key& other) const {
209 return 0 == memcmp(this, &other, sizeof(Key));
210 }
211 };
212
213 struct StrokeInfo {
214 SkScalar fFrameWidth;
215 SkScalar fMiterLimit;
216 SkPaint::Join fJoin;
217 };
218
219 enum TextType {
220 kHasDistanceField_TextType = 0x1,
221 kHasBitmap_TextType = 0x2,
222 };
223
224 // all glyph / vertex offsets are into these pools.
225 unsigned char* fVertices;
226 GrGlyph** fGlyphs;
227 Run* fRuns;
228 GrMemoryPool* fPool;
229 SkMaskFilter::BlurRec fBlurRec;
230 StrokeInfo fStrokeInfo;
231 SkTArray<BigGlyph> fBigGlyphs;
232 Key fKey;
233 SkMatrix fViewMatrix;
jvanverth0628a522015-08-18 07:44:22 -0700234 GrColor fPaintColor;
joshualitt374b2f72015-07-21 08:05:03 -0700235 SkScalar fX;
236 SkScalar fY;
237
238 // We can reuse distance field text, but only if the new viewmatrix would not result in
239 // a mip change. Because there can be multiple runs in a blob, we track the overall
240 // maximum minimum scale, and minimum maximum scale, we can support before we need to regen
241 SkScalar fMaxMinScale;
242 SkScalar fMinMaxScale;
243 int fRunCount;
244 uint8_t fTextType;
245
246 GrAtlasTextBlob()
247 : fMaxMinScale(-SK_ScalarMax)
248 , fMinMaxScale(SK_ScalarMax)
249 , fTextType(0) {}
250
joshualittb3adc262015-12-07 13:26:31 -0800251 ~GrAtlasTextBlob() {
joshualitt374b2f72015-07-21 08:05:03 -0700252 for (int i = 0; i < fRunCount; i++) {
253 fRuns[i].~Run();
254 }
255 }
256
257 static const Key& GetKey(const GrAtlasTextBlob& blob) {
258 return blob.fKey;
259 }
260
261 static uint32_t Hash(const Key& key) {
262 return SkChecksum::Murmur3(&key, sizeof(Key));
263 }
264
265 void operator delete(void* p) {
266 GrAtlasTextBlob* blob = reinterpret_cast<GrAtlasTextBlob*>(p);
267 blob->fPool->release(p);
268 }
269 void* operator new(size_t) {
270 SkFAIL("All blobs are created by placement new.");
271 return sk_malloc_throw(0);
272 }
273
274 void* operator new(size_t, void* p) { return p; }
275 void operator delete(void* target, void* placement) {
276 ::operator delete(target, placement);
277 }
278
279 bool hasDistanceField() const { return SkToBool(fTextType & kHasDistanceField_TextType); }
280 bool hasBitmap() const { return SkToBool(fTextType & kHasBitmap_TextType); }
281 void setHasDistanceField() { fTextType |= kHasDistanceField_TextType; }
282 void setHasBitmap() { fTextType |= kHasBitmap_TextType; }
joshualitt18b072d2015-12-07 12:26:12 -0800283
284 void push_back_run(int currRun) {
285 SkASSERT(currRun < fRunCount);
286 if (currRun > 0) {
287 Run::SubRunInfo& newRun = fRuns[currRun].fSubRunInfo.back();
288 Run::SubRunInfo& lastRun = fRuns[currRun - 1].fSubRunInfo.back();
289 newRun.setAsSuccessor(lastRun);
290 }
joshualitt3660d532015-12-07 11:32:50 -0800291 }
292
joshualitta06e6ab2015-12-10 08:54:41 -0800293 // Appends a glyph to the blob. If the glyph is too large, the glyph will be appended
294 // as a path.
joshualittf528e0d2015-12-09 06:42:52 -0800295 void appendGlyph(int runIndex,
296 const SkRect& positions,
297 GrColor color,
298 GrBatchTextStrike* strike,
joshualitta06e6ab2015-12-10 08:54:41 -0800299 GrGlyph* glyph,
300 GrFontScaler* scaler, const SkGlyph& skGlyph,
301 SkScalar x, SkScalar y, SkScalar scale, bool applyVM);
joshualitt18b072d2015-12-07 12:26:12 -0800302
joshualittf528e0d2015-12-09 06:42:52 -0800303 static size_t GetVertexStride(GrMaskFormat maskFormat) {
304 switch (maskFormat) {
305 case kA8_GrMaskFormat:
306 return kGrayTextVASize;
307 case kARGB_GrMaskFormat:
308 return kColorTextVASize;
309 default:
310 return kLCDTextVASize;
311 }
312 }
313
joshualittfd5f6c12015-12-10 07:44:50 -0800314 bool mustRegenerate(SkScalar* outTransX, SkScalar* outTransY, const SkPaint& paint,
315 GrColor color, const SkMaskFilter::BlurRec& blurRec,
316 const SkMatrix& viewMatrix, SkScalar x, SkScalar y);
317
joshualitt2e2202e2015-12-10 11:22:08 -0800318 // flush a GrAtlasTextBlob associated with a SkTextBlob
319 void flushCached(const SkTextBlob* blob,
320 GrContext* context,
321 GrDrawContext* dc,
322 GrTextContext* textContext,
323 const SkSurfaceProps& props,
324 const GrDistanceFieldAdjustTable* distanceAdjustTable,
325 const SkPaint& skPaint,
326 const GrPaint& grPaint,
327 SkDrawFilter* drawFilter,
328 const GrClip& clip,
329 const SkMatrix& viewMatrix,
330 const SkIRect& clipBounds,
331 SkScalar x, SkScalar y,
332 SkScalar transX, SkScalar transY);
333
334 // flush a throwaway GrAtlasTextBlob *not* associated with an SkTextBlob
335 void flushThrowaway(GrContext* context,
336 GrDrawContext* dc,
337 const SkSurfaceProps& props,
338 const GrDistanceFieldAdjustTable* distanceAdjustTable,
339 const SkPaint& skPaint,
340 const GrPaint& grPaint,
341 const GrClip& clip,
342 const SkIRect& clipBounds);
343
joshualittf528e0d2015-12-09 06:42:52 -0800344 // position + local coord
345 static const size_t kColorTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16);
346 static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof(SkIPoint16);
347 static const size_t kLCDTextVASize = kGrayTextVASize;
joshualitt3660d532015-12-07 11:32:50 -0800348 static const int kVerticesPerGlyph = 4;
joshualitt259fbf12015-07-21 11:39:34 -0700349
350#ifdef CACHE_SANITY_CHECK
351 static void AssertEqual(const GrAtlasTextBlob&, const GrAtlasTextBlob&);
352 size_t fSize;
353#endif
joshualitt2e2202e2015-12-10 11:22:08 -0800354
355 // We'd like to inline this and make it private, but there is some test code which calls it.
356 // TODO refactor this
357 GrDrawBatch* createBatch(const Run::SubRunInfo& info,
358 int glyphCount, int run, int subRun,
359 GrColor color, SkScalar transX, SkScalar transY,
360 const SkPaint& skPaint, const SkSurfaceProps& props,
361 const GrDistanceFieldAdjustTable* distanceAdjustTable,
362 GrBatchFontCache* cache);
363
joshualitta06e6ab2015-12-10 08:54:41 -0800364private:
365 void appendLargeGlyph(GrGlyph* glyph, GrFontScaler* scaler, const SkGlyph& skGlyph,
366 SkScalar x, SkScalar y, SkScalar scale, bool applyVM);
joshualitt2e2202e2015-12-10 11:22:08 -0800367
368 inline void flushRun(GrDrawContext* dc, GrPipelineBuilder* pipelineBuilder,
369 int run, GrColor color,
370 SkScalar transX, SkScalar transY,
371 const SkPaint& skPaint, const SkSurfaceProps& props,
372 const GrDistanceFieldAdjustTable* distanceAdjustTable,
373 GrBatchFontCache* cache);
374
375 void flushBigGlyphs(GrContext* context, GrDrawContext* dc,
376 const GrClip& clip, const SkPaint& skPaint,
377 SkScalar transX, SkScalar transY,
378 const SkIRect& clipBounds);
379
380 void flushRunAsPaths(GrDrawContext* dc,
381 GrTextContext* textContext,
382 const SkSurfaceProps& props,
383 const SkTextBlobRunIterator& it,
384 const GrClip& clip, const SkPaint& skPaint,
385 SkDrawFilter* drawFilter, const SkMatrix& viewMatrix,
386 const SkIRect& clipBounds, SkScalar x, SkScalar y);
joshualitt374b2f72015-07-21 08:05:03 -0700387};
388
389#endif