Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1491)

Side by Side Diff: src/gpu/GrTextStrike.cpp

Issue 780923002: Ganesh text rendering cleanup. (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/gpu/GrTextStrike.h ('k') | src/gpu/GrTextStrike_impl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2010 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 #include "GrGpu.h"
9 #include "GrRectanizer.h"
10 #include "GrSurfacePriv.h"
11 #include "GrTextStrike.h"
12 #include "GrTextStrike_impl.h"
13 #include "SkString.h"
14
15 #include "SkDistanceFieldGen.h"
16
17 ///////////////////////////////////////////////////////////////////////////////
18
19 #define GR_ATLAS_TEXTURE_WIDTH 1024
20 #define GR_ATLAS_TEXTURE_HEIGHT 2048
21
22 #define GR_PLOT_WIDTH 256
23 #define GR_PLOT_HEIGHT 256
24
25 #define GR_NUM_PLOTS_X (GR_ATLAS_TEXTURE_WIDTH / GR_PLOT_WIDTH)
26 #define GR_NUM_PLOTS_Y (GR_ATLAS_TEXTURE_HEIGHT / GR_PLOT_HEIGHT)
27
28 #define FONT_CACHE_STATS 0
29 #if FONT_CACHE_STATS
30 static int g_PurgeCount = 0;
31 #endif
32
33 GrFontCache::GrFontCache(GrGpu* gpu) : fGpu(gpu) {
34 gpu->ref();
35 for (int i = 0; i < kAtlasCount; ++i) {
36 fAtlases[i] = NULL;
37 }
38
39 fHead = fTail = NULL;
40 }
41
42 GrFontCache::~GrFontCache() {
43 SkTDynamicHash<GrTextStrike, GrFontDescKey>::Iter iter(&fCache);
44 while (!iter.done()) {
45 SkDELETE(&(*iter));
46 ++iter;
47 }
48 for (int i = 0; i < kAtlasCount; ++i) {
49 delete fAtlases[i];
50 }
51 fGpu->unref();
52 #if FONT_CACHE_STATS
53 SkDebugf("Num purges: %d\n", g_PurgeCount);
54 #endif
55 }
56
57 static GrPixelConfig mask_format_to_pixel_config(GrMaskFormat format) {
58 static const GrPixelConfig sPixelConfigs[] = {
59 kAlpha_8_GrPixelConfig,
60 kRGB_565_GrPixelConfig,
61 kSkia8888_GrPixelConfig
62 };
63 SK_COMPILE_ASSERT(SK_ARRAY_COUNT(sPixelConfigs) == kMaskFormatCount, array_s ize_mismatch);
64
65 return sPixelConfigs[format];
66 }
67
68 static int mask_format_to_atlas_index(GrMaskFormat format) {
69 static const int sAtlasIndices[] = {
70 GrFontCache::kA8_AtlasType,
71 GrFontCache::k565_AtlasType,
72 GrFontCache::k8888_AtlasType
73 };
74 SK_COMPILE_ASSERT(SK_ARRAY_COUNT(sAtlasIndices) == kMaskFormatCount, array_s ize_mismatch);
75
76 SkASSERT(sAtlasIndices[format] < GrFontCache::kAtlasCount);
77 return sAtlasIndices[format];
78 }
79
80 GrTextStrike* GrFontCache::generateStrike(GrFontScaler* scaler) {
81 GrTextStrike* strike = SkNEW_ARGS(GrTextStrike, (this, scaler->getKey()));
82 fCache.add(strike);
83
84 if (fHead) {
85 fHead->fPrev = strike;
86 } else {
87 SkASSERT(NULL == fTail);
88 fTail = strike;
89 }
90 strike->fPrev = NULL;
91 strike->fNext = fHead;
92 fHead = strike;
93
94 return strike;
95 }
96
97 void GrFontCache::freeAll() {
98 SkTDynamicHash<GrTextStrike, GrFontDescKey>::Iter iter(&fCache);
99 while (!iter.done()) {
100 SkDELETE(&(*iter));
101 ++iter;
102 }
103 fCache.rewind();
104 for (int i = 0; i < kAtlasCount; ++i) {
105 delete fAtlases[i];
106 fAtlases[i] = NULL;
107 }
108 fHead = NULL;
109 fTail = NULL;
110 }
111
112 void GrFontCache::purgeStrike(GrTextStrike* strike) {
113 fCache.remove(*(strike->fFontScalerKey));
114 this->detachStrikeFromList(strike);
115 delete strike;
116 }
117
118
119 GrPlot* GrFontCache::addToAtlas(GrMaskFormat format, GrAtlas::ClientPlotUsage* u sage,
120 int width, int height, const void* image,
121 SkIPoint16* loc) {
122 GrPixelConfig config = mask_format_to_pixel_config(format);
123 int atlasIndex = mask_format_to_atlas_index(format);
124 if (NULL == fAtlases[atlasIndex]) {
125 SkISize textureSize = SkISize::Make(GR_ATLAS_TEXTURE_WIDTH,
126 GR_ATLAS_TEXTURE_HEIGHT);
127 fAtlases[atlasIndex] = SkNEW_ARGS(GrAtlas, (fGpu, config, kNone_GrSurfac eFlags,
128 textureSize,
129 GR_NUM_PLOTS_X,
130 GR_NUM_PLOTS_Y,
131 true));
132 }
133 return fAtlases[atlasIndex]->addToAtlas(usage, width, height, image, loc);
134 }
135
136
137 bool GrFontCache::freeUnusedPlot(GrTextStrike* preserveStrike, const GrGlyph* gl yph) {
138 SkASSERT(preserveStrike);
139
140 int index = mask_format_to_atlas_index(glyph->fMaskFormat);
141 GrAtlas* atlas = fAtlases[index];
142 GrPlot* plot = atlas->getUnusedPlot();
143 if (NULL == plot) {
144 return false;
145 }
146 plot->resetRects();
147
148 GrTextStrike* strike = fHead;
149 while (strike) {
150 GrTextStrike* strikeToPurge = strike;
151 strike = strikeToPurge->fNext;
152 strikeToPurge->removePlot(plot);
153
154 // clear out any empty strikes (except this one)
155 if (strikeToPurge != preserveStrike && strikeToPurge->fPlotUsage.isEmpty ()) {
156 this->purgeStrike(strikeToPurge);
157 }
158 }
159
160 #if FONT_CACHE_STATS
161 ++g_PurgeCount;
162 #endif
163
164 return true;
165 }
166
167 #ifdef SK_DEBUG
168 void GrFontCache::validate() const {
169 int count = fCache.count();
170 if (0 == count) {
171 SkASSERT(!fHead);
172 SkASSERT(!fTail);
173 } else if (1 == count) {
174 SkASSERT(fHead == fTail);
175 } else {
176 SkASSERT(fHead != fTail);
177 }
178
179 int count2 = 0;
180 const GrTextStrike* strike = fHead;
181 while (strike) {
182 count2 += 1;
183 strike = strike->fNext;
184 }
185 SkASSERT(count == count2);
186
187 count2 = 0;
188 strike = fTail;
189 while (strike) {
190 count2 += 1;
191 strike = strike->fPrev;
192 }
193 SkASSERT(count == count2);
194 }
195 #endif
196
197 void GrFontCache::dump() const {
198 static int gDumpCount = 0;
199 for (int i = 0; i < kAtlasCount; ++i) {
200 if (fAtlases[i]) {
201 GrTexture* texture = fAtlases[i]->getTexture();
202 if (texture) {
203 SkString filename;
204 #ifdef SK_BUILD_FOR_ANDROID
205 filename.printf("/sdcard/fontcache_%d%d.png", gDumpCount, i);
206 #else
207 filename.printf("fontcache_%d%d.png", gDumpCount, i);
208 #endif
209 texture->surfacePriv().savePixels(filename.c_str());
210 }
211 }
212 }
213 ++gDumpCount;
214 }
215
216 ///////////////////////////////////////////////////////////////////////////////
217
218 #ifdef SK_DEBUG
219 static int gCounter;
220 #endif
221
222 /*
223 The text strike is specific to a given font/style/matrix setup, which is
224 represented by the GrHostFontScaler object we are given in getGlyph().
225
226 We map a 32bit glyphID to a GrGlyph record, which in turn points to a
227 atlas and a position within that texture.
228 */
229
230 GrTextStrike::GrTextStrike(GrFontCache* cache, const GrFontDescKey* key) {
231 fFontScalerKey = key;
232 fFontScalerKey->ref();
233
234 fFontCache = cache; // no need to ref, it won't go away before we do
235
236 #ifdef SK_DEBUG
237 // SkDebugf(" GrTextStrike %p %d\n", this, gCounter);
238 gCounter += 1;
239 #endif
240 }
241
242 GrTextStrike::~GrTextStrike() {
243 fFontScalerKey->unref();
244 SkTDynamicHash<GrGlyph, GrGlyph::PackedID>::Iter iter(&fCache);
245 while (!iter.done()) {
246 (*iter).free();
247 ++iter;
248 }
249
250 #ifdef SK_DEBUG
251 gCounter -= 1;
252 // SkDebugf("~GrTextStrike %p %d\n", this, gCounter);
253 #endif
254 }
255
256 GrGlyph* GrTextStrike::generateGlyph(GrGlyph::PackedID packed,
257 GrFontScaler* scaler) {
258 SkIRect bounds;
259 if (fUseDistanceField) {
260 if (!scaler->getPackedGlyphDFBounds(packed, &bounds)) {
261 return NULL;
262 }
263 } else {
264 if (!scaler->getPackedGlyphBounds(packed, &bounds)) {
265 return NULL;
266 }
267 }
268 GrMaskFormat format = scaler->getPackedGlyphMaskFormat(packed);
269
270 GrGlyph* glyph = (GrGlyph*)fPool.alloc(sizeof(GrGlyph), SK_MALLOC_THROW);
271 glyph->init(packed, bounds, format);
272 fCache.add(glyph);
273 return glyph;
274 }
275
276 void GrTextStrike::removePlot(const GrPlot* plot) {
277 SkTDynamicHash<GrGlyph, GrGlyph::PackedID>::Iter iter(&fCache);
278 while (!iter.done()) {
279 if (plot == (*iter).fPlot) {
280 (*iter).fPlot = NULL;
281 }
282 ++iter;
283 }
284
285 GrAtlas::RemovePlot(&fPlotUsage, plot);
286 }
287
288 bool GrTextStrike::glyphTooLargeForAtlas(GrGlyph* glyph) {
289 int width = glyph->fBounds.width();
290 int height = glyph->fBounds.height();
291 int pad = fUseDistanceField ? 2 * SK_DistanceFieldPad : 0;
292 if (width + pad > GR_PLOT_WIDTH) {
293 return true;
294 }
295 if (height + pad > GR_PLOT_HEIGHT) {
296 return true;
297 }
298
299 return false;
300 }
301
302 bool GrTextStrike::addGlyphToAtlas(GrGlyph* glyph, GrFontScaler* scaler) {
303 #if 0 // testing hack to force us to flush our cache often
304 static int gCounter;
305 if ((++gCounter % 10) == 0) return false;
306 #endif
307
308 SkASSERT(glyph);
309 SkASSERT(scaler);
310 SkASSERT(fCache.find(glyph->fPackedID));
311 SkASSERT(NULL == glyph->fPlot);
312
313 SkAutoUnref ar(SkSafeRef(scaler));
314
315 int bytesPerPixel = GrMaskFormatBytesPerPixel(glyph->fMaskFormat);
316
317 size_t size = glyph->fBounds.area() * bytesPerPixel;
318 GrAutoMalloc<1024> storage(size);
319
320 if (fUseDistanceField) {
321 if (!scaler->getPackedGlyphDFImage(glyph->fPackedID, glyph->width(),
322 glyph->height(),
323 storage.get())) {
324 return false;
325 }
326 } else {
327 if (!scaler->getPackedGlyphImage(glyph->fPackedID, glyph->width(),
328 glyph->height(),
329 glyph->width() * bytesPerPixel,
330 storage.get())) {
331 return false;
332 }
333 }
334
335 GrPlot* plot = fFontCache->addToAtlas(glyph->fMaskFormat, &fPlotUsage,
336 glyph->width(), glyph->height(),
337 storage.get(), &glyph->fAtlasLocation) ;
338
339 if (NULL == plot) {
340 return false;
341 }
342
343 glyph->fPlot = plot;
344 return true;
345 }
OLDNEW
« no previous file with comments | « src/gpu/GrTextStrike.h ('k') | src/gpu/GrTextStrike_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698