blob: a75eb0e4697d671f65d514679921c564d7ef2146 [file] [log] [blame]
joshualitt1d89e8d2015-04-01 12:40:54 -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 GrAtlasTextContext_DEFINED
9#define GrAtlasTextContext_DEFINED
10
11#include "GrTextContext.h"
12
joshualittb4c507e2015-04-08 08:07:59 -070013#include "GrBatchAtlas.h"
joshualitt1d89e8d2015-04-01 12:40:54 -070014#include "GrGeometryProcessor.h"
15#include "SkDescriptor.h"
joshualitt9a27e632015-04-06 10:53:36 -070016#include "SkTextBlob.h"
joshualitt1d89e8d2015-04-01 12:40:54 -070017#include "SkTHash.h"
18
19class GrBatchTextStrike;
20class GrPipelineBuilder;
21
22/*
23 * This class implements GrTextContext using standard bitmap fonts, and can also process textblobs.
24 * TODO replace GrBitmapTextContext
25 */
joshualittdbd35932015-04-02 09:19:04 -070026class GrAtlasTextContext : public GrTextContext {
joshualitt1d89e8d2015-04-01 12:40:54 -070027public:
joshualittdbd35932015-04-02 09:19:04 -070028 static GrAtlasTextContext* Create(GrContext*, SkGpuDevice*, const SkDeviceProperties&);
joshualitt1d89e8d2015-04-01 12:40:54 -070029
joshualittdbd35932015-04-02 09:19:04 -070030 virtual ~GrAtlasTextContext();
joshualitt1d89e8d2015-04-01 12:40:54 -070031
32private:
joshualittdbd35932015-04-02 09:19:04 -070033 GrAtlasTextContext(GrContext*, SkGpuDevice*, const SkDeviceProperties&);
joshualitt1d89e8d2015-04-01 12:40:54 -070034
35 bool canDraw(const GrRenderTarget*, const GrClip&, const GrPaint&,
36 const SkPaint&, const SkMatrix& viewMatrix) override;
37
38 void onDrawText(GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&,
39 const SkMatrix& viewMatrix, const char text[], size_t byteLength,
40 SkScalar x, SkScalar y, const SkIRect& regionClipBounds) override;
41 void onDrawPosText(GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&,
42 const SkMatrix& viewMatrix,
43 const char text[], size_t byteLength,
44 const SkScalar pos[], int scalarsPerPosition,
45 const SkPoint& offset, const SkIRect& regionClipBounds) override;
46 void drawTextBlob(GrRenderTarget*, const GrClip&, const SkPaint&,
47 const SkMatrix& viewMatrix, const SkTextBlob*, SkScalar x, SkScalar y,
48 SkDrawFilter*, const SkIRect& clipBounds) override;
49
joshualitt1d89e8d2015-04-01 12:40:54 -070050 /*
51 * A BitmapTextBlob contains a fully processed SkTextBlob, suitable for nearly immediate drawing
52 * on the GPU. These are initially created with valid positions and colors, but invalid
53 * texture coordinates. The BitmapTextBlob itself has a few Blob-wide properties, and also
54 * consists of a number of runs. Runs inside a blob are flushed individually so they can be
55 * reordered.
56 *
57 * The only thing(aside from a memcopy) required to flush a BitmapTextBlob is to ensure that
58 * the GrAtlas will not evict anything the Blob needs.
59 * TODO this is currently a bug
60 */
61 struct BitmapTextBlob : public SkRefCnt {
joshualitt9a27e632015-04-06 10:53:36 -070062 /*
63 * Each Run inside of the blob can have its texture coordinates regenerated if required.
64 * To determine if regeneration is necessary, fAtlasGeneration is used. If there have been
65 * any evictions inside of the atlas, then we will simply regenerate Runs. We could track
66 * this at a more fine grained level, but its not clear if this is worth it, as evictions
67 * should be fairly rare.
68 *
69 * One additional point, each run can contain glyphs with any of the three mask formats.
70 * We call these SubRuns. Because a subrun must be a contiguous range, we have to create
71 * a new subrun each time the mask format changes in a run. In theory, a run can have as
72 * many SubRuns as it has glyphs, ie if a run alternates between color emoji and A8. In
73 * practice, the vast majority of runs have only a single subrun.
74 *
75 * Finally, for runs where the entire thing is too large for the GrAtlasTextContext to
76 * handle, we have a bit to mark the run as flusahable via rendering as paths. It is worth
77 * pointing. It would be a bit expensive to figure out ahead of time whether or not a run
78 * can flush in this manner, so we always allocate vertices for the run, regardless of
79 * whether or not it is too large. The benefit of this strategy is that we can always reuse
80 * a blob allocation regardless of viewmatrix changes. We could store positions for these
81 * glyphs. However, its not clear if this is a win because we'd still have to either go the
82 * glyph cache to get the path at flush time, or hold onto the path in the cache, which
83 * would greatly increase the memory of these cached items.
84 */
joshualitt1d89e8d2015-04-01 12:40:54 -070085
86 struct Run {
joshualitt9a27e632015-04-06 10:53:36 -070087 Run() : fColor(GrColor_ILLEGAL), fInitialized(false), fDrawAsPaths(false) {
joshualitt1d89e8d2015-04-01 12:40:54 -070088 fVertexBounds.setLargestInverted();
89 // We insert the first subrun to gurantee a run always has atleast one subrun.
90 // We do this to simplify things when we 'hand off' data from one subrun to the
91 // next
92 fSubRunInfo.push_back();
93 }
94 struct SubRunInfo {
95 SubRunInfo()
96 : fAtlasGeneration(GrBatchAtlas::kInvalidAtlasGeneration)
97 , fGlyphStartIndex(0)
98 , fGlyphEndIndex(0)
99 , fVertexStartIndex(0)
100 , fVertexEndIndex(0) {}
101 GrMaskFormat fMaskFormat;
102 uint64_t fAtlasGeneration;
103 uint32_t fGlyphStartIndex;
104 uint32_t fGlyphEndIndex;
105 size_t fVertexStartIndex;
106 size_t fVertexEndIndex;
joshualittb4c507e2015-04-08 08:07:59 -0700107 GrBatchAtlas::BulkUseTokenUpdater fBulkUseToken;
joshualitt1d89e8d2015-04-01 12:40:54 -0700108 };
109 SkSTArray<1, SubRunInfo, true> fSubRunInfo;
110 SkAutoDescriptor fDescriptor;
111 SkAutoTUnref<SkTypeface> fTypeface;
112 SkRect fVertexBounds;
113 GrColor fColor;
114 bool fInitialized;
joshualitt9a27e632015-04-06 10:53:36 -0700115 bool fDrawAsPaths;
joshualitt1d89e8d2015-04-01 12:40:54 -0700116 };
117
118 struct BigGlyph {
119 BigGlyph(const SkPath& path, int vx, int vy) : fPath(path), fVx(vx), fVy(vy) {}
120 SkPath fPath;
121 int fVx;
122 int fVy;
123 };
124
125 SkTArray<BigGlyph> fBigGlyphs;
126 SkMatrix fViewMatrix;
127 SkScalar fX;
128 SkScalar fY;
129 SkPaint::Style fStyle;
joshualitt9a27e632015-04-06 10:53:36 -0700130 int fRunCount;
joshualitt1d89e8d2015-04-01 12:40:54 -0700131
132 // all glyph / vertex offsets are into these pools.
133 unsigned char* fVertices;
134 GrGlyph::PackedID* fGlyphIDs;
135 Run* fRuns;
136
137 static uint32_t Hash(const uint32_t& key) {
138 return SkChecksum::Mix(key);
139 }
140
141 void operator delete(void* p) { sk_free(p); }
142 void* operator new(size_t) {
143 SkFAIL("All blobs are created by placement new.");
144 return sk_malloc_throw(0);
145 }
146
147 void* operator new(size_t, void* p) { return p; }
148 void operator delete(void* target, void* placement) {
149 ::operator delete(target, placement);
150 }
151 };
152
153 typedef BitmapTextBlob::Run Run;
154 typedef Run::SubRunInfo PerSubRunInfo;
155
156 BitmapTextBlob* CreateBlob(int glyphCount, int runCount);
157
158 void appendGlyph(BitmapTextBlob*, int runIndex, GrGlyph::PackedID, int left, int top,
joshualitteef5b3e2015-04-03 08:07:26 -0700159 GrColor color, GrFontScaler*, const SkIRect& clipRect);
joshualitt9a27e632015-04-06 10:53:36 -0700160
161 inline void flushRunAsPaths(const SkTextBlob::RunIterator&, const SkPaint&, SkDrawFilter*,
162 const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x,
163 SkScalar y);
164 inline void flushRun(GrDrawTarget*, GrPipelineBuilder*, BitmapTextBlob*, int run, GrColor,
165 uint8_t paintAlpha);
166 inline void flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRenderTarget* rt,
167 const GrPaint& grPaint, const GrClip& clip);
168
169 // We have to flush SkTextBlobs differently from drawText / drawPosText
170 void flush(GrDrawTarget*, const SkTextBlob*, BitmapTextBlob*, GrRenderTarget*, const SkPaint&,
171 const GrPaint&, SkDrawFilter*, const GrClip&, const SkMatrix& viewMatrix,
172 const SkIRect& clipBounds, SkScalar x, SkScalar y);
173 void flush(GrDrawTarget*, BitmapTextBlob*, GrRenderTarget*, const SkPaint&,
174 const GrPaint&, const GrClip&, const SkMatrix& viewMatrix);
joshualitt1d89e8d2015-04-01 12:40:54 -0700175
176 void internalDrawText(BitmapTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&,
177 const SkMatrix& viewMatrix, const char text[], size_t byteLength,
178 SkScalar x, SkScalar y, const SkIRect& clipRect);
179 void internalDrawPosText(BitmapTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&,
180 const SkMatrix& viewMatrix,
181 const char text[], size_t byteLength,
182 const SkScalar pos[], int scalarsPerPosition,
183 const SkPoint& offset, const SkIRect& clipRect);
184
185 // sets up the descriptor on the blob and returns a detached cache. Client must attach
186 inline SkGlyphCache* setupCache(Run*, const SkPaint&, const SkMatrix& viewMatrix);
187 static inline bool MustRegenerateBlob(const BitmapTextBlob&, const SkPaint&,
188 const SkMatrix& viewMatrix, SkScalar x, SkScalar y);
189 void regenerateTextBlob(BitmapTextBlob* bmp, const SkPaint& skPaint, const SkMatrix& viewMatrix,
190 const SkTextBlob* blob, SkScalar x, SkScalar y,
191 SkDrawFilter* drawFilter, const SkIRect& clipRect);
192
193 // TODO this currently only uses the public interface of SkTextBlob, however, I may need to add
194 // functionality to it while looping over the runs so I'm putting this here for the time being.
195 // If this lands in Chrome without changes, move it to SkTextBlob.
196 static inline void BlobGlyphCount(int* glyphCount, int* runCount, const SkTextBlob*);
197
198 GrBatchTextStrike* fCurrStrike;
199
200 // TODO use real cache
201 static void ClearCacheEntry(uint32_t key, BitmapTextBlob**);
202 SkTHashMap<uint32_t, BitmapTextBlob*, BitmapTextBlob::Hash> fCache;
203
204 friend class BitmapTextBatch;
205
206 typedef GrTextContext INHERITED;
207};
208
209#endif