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