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