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 #include "GrAtlasGlyphCache.h"
9 #include "GrContext.h"
10 #include "GrGpu.h"
11 #include "GrRectanizer.h"
12 #include "GrResourceProvider.h"
13 #include "GrSurfacePriv.h"
14 #include "SkAutoMalloc.h"
15 #include "SkString.h"
16
17 #include "SkDistanceFieldGen.h"
18 #include "GrDistanceFieldGenFromVector.h"
19
initAtlas(GrMaskFormat format)20 bool GrAtlasGlyphCache::initAtlas(GrMaskFormat format) {
21 int index = MaskFormatToAtlasIndex(format);
22 if (!fAtlases[index]) {
23 GrPixelConfig config = MaskFormatToPixelConfig(format, *fContext->caps());
24 int width = fAtlasConfigs[index].fWidth;
25 int height = fAtlasConfigs[index].fHeight;
26 int numPlotsX = fAtlasConfigs[index].numPlotsX();
27 int numPlotsY = fAtlasConfigs[index].numPlotsY();
28
29 fAtlases[index] = GrDrawOpAtlas::Make(
30 fContext, config, width, height, numPlotsX, numPlotsY,
31 &GrAtlasGlyphCache::HandleEviction, (void*)this);
32 if (!fAtlases[index]) {
33 return false;
34 }
35 }
36 return true;
37 }
38
GrAtlasGlyphCache(GrContext * context)39 GrAtlasGlyphCache::GrAtlasGlyphCache(GrContext* context)
40 : fContext(context)
41 , fPreserveStrike(nullptr) {
42
43 // setup default atlas configs
44 fAtlasConfigs[kA8_GrMaskFormat].fWidth = 2048;
45 fAtlasConfigs[kA8_GrMaskFormat].fHeight = 2048;
46 fAtlasConfigs[kA8_GrMaskFormat].fLog2Width = 11;
47 fAtlasConfigs[kA8_GrMaskFormat].fLog2Height = 11;
48 fAtlasConfigs[kA8_GrMaskFormat].fPlotWidth = 512;
49 fAtlasConfigs[kA8_GrMaskFormat].fPlotHeight = 256;
50
51 fAtlasConfigs[kA565_GrMaskFormat].fWidth = 1024;
52 fAtlasConfigs[kA565_GrMaskFormat].fHeight = 2048;
53 fAtlasConfigs[kA565_GrMaskFormat].fLog2Width = 10;
54 fAtlasConfigs[kA565_GrMaskFormat].fLog2Height = 11;
55 fAtlasConfigs[kA565_GrMaskFormat].fPlotWidth = 256;
56 fAtlasConfigs[kA565_GrMaskFormat].fPlotHeight = 256;
57
58 fAtlasConfigs[kARGB_GrMaskFormat].fWidth = 1024;
59 fAtlasConfigs[kARGB_GrMaskFormat].fHeight = 2048;
60 fAtlasConfigs[kARGB_GrMaskFormat].fLog2Width = 10;
61 fAtlasConfigs[kARGB_GrMaskFormat].fLog2Height = 11;
62 fAtlasConfigs[kARGB_GrMaskFormat].fPlotWidth = 256;
63 fAtlasConfigs[kARGB_GrMaskFormat].fPlotHeight = 256;
64 }
65
~GrAtlasGlyphCache()66 GrAtlasGlyphCache::~GrAtlasGlyphCache() {
67 StrikeHash::Iter iter(&fCache);
68 while (!iter.done()) {
69 (*iter).fIsAbandoned = true;
70 (*iter).unref();
71 ++iter;
72 }
73 }
74
freeAll()75 void GrAtlasGlyphCache::freeAll() {
76 StrikeHash::Iter iter(&fCache);
77 while (!iter.done()) {
78 (*iter).fIsAbandoned = true;
79 (*iter).unref();
80 ++iter;
81 }
82 fCache.rewind();
83 for (int i = 0; i < kMaskFormatCount; ++i) {
84 fAtlases[i] = nullptr;
85 }
86 }
87
HandleEviction(GrDrawOpAtlas::AtlasID id,void * ptr)88 void GrAtlasGlyphCache::HandleEviction(GrDrawOpAtlas::AtlasID id, void* ptr) {
89 GrAtlasGlyphCache* fontCache = reinterpret_cast<GrAtlasGlyphCache*>(ptr);
90
91 StrikeHash::Iter iter(&fontCache->fCache);
92 for (; !iter.done(); ++iter) {
93 GrAtlasTextStrike* strike = &*iter;
94 strike->removeID(id);
95
96 // clear out any empty strikes. We will preserve the strike whose call to addToAtlas
97 // triggered the eviction
98 if (strike != fontCache->fPreserveStrike && 0 == strike->fAtlasedGlyphs) {
99 fontCache->fCache.remove(GrAtlasTextStrike::GetKey(*strike));
100 strike->fIsAbandoned = true;
101 strike->unref();
102 }
103 }
104 }
105
106 #ifdef SK_DEBUG
107 #include "GrContextPriv.h"
108 #include "GrSurfaceProxy.h"
109 #include "GrSurfaceContext.h"
110 #include "GrTextureProxy.h"
111
112 #include "SkBitmap.h"
113 #include "SkImageEncoder.h"
114 #include "SkStream.h"
115 #include <stdio.h>
116
117 /**
118 * Write the contents of the surface proxy to a PNG. Returns true if successful.
119 * @param filename Full path to desired file
120 */
save_pixels(GrContext * context,GrSurfaceProxy * sProxy,const char * filename)121 static bool save_pixels(GrContext* context, GrSurfaceProxy* sProxy, const char* filename) {
122 if (!sProxy) {
123 return false;
124 }
125
126 SkImageInfo ii = SkImageInfo::Make(sProxy->width(), sProxy->height(),
127 kRGBA_8888_SkColorType, kPremul_SkAlphaType);
128 SkBitmap bm;
129 if (!bm.tryAllocPixels(ii)) {
130 return false;
131 }
132
133 sk_sp<GrSurfaceContext> sContext(context->contextPriv().makeWrappedSurfaceContext(
134 sk_ref_sp(sProxy),
135 nullptr));
136 if (!sContext || !sContext->asTextureProxy()) {
137 return false;
138 }
139
140 bool result = sContext->readPixels(ii, bm.getPixels(), bm.rowBytes(), 0, 0);
141 if (!result) {
142 SkDebugf("------ failed to read pixels for %s\n", filename);
143 return false;
144 }
145
146 // remove any previous version of this file
147 remove(filename);
148
149 SkFILEWStream file(filename);
150 if (!file.isValid()) {
151 SkDebugf("------ failed to create file: %s\n", filename);
152 remove(filename); // remove any partial file
153 return false;
154 }
155
156 if (!SkEncodeImage(&file, bm, SkEncodedImageFormat::kPNG, 100)) {
157 SkDebugf("------ failed to encode %s\n", filename);
158 remove(filename); // remove any partial file
159 return false;
160 }
161
162 return true;
163 }
164
dump() const165 void GrAtlasGlyphCache::dump() const {
166 static int gDumpCount = 0;
167 for (int i = 0; i < kMaskFormatCount; ++i) {
168 if (fAtlases[i]) {
169 sk_sp<GrTextureProxy> proxy = fAtlases[i]->getProxy();
170 if (proxy) {
171 SkString filename;
172 #ifdef SK_BUILD_FOR_ANDROID
173 filename.printf("/sdcard/fontcache_%d%d.png", gDumpCount, i);
174 #else
175 filename.printf("fontcache_%d%d.png", gDumpCount, i);
176 #endif
177
178 save_pixels(fContext, proxy.get(), filename.c_str());
179 }
180 }
181 }
182 ++gDumpCount;
183 }
184 #endif
185
setAtlasSizes_ForTesting(const GrDrawOpAtlasConfig configs[3])186 void GrAtlasGlyphCache::setAtlasSizes_ForTesting(const GrDrawOpAtlasConfig configs[3]) {
187 // Delete any old atlases.
188 // This should be safe to do as long as we are not in the middle of a flush.
189 for (int i = 0; i < kMaskFormatCount; i++) {
190 fAtlases[i] = nullptr;
191 }
192 memcpy(fAtlasConfigs, configs, sizeof(fAtlasConfigs));
193 }
194
195 ///////////////////////////////////////////////////////////////////////////////
196
get_packed_glyph_mask_format(const SkGlyph & glyph)197 static inline GrMaskFormat get_packed_glyph_mask_format(const SkGlyph& glyph) {
198 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
199 switch (format) {
200 case SkMask::kBW_Format:
201 // fall through to kA8 -- we store BW glyphs in our 8-bit cache
202 case SkMask::kA8_Format:
203 return kA8_GrMaskFormat;
204 case SkMask::kLCD16_Format:
205 return kA565_GrMaskFormat;
206 case SkMask::kARGB32_Format:
207 return kARGB_GrMaskFormat;
208 default:
209 SkDEBUGFAIL("unsupported SkMask::Format");
210 return kA8_GrMaskFormat;
211 }
212 }
213
get_packed_glyph_bounds(SkGlyphCache * cache,const SkGlyph & glyph,SkIRect * bounds)214 static inline bool get_packed_glyph_bounds(SkGlyphCache* cache, const SkGlyph& glyph,
215 SkIRect* bounds) {
216 #if 1
217 // crbug:510931
218 // Retrieving the image from the cache can actually change the mask format.
219 cache->findImage(glyph);
220 #endif
221 bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight);
222
223 return true;
224 }
225
get_packed_glyph_df_bounds(SkGlyphCache * cache,const SkGlyph & glyph,SkIRect * bounds)226 static inline bool get_packed_glyph_df_bounds(SkGlyphCache* cache, const SkGlyph& glyph,
227 SkIRect* bounds) {
228 #if 1
229 // crbug:510931
230 // Retrieving the image from the cache can actually change the mask format.
231 cache->findImage(glyph);
232 #endif
233 bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight);
234 bounds->outset(SK_DistanceFieldPad, SK_DistanceFieldPad);
235
236 return true;
237 }
238
239 // expands each bit in a bitmask to 0 or ~0 of type INT_TYPE. Used to expand a BW glyph mask to
240 // A8, RGB565, or RGBA8888.
241 template <typename INT_TYPE>
expand_bits(INT_TYPE * dst,const uint8_t * src,int width,int height,int dstRowBytes,int srcRowBytes)242 static void expand_bits(INT_TYPE* dst,
243 const uint8_t* src,
244 int width,
245 int height,
246 int dstRowBytes,
247 int srcRowBytes) {
248 for (int i = 0; i < height; ++i) {
249 int rowWritesLeft = width;
250 const uint8_t* s = src;
251 INT_TYPE* d = dst;
252 while (rowWritesLeft > 0) {
253 unsigned mask = *s++;
254 for (int i = 7; i >= 0 && rowWritesLeft; --i, --rowWritesLeft) {
255 *d++ = (mask & (1 << i)) ? (INT_TYPE)(~0UL) : 0;
256 }
257 }
258 dst = reinterpret_cast<INT_TYPE*>(reinterpret_cast<intptr_t>(dst) + dstRowBytes);
259 src += srcRowBytes;
260 }
261 }
262
get_packed_glyph_image(SkGlyphCache * cache,const SkGlyph & glyph,int width,int height,int dstRB,GrMaskFormat expectedMaskFormat,void * dst)263 static bool get_packed_glyph_image(SkGlyphCache* cache, const SkGlyph& glyph, int width,
264 int height, int dstRB, GrMaskFormat expectedMaskFormat,
265 void* dst) {
266 SkASSERT(glyph.fWidth == width);
267 SkASSERT(glyph.fHeight == height);
268 const void* src = cache->findImage(glyph);
269 if (nullptr == src) {
270 return false;
271 }
272
273 // crbug:510931
274 // Retrieving the image from the cache can actually change the mask format. This case is very
275 // uncommon so for now we just draw a clear box for these glyphs.
276 if (get_packed_glyph_mask_format(glyph) != expectedMaskFormat) {
277 const int bpp = GrMaskFormatBytesPerPixel(expectedMaskFormat);
278 for (int y = 0; y < height; y++) {
279 sk_bzero(dst, width * bpp);
280 dst = (char*)dst + dstRB;
281 }
282 return true;
283 }
284
285 int srcRB = glyph.rowBytes();
286 // The windows font host sometimes has BW glyphs in a non-BW strike. So it is important here to
287 // check the glyph's format, not the strike's format, and to be able to convert to any of the
288 // GrMaskFormats.
289 if (SkMask::kBW_Format == glyph.fMaskFormat) {
290 // expand bits to our mask type
291 const uint8_t* bits = reinterpret_cast<const uint8_t*>(src);
292 switch (expectedMaskFormat) {
293 case kA8_GrMaskFormat:{
294 uint8_t* bytes = reinterpret_cast<uint8_t*>(dst);
295 expand_bits(bytes, bits, width, height, dstRB, srcRB);
296 break;
297 }
298 case kA565_GrMaskFormat: {
299 uint16_t* rgb565 = reinterpret_cast<uint16_t*>(dst);
300 expand_bits(rgb565, bits, width, height, dstRB, srcRB);
301 break;
302 }
303 default:
304 SkFAIL("Invalid GrMaskFormat");
305 }
306 } else if (srcRB == dstRB) {
307 memcpy(dst, src, dstRB * height);
308 } else {
309 const int bbp = GrMaskFormatBytesPerPixel(expectedMaskFormat);
310 for (int y = 0; y < height; y++) {
311 memcpy(dst, src, width * bbp);
312 src = (const char*)src + srcRB;
313 dst = (char*)dst + dstRB;
314 }
315 }
316 return true;
317 }
318
get_packed_glyph_df_image(SkGlyphCache * cache,const SkGlyph & glyph,int width,int height,void * dst)319 static bool get_packed_glyph_df_image(SkGlyphCache* cache, const SkGlyph& glyph,
320 int width, int height, void* dst) {
321 SkASSERT(glyph.fWidth + 2*SK_DistanceFieldPad == width);
322 SkASSERT(glyph.fHeight + 2*SK_DistanceFieldPad == height);
323
324 #ifndef SK_USE_LEGACY_DISTANCE_FIELDS
325 const SkPath* path = cache->findPath(glyph);
326 if (nullptr == path) {
327 return false;
328 }
329
330 SkDEBUGCODE(SkRect glyphBounds = SkRect::MakeXYWH(glyph.fLeft,
331 glyph.fTop,
332 glyph.fWidth,
333 glyph.fHeight));
334 SkASSERT(glyphBounds.contains(path->getBounds()));
335
336 // now generate the distance field
337 SkASSERT(dst);
338 SkMatrix drawMatrix;
339 drawMatrix.setTranslate((SkScalar)-glyph.fLeft, (SkScalar)-glyph.fTop);
340
341 // Generate signed distance field directly from SkPath
342 bool succeed = GrGenerateDistanceFieldFromPath((unsigned char*)dst,
343 *path, drawMatrix,
344 width, height, width * sizeof(unsigned char));
345
346 if (!succeed) {
347 #endif
348 const void* image = cache->findImage(glyph);
349 if (nullptr == image) {
350 return false;
351 }
352
353 // now generate the distance field
354 SkASSERT(dst);
355 SkMask::Format maskFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
356 if (SkMask::kA8_Format == maskFormat) {
357 // make the distance field from the image
358 SkGenerateDistanceFieldFromA8Image((unsigned char*)dst,
359 (unsigned char*)image,
360 glyph.fWidth, glyph.fHeight,
361 glyph.rowBytes());
362 } else if (SkMask::kBW_Format == maskFormat) {
363 // make the distance field from the image
364 SkGenerateDistanceFieldFromBWImage((unsigned char*)dst,
365 (unsigned char*)image,
366 glyph.fWidth, glyph.fHeight,
367 glyph.rowBytes());
368 } else {
369 return false;
370 }
371 #ifndef SK_USE_LEGACY_DISTANCE_FIELDS
372 }
373 #endif
374 return true;
375 }
376
377 ///////////////////////////////////////////////////////////////////////////////
378
379 /*
380 The text strike is specific to a given font/style/matrix setup, which is
381 represented by the GrHostFontScaler object we are given in getGlyph().
382
383 We map a 32bit glyphID to a GrGlyph record, which in turn points to a
384 atlas and a position within that texture.
385 */
386
GrAtlasTextStrike(GrAtlasGlyphCache * owner,const SkDescriptor & key)387 GrAtlasTextStrike::GrAtlasTextStrike(GrAtlasGlyphCache* owner, const SkDescriptor& key)
388 : fFontScalerKey(key)
389 , fPool(9/*start allocations at 512 bytes*/)
390 , fAtlasGlyphCache(owner) // no need to ref, it won't go away before we do
391 , fAtlasedGlyphs(0)
392 , fIsAbandoned(false) {}
393
~GrAtlasTextStrike()394 GrAtlasTextStrike::~GrAtlasTextStrike() {
395 SkTDynamicHash<GrGlyph, GrGlyph::PackedID>::Iter iter(&fCache);
396 while (!iter.done()) {
397 (*iter).reset();
398 ++iter;
399 }
400 }
401
generateGlyph(const SkGlyph & skGlyph,GrGlyph::PackedID packed,SkGlyphCache * cache)402 GrGlyph* GrAtlasTextStrike::generateGlyph(const SkGlyph& skGlyph, GrGlyph::PackedID packed,
403 SkGlyphCache* cache) {
404 SkIRect bounds;
405 if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(packed)) {
406 if (!get_packed_glyph_df_bounds(cache, skGlyph, &bounds)) {
407 return nullptr;
408 }
409 } else {
410 if (!get_packed_glyph_bounds(cache, skGlyph, &bounds)) {
411 return nullptr;
412 }
413 }
414 GrMaskFormat format = get_packed_glyph_mask_format(skGlyph);
415
416 GrGlyph* glyph = (GrGlyph*)fPool.alloc(sizeof(GrGlyph));
417 glyph->init(packed, bounds, format);
418 fCache.add(glyph);
419 return glyph;
420 }
421
removeID(GrDrawOpAtlas::AtlasID id)422 void GrAtlasTextStrike::removeID(GrDrawOpAtlas::AtlasID id) {
423 SkTDynamicHash<GrGlyph, GrGlyph::PackedID>::Iter iter(&fCache);
424 while (!iter.done()) {
425 if (id == (*iter).fID) {
426 (*iter).fID = GrDrawOpAtlas::kInvalidAtlasID;
427 fAtlasedGlyphs--;
428 SkASSERT(fAtlasedGlyphs >= 0);
429 }
430 ++iter;
431 }
432 }
433
addGlyphToAtlas(GrDrawOp::Target * target,GrGlyph * glyph,SkGlyphCache * cache,GrMaskFormat expectedMaskFormat)434 bool GrAtlasTextStrike::addGlyphToAtlas(GrDrawOp::Target* target,
435 GrGlyph* glyph,
436 SkGlyphCache* cache,
437 GrMaskFormat expectedMaskFormat) {
438 SkASSERT(glyph);
439 SkASSERT(cache);
440 SkASSERT(fCache.find(glyph->fPackedID));
441
442 int bytesPerPixel = GrMaskFormatBytesPerPixel(expectedMaskFormat);
443
444 size_t size = glyph->fBounds.area() * bytesPerPixel;
445 SkAutoSMalloc<1024> storage(size);
446
447 const SkGlyph& skGlyph = GrToSkGlyph(cache, glyph->fPackedID);
448 if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(glyph->fPackedID)) {
449 if (!get_packed_glyph_df_image(cache, skGlyph, glyph->width(), glyph->height(),
450 storage.get())) {
451 return false;
452 }
453 } else {
454 if (!get_packed_glyph_image(cache, skGlyph, glyph->width(), glyph->height(),
455 glyph->width() * bytesPerPixel, expectedMaskFormat,
456 storage.get())) {
457 return false;
458 }
459 }
460
461 bool success = fAtlasGlyphCache->addToAtlas(this, &glyph->fID, target, expectedMaskFormat,
462 glyph->width(), glyph->height(),
463 storage.get(), &glyph->fAtlasLocation);
464 if (success) {
465 SkASSERT(GrDrawOpAtlas::kInvalidAtlasID != glyph->fID);
466 fAtlasedGlyphs++;
467 }
468 return success;
469 }
470