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 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 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 66 GrAtlasGlyphCache::~GrAtlasGlyphCache() { 67 StrikeHash::Iter iter(&fCache); 68 while (!iter.done()) { 69 (*iter).fIsAbandoned = true; 70 (*iter).unref(); 71 ++iter; 72 } 73 } 74 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 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 */ 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 165 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 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 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 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 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> 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 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 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 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 394 GrAtlasTextStrike::~GrAtlasTextStrike() { 395 SkTDynamicHash<GrGlyph, GrGlyph::PackedID>::Iter iter(&fCache); 396 while (!iter.done()) { 397 (*iter).reset(); 398 ++iter; 399 } 400 } 401 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 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 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