Home | History | Annotate | Download | only in text
      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