Home | History | Annotate | Download | only in gpu
      1 
      2 /*
      3  * Copyright 2010 Google Inc.
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 
     10 
     11 #include "GrAtlas.h"
     12 #include "GrGpu.h"
     13 #include "GrRectanizer.h"
     14 #include "GrTextStrike.h"
     15 #include "GrTextStrike_impl.h"
     16 #include "GrRect.h"
     17 
     18 SK_DEFINE_INST_COUNT(GrFontScaler)
     19 SK_DEFINE_INST_COUNT(GrKey)
     20 
     21 ///////////////////////////////////////////////////////////////////////////////
     22 
     23 GrFontCache::GrFontCache(GrGpu* gpu) : fGpu(gpu) {
     24     gpu->ref();
     25     fAtlasMgr = NULL;
     26 
     27     fHead = fTail = NULL;
     28 }
     29 
     30 GrFontCache::~GrFontCache() {
     31     fCache.deleteAll();
     32     delete fAtlasMgr;
     33     fGpu->unref();
     34 }
     35 
     36 GrTextStrike* GrFontCache::generateStrike(GrFontScaler* scaler,
     37                                           const Key& key) {
     38     if (NULL == fAtlasMgr) {
     39         fAtlasMgr = SkNEW_ARGS(GrAtlasMgr, (fGpu));
     40     }
     41     GrTextStrike* strike = SkNEW_ARGS(GrTextStrike,
     42                                       (this, scaler->getKey(),
     43                                        scaler->getMaskFormat(), fAtlasMgr));
     44     fCache.insert(key, strike);
     45 
     46     if (fHead) {
     47         fHead->fPrev = strike;
     48     } else {
     49         GrAssert(NULL == fTail);
     50         fTail = strike;
     51     }
     52     strike->fPrev = NULL;
     53     strike->fNext = fHead;
     54     fHead = strike;
     55 
     56     return strike;
     57 }
     58 
     59 void GrFontCache::freeAll() {
     60     fCache.deleteAll();
     61     delete fAtlasMgr;
     62     fAtlasMgr = NULL;
     63     fHead = NULL;
     64     fTail = NULL;
     65 }
     66 
     67 void GrFontCache::purgeExceptFor(GrTextStrike* preserveStrike) {
     68     GrTextStrike* strike = fTail;
     69     while (strike) {
     70         if (strike == preserveStrike) {
     71             strike = strike->fPrev;
     72             continue;
     73         }
     74         GrTextStrike* strikeToPurge = strike;
     75         // keep going if we won't free up any atlases with this strike.
     76         strike = (NULL == strikeToPurge->fAtlas) ? strikeToPurge->fPrev : NULL;
     77         int index = fCache.slowFindIndex(strikeToPurge);
     78         GrAssert(index >= 0);
     79         fCache.removeAt(index, strikeToPurge->fFontScalerKey->getHash());
     80         this->detachStrikeFromList(strikeToPurge);
     81         delete strikeToPurge;
     82     }
     83 }
     84 
     85 #if GR_DEBUG
     86 void GrFontCache::validate() const {
     87     int count = fCache.count();
     88     if (0 == count) {
     89         GrAssert(!fHead);
     90         GrAssert(!fTail);
     91     } else if (1 == count) {
     92         GrAssert(fHead == fTail);
     93     } else {
     94         GrAssert(fHead != fTail);
     95     }
     96 
     97     int count2 = 0;
     98     const GrTextStrike* strike = fHead;
     99     while (strike) {
    100         count2 += 1;
    101         strike = strike->fNext;
    102     }
    103     GrAssert(count == count2);
    104 
    105     count2 = 0;
    106     strike = fTail;
    107     while (strike) {
    108         count2 += 1;
    109         strike = strike->fPrev;
    110     }
    111     GrAssert(count == count2);
    112 }
    113 #endif
    114 
    115 ///////////////////////////////////////////////////////////////////////////////
    116 
    117 #if GR_DEBUG
    118     static int gCounter;
    119 #endif
    120 
    121 /*
    122     The text strike is specific to a given font/style/matrix setup, which is
    123     represented by the GrHostFontScaler object we are given in getGlyph().
    124 
    125     We map a 32bit glyphID to a GrGlyph record, which in turn points to a
    126     atlas and a position within that texture.
    127  */
    128 
    129 GrTextStrike::GrTextStrike(GrFontCache* cache, const GrKey* key,
    130                            GrMaskFormat format,
    131                            GrAtlasMgr* atlasMgr) : fPool(64) {
    132     fFontScalerKey = key;
    133     fFontScalerKey->ref();
    134 
    135     fFontCache = cache;     // no need to ref, it won't go away before we do
    136     fAtlasMgr = atlasMgr;   // no need to ref, it won't go away before we do
    137     fAtlas = NULL;
    138 
    139     fMaskFormat = format;
    140 
    141 #if GR_DEBUG
    142 //    GrPrintf(" GrTextStrike %p %d\n", this, gCounter);
    143     gCounter += 1;
    144 #endif
    145 }
    146 
    147 static void FreeGlyph(GrGlyph*& glyph) { glyph->free(); }
    148 
    149 GrTextStrike::~GrTextStrike() {
    150     GrAtlas::FreeLList(fAtlas);
    151     fFontScalerKey->unref();
    152     fCache.getArray().visitAll(FreeGlyph);
    153 
    154 #if GR_DEBUG
    155     gCounter -= 1;
    156 //    GrPrintf("~GrTextStrike %p %d\n", this, gCounter);
    157 #endif
    158 }
    159 
    160 GrGlyph* GrTextStrike::generateGlyph(GrGlyph::PackedID packed,
    161                                      GrFontScaler* scaler) {
    162     GrIRect bounds;
    163     if (!scaler->getPackedGlyphBounds(packed, &bounds)) {
    164         return NULL;
    165     }
    166 
    167     GrGlyph* glyph = fPool.alloc();
    168     glyph->init(packed, bounds);
    169     fCache.insert(packed, glyph);
    170     return glyph;
    171 }
    172 
    173 bool GrTextStrike::getGlyphAtlas(GrGlyph* glyph, GrFontScaler* scaler) {
    174 #if 0   // testing hack to force us to flush our cache often
    175     static int gCounter;
    176     if ((++gCounter % 10) == 0) return false;
    177 #endif
    178 
    179     GrAssert(glyph);
    180     GrAssert(scaler);
    181     GrAssert(fCache.contains(glyph));
    182     if (glyph->fAtlas) {
    183         return true;
    184     }
    185 
    186     GrAutoRef ar(scaler);
    187 
    188     int bytesPerPixel = GrMaskFormatBytesPerPixel(fMaskFormat);
    189     size_t size = glyph->fBounds.area() * bytesPerPixel;
    190     SkAutoSMalloc<1024> storage(size);
    191     if (!scaler->getPackedGlyphImage(glyph->fPackedID, glyph->width(),
    192                                      glyph->height(),
    193                                      glyph->width() * bytesPerPixel,
    194                                      storage.get())) {
    195         return false;
    196     }
    197 
    198     GrAtlas* atlas = fAtlasMgr->addToAtlas(fAtlas, glyph->width(),
    199                                            glyph->height(), storage.get(),
    200                                            fMaskFormat,
    201                                            &glyph->fAtlasLocation);
    202     if (NULL == atlas) {
    203         return false;
    204     }
    205 
    206     // update fAtlas as well, since they may be chained in a linklist
    207     glyph->fAtlas = fAtlas = atlas;
    208     return true;
    209 }
    210