LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/gpu/text - GrAtlasGlyphCache.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 230 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 20 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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           0 : bool GrAtlasGlyphCache::initAtlas(GrMaskFormat format) {
      21           0 :     int index = MaskFormatToAtlasIndex(format);
      22           0 :     if (!fAtlases[index]) {
      23           0 :         GrPixelConfig config = MaskFormatToPixelConfig(format, *fContext->caps());
      24           0 :         int width = fAtlasConfigs[index].fWidth;
      25           0 :         int height = fAtlasConfigs[index].fHeight;
      26           0 :         int numPlotsX = fAtlasConfigs[index].numPlotsX();
      27           0 :         int numPlotsY = fAtlasConfigs[index].numPlotsY();
      28             : 
      29           0 :         fAtlases[index] = GrDrawOpAtlas::Make(
      30             :                 fContext, config, width, height, numPlotsX, numPlotsY,
      31           0 :                 &GrAtlasGlyphCache::HandleEviction, (void*)this);
      32           0 :         if (!fAtlases[index]) {
      33           0 :             return false;
      34             :         }
      35             :     }
      36           0 :     return true;
      37             : }
      38             : 
      39           0 : GrAtlasGlyphCache::GrAtlasGlyphCache(GrContext* context)
      40             :     : fContext(context)
      41           0 :     , fPreserveStrike(nullptr) {
      42             : 
      43             :     // setup default atlas configs
      44           0 :     fAtlasConfigs[kA8_GrMaskFormat].fWidth = 2048;
      45           0 :     fAtlasConfigs[kA8_GrMaskFormat].fHeight = 2048;
      46           0 :     fAtlasConfigs[kA8_GrMaskFormat].fLog2Width = 11;
      47           0 :     fAtlasConfigs[kA8_GrMaskFormat].fLog2Height = 11;
      48           0 :     fAtlasConfigs[kA8_GrMaskFormat].fPlotWidth = 512;
      49           0 :     fAtlasConfigs[kA8_GrMaskFormat].fPlotHeight = 256;
      50             : 
      51           0 :     fAtlasConfigs[kA565_GrMaskFormat].fWidth = 1024;
      52           0 :     fAtlasConfigs[kA565_GrMaskFormat].fHeight = 2048;
      53           0 :     fAtlasConfigs[kA565_GrMaskFormat].fLog2Width = 10;
      54           0 :     fAtlasConfigs[kA565_GrMaskFormat].fLog2Height = 11;
      55           0 :     fAtlasConfigs[kA565_GrMaskFormat].fPlotWidth = 256;
      56           0 :     fAtlasConfigs[kA565_GrMaskFormat].fPlotHeight = 256;
      57             : 
      58           0 :     fAtlasConfigs[kARGB_GrMaskFormat].fWidth = 1024;
      59           0 :     fAtlasConfigs[kARGB_GrMaskFormat].fHeight = 2048;
      60           0 :     fAtlasConfigs[kARGB_GrMaskFormat].fLog2Width = 10;
      61           0 :     fAtlasConfigs[kARGB_GrMaskFormat].fLog2Height = 11;
      62           0 :     fAtlasConfigs[kARGB_GrMaskFormat].fPlotWidth = 256;
      63           0 :     fAtlasConfigs[kARGB_GrMaskFormat].fPlotHeight = 256;
      64           0 : }
      65             : 
      66           0 : GrAtlasGlyphCache::~GrAtlasGlyphCache() {
      67           0 :     StrikeHash::Iter iter(&fCache);
      68           0 :     while (!iter.done()) {
      69           0 :         (*iter).fIsAbandoned = true;
      70           0 :         (*iter).unref();
      71           0 :         ++iter;
      72             :     }
      73           0 : }
      74             : 
      75           0 : void GrAtlasGlyphCache::freeAll() {
      76           0 :     StrikeHash::Iter iter(&fCache);
      77           0 :     while (!iter.done()) {
      78           0 :         (*iter).fIsAbandoned = true;
      79           0 :         (*iter).unref();
      80           0 :         ++iter;
      81             :     }
      82           0 :     fCache.rewind();
      83           0 :     for (int i = 0; i < kMaskFormatCount; ++i) {
      84           0 :         fAtlases[i] = nullptr;
      85             :     }
      86           0 : }
      87             : 
      88           0 : void GrAtlasGlyphCache::HandleEviction(GrDrawOpAtlas::AtlasID id, void* ptr) {
      89           0 :     GrAtlasGlyphCache* fontCache = reinterpret_cast<GrAtlasGlyphCache*>(ptr);
      90             : 
      91           0 :     StrikeHash::Iter iter(&fontCache->fCache);
      92           0 :     for (; !iter.done(); ++iter) {
      93           0 :         GrAtlasTextStrike* strike = &*iter;
      94           0 :         strike->removeID(id);
      95             : 
      96             :         // clear out any empty strikes.  We will preserve the strike whose call to addToAtlas
      97             :         // triggered the eviction
      98           0 :         if (strike != fontCache->fPreserveStrike && 0 == strike->fAtlasedGlyphs) {
      99           0 :             fontCache->fCache.remove(GrAtlasTextStrike::GetKey(*strike));
     100           0 :             strike->fIsAbandoned = true;
     101           0 :             strike->unref();
     102             :         }
     103             :     }
     104           0 : }
     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           0 : static bool save_pixels(GrContext* context, GrSurfaceProxy* sProxy, const char* filename) {
     122           0 :     if (!sProxy) {
     123           0 :         return false;
     124             :     }
     125             : 
     126             :     SkImageInfo ii = SkImageInfo::Make(sProxy->width(), sProxy->height(),
     127           0 :                                        kRGBA_8888_SkColorType, kPremul_SkAlphaType);
     128           0 :     SkBitmap bm;
     129           0 :     if (!bm.tryAllocPixels(ii)) {
     130           0 :         return false;
     131             :     }
     132             : 
     133           0 :     sk_sp<GrSurfaceContext> sContext(context->contextPriv().makeWrappedSurfaceContext(
     134           0 :                                                                             sk_ref_sp(sProxy),
     135           0 :                                                                             nullptr));
     136           0 :     if (!sContext || !sContext->asTextureProxy()) {
     137           0 :         return false;
     138             :     }
     139             : 
     140           0 :     bool result = sContext->readPixels(ii, bm.getPixels(), bm.rowBytes(), 0, 0);
     141           0 :     if (!result) {
     142           0 :         SkDebugf("------ failed to read pixels for %s\n", filename);
     143           0 :         return false;
     144             :     }
     145             : 
     146             :     // remove any previous version of this file
     147           0 :     remove(filename);
     148             : 
     149           0 :     SkFILEWStream file(filename);
     150           0 :     if (!file.isValid()) {
     151           0 :         SkDebugf("------ failed to create file: %s\n", filename);
     152           0 :         remove(filename);   // remove any partial file
     153           0 :         return false;
     154             :     }
     155             : 
     156           0 :     if (!SkEncodeImage(&file, bm, SkEncodedImageFormat::kPNG, 100)) {
     157           0 :         SkDebugf("------ failed to encode %s\n", filename);
     158           0 :         remove(filename);   // remove any partial file
     159           0 :         return false;
     160             :     }
     161             : 
     162           0 :     return true;
     163             : }
     164             : 
     165           0 : void GrAtlasGlyphCache::dump() const {
     166             :     static int gDumpCount = 0;
     167           0 :     for (int i = 0; i < kMaskFormatCount; ++i) {
     168           0 :         if (fAtlases[i]) {
     169           0 :             sk_sp<GrTextureProxy> proxy = fAtlases[i]->getProxy();
     170           0 :             if (proxy) {
     171           0 :                 SkString filename;
     172             : #ifdef SK_BUILD_FOR_ANDROID
     173             :                 filename.printf("/sdcard/fontcache_%d%d.png", gDumpCount, i);
     174             : #else
     175           0 :                 filename.printf("fontcache_%d%d.png", gDumpCount, i);
     176             : #endif
     177             : 
     178           0 :                 save_pixels(fContext, proxy.get(), filename.c_str());
     179             :             }
     180             :         }
     181             :     }
     182           0 :     ++gDumpCount;
     183           0 : }
     184             : #endif
     185             : 
     186           0 : 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           0 :     for (int i = 0; i < kMaskFormatCount; i++) {
     190           0 :         fAtlases[i] = nullptr;
     191             :     }
     192           0 :     memcpy(fAtlasConfigs, configs, sizeof(fAtlasConfigs));
     193           0 : }
     194             : 
     195             : ///////////////////////////////////////////////////////////////////////////////
     196             : 
     197           0 : static inline GrMaskFormat get_packed_glyph_mask_format(const SkGlyph& glyph) {
     198           0 :     SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
     199           0 :     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           0 :             return kA8_GrMaskFormat;
     204             :         case SkMask::kLCD16_Format:
     205           0 :             return kA565_GrMaskFormat;
     206             :         case SkMask::kARGB32_Format:
     207           0 :             return kARGB_GrMaskFormat;
     208             :         default:
     209           0 :             SkDEBUGFAIL("unsupported SkMask::Format");
     210           0 :             return kA8_GrMaskFormat;
     211             :     }
     212             : }
     213             : 
     214           0 : 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           0 :     cache->findImage(glyph);
     220             : #endif
     221           0 :     bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight);
     222             : 
     223           0 :     return true;
     224             : }
     225             : 
     226           0 : 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           0 :     cache->findImage(glyph);
     232             : #endif
     233           0 :     bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight);
     234           0 :     bounds->outset(SK_DistanceFieldPad, SK_DistanceFieldPad);
     235             : 
     236           0 :     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           0 : 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           0 :     for (int i = 0; i < height; ++i) {
     249           0 :         int rowWritesLeft = width;
     250           0 :         const uint8_t* s = src;
     251           0 :         INT_TYPE* d = dst;
     252           0 :         while (rowWritesLeft > 0) {
     253           0 :             unsigned mask = *s++;
     254           0 :             for (int i = 7; i >= 0 && rowWritesLeft; --i, --rowWritesLeft) {
     255           0 :                 *d++ = (mask & (1 << i)) ? (INT_TYPE)(~0UL) : 0;
     256             :             }
     257             :         }
     258           0 :         dst = reinterpret_cast<INT_TYPE*>(reinterpret_cast<intptr_t>(dst) + dstRowBytes);
     259           0 :         src += srcRowBytes;
     260             :     }
     261           0 : }
     262             : 
     263           0 : static bool get_packed_glyph_image(SkGlyphCache* cache, const SkGlyph& glyph, int width,
     264             :                                    int height, int dstRB, GrMaskFormat expectedMaskFormat,
     265             :                                    void* dst) {
     266           0 :     SkASSERT(glyph.fWidth == width);
     267           0 :     SkASSERT(glyph.fHeight == height);
     268           0 :     const void* src = cache->findImage(glyph);
     269           0 :     if (nullptr == src) {
     270           0 :         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           0 :     if (get_packed_glyph_mask_format(glyph) != expectedMaskFormat) {
     277           0 :         const int bpp = GrMaskFormatBytesPerPixel(expectedMaskFormat);
     278           0 :         for (int y = 0; y < height; y++) {
     279           0 :             sk_bzero(dst, width * bpp);
     280           0 :             dst = (char*)dst + dstRB;
     281             :         }
     282           0 :         return true;
     283             :     }
     284             : 
     285           0 :     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           0 :     if (SkMask::kBW_Format == glyph.fMaskFormat) {
     290             :         // expand bits to our mask type
     291           0 :         const uint8_t* bits = reinterpret_cast<const uint8_t*>(src);
     292           0 :         switch (expectedMaskFormat) {
     293             :             case kA8_GrMaskFormat:{
     294           0 :                 uint8_t* bytes = reinterpret_cast<uint8_t*>(dst);
     295           0 :                 expand_bits(bytes, bits, width, height, dstRB, srcRB);
     296           0 :                 break;
     297             :             }
     298             :             case kA565_GrMaskFormat: {
     299           0 :                 uint16_t* rgb565 = reinterpret_cast<uint16_t*>(dst);
     300           0 :                 expand_bits(rgb565, bits, width, height, dstRB, srcRB);
     301           0 :                 break;
     302             :             }
     303             :             default:
     304           0 :                 SkFAIL("Invalid GrMaskFormat");
     305             :         }
     306           0 :     } else if (srcRB == dstRB) {
     307           0 :         memcpy(dst, src, dstRB * height);
     308             :     } else {
     309           0 :         const int bbp = GrMaskFormatBytesPerPixel(expectedMaskFormat);
     310           0 :         for (int y = 0; y < height; y++) {
     311           0 :             memcpy(dst, src, width * bbp);
     312           0 :             src = (const char*)src + srcRB;
     313           0 :             dst = (char*)dst + dstRB;
     314             :         }
     315             :     }
     316           0 :     return true;
     317             : }
     318             : 
     319           0 : static bool get_packed_glyph_df_image(SkGlyphCache* cache, const SkGlyph& glyph,
     320             :                                       int width, int height, void* dst) {
     321           0 :     SkASSERT(glyph.fWidth + 2*SK_DistanceFieldPad == width);
     322           0 :     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           0 :         const void* image = cache->findImage(glyph);
     349           0 :         if (nullptr == image) {
     350           0 :             return false;
     351             :         }
     352             : 
     353             :         // now generate the distance field
     354           0 :         SkASSERT(dst);
     355           0 :         SkMask::Format maskFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
     356           0 :         if (SkMask::kA8_Format == maskFormat) {
     357             :             // make the distance field from the image
     358           0 :             SkGenerateDistanceFieldFromA8Image((unsigned char*)dst,
     359             :                                                (unsigned char*)image,
     360           0 :                                                glyph.fWidth, glyph.fHeight,
     361           0 :                                                glyph.rowBytes());
     362           0 :         } else if (SkMask::kBW_Format == maskFormat) {
     363             :             // make the distance field from the image
     364           0 :             SkGenerateDistanceFieldFromBWImage((unsigned char*)dst,
     365             :                                                (unsigned char*)image,
     366           0 :                                                glyph.fWidth, glyph.fHeight,
     367           0 :                                                glyph.rowBytes());
     368             :         } else {
     369           0 :             return false;
     370             :         }
     371             : #ifndef SK_USE_LEGACY_DISTANCE_FIELDS
     372             :     }
     373             : #endif
     374           0 :     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           0 : 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           0 :     , fIsAbandoned(false) {}
     393             : 
     394           0 : GrAtlasTextStrike::~GrAtlasTextStrike() {
     395           0 :     SkTDynamicHash<GrGlyph, GrGlyph::PackedID>::Iter iter(&fCache);
     396           0 :     while (!iter.done()) {
     397           0 :         (*iter).reset();
     398           0 :         ++iter;
     399             :     }
     400           0 : }
     401             : 
     402           0 : GrGlyph* GrAtlasTextStrike::generateGlyph(const SkGlyph& skGlyph, GrGlyph::PackedID packed,
     403             :                                           SkGlyphCache* cache) {
     404             :     SkIRect bounds;
     405           0 :     if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(packed)) {
     406           0 :         if (!get_packed_glyph_df_bounds(cache, skGlyph, &bounds)) {
     407           0 :             return nullptr;
     408             :         }
     409             :     } else {
     410           0 :         if (!get_packed_glyph_bounds(cache, skGlyph, &bounds)) {
     411           0 :             return nullptr;
     412             :         }
     413             :     }
     414           0 :     GrMaskFormat format = get_packed_glyph_mask_format(skGlyph);
     415             : 
     416           0 :     GrGlyph* glyph = (GrGlyph*)fPool.alloc(sizeof(GrGlyph));
     417           0 :     glyph->init(packed, bounds, format);
     418           0 :     fCache.add(glyph);
     419           0 :     return glyph;
     420             : }
     421             : 
     422           0 : void GrAtlasTextStrike::removeID(GrDrawOpAtlas::AtlasID id) {
     423           0 :     SkTDynamicHash<GrGlyph, GrGlyph::PackedID>::Iter iter(&fCache);
     424           0 :     while (!iter.done()) {
     425           0 :         if (id == (*iter).fID) {
     426           0 :             (*iter).fID = GrDrawOpAtlas::kInvalidAtlasID;
     427           0 :             fAtlasedGlyphs--;
     428           0 :             SkASSERT(fAtlasedGlyphs >= 0);
     429             :         }
     430           0 :         ++iter;
     431             :     }
     432           0 : }
     433             : 
     434           0 : bool GrAtlasTextStrike::addGlyphToAtlas(GrDrawOp::Target* target,
     435             :                                         GrGlyph* glyph,
     436             :                                         SkGlyphCache* cache,
     437             :                                         GrMaskFormat expectedMaskFormat) {
     438           0 :     SkASSERT(glyph);
     439           0 :     SkASSERT(cache);
     440           0 :     SkASSERT(fCache.find(glyph->fPackedID));
     441             : 
     442           0 :     int bytesPerPixel = GrMaskFormatBytesPerPixel(expectedMaskFormat);
     443             : 
     444           0 :     size_t size = glyph->fBounds.area() * bytesPerPixel;
     445           0 :     SkAutoSMalloc<1024> storage(size);
     446             : 
     447           0 :     const SkGlyph& skGlyph = GrToSkGlyph(cache, glyph->fPackedID);
     448           0 :     if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(glyph->fPackedID)) {
     449           0 :         if (!get_packed_glyph_df_image(cache, skGlyph, glyph->width(), glyph->height(),
     450             :                                        storage.get())) {
     451           0 :             return false;
     452             :         }
     453             :     } else {
     454           0 :         if (!get_packed_glyph_image(cache, skGlyph, glyph->width(), glyph->height(),
     455           0 :                                     glyph->width() * bytesPerPixel, expectedMaskFormat,
     456             :                                     storage.get())) {
     457           0 :             return false;
     458             :         }
     459             :     }
     460             : 
     461           0 :     bool success = fAtlasGlyphCache->addToAtlas(this, &glyph->fID, target, expectedMaskFormat,
     462             :                                                glyph->width(), glyph->height(),
     463           0 :                                                storage.get(), &glyph->fAtlasLocation);
     464           0 :     if (success) {
     465           0 :         SkASSERT(GrDrawOpAtlas::kInvalidAtlasID != glyph->fID);
     466           0 :         fAtlasedGlyphs++;
     467             :     }
     468           0 :     return success;
     469             : }

Generated by: LCOV version 1.13