LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/gpu/text - GrAtlasGlyphCache.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 65 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             : #ifndef GrAtlasGlyphCache_DEFINED
       9             : #define GrAtlasGlyphCache_DEFINED
      10             : 
      11             : #include "GrCaps.h"
      12             : #include "GrDrawOpAtlas.h"
      13             : #include "GrGlyph.h"
      14             : #include "SkGlyphCache.h"
      15             : #include "SkTDynamicHash.h"
      16             : #include "SkVarAlloc.h"
      17             : 
      18             : class GrAtlasGlyphCache;
      19             : class GrGpu;
      20             : 
      21             : /**
      22             :  *  The GrAtlasTextStrike manages a pool of CPU backing memory for GrGlyphs. This backing memory
      23             :  *  is indexed by a PackedID and SkGlyphCache. The SkGlyphCache is what actually creates the mask.
      24             :  *  The GrAtlasTextStrike may outlive the generating SkGlyphCache. However, it retains a copy
      25             :  *  of it's SkDescriptor as a key to access (or regenerate) the SkGlyphCache. GrAtlasTextStrike are
      26             :  *  created by and owned by a GrAtlasGlyphCache.
      27             :  */
      28             : class GrAtlasTextStrike : public SkNVRefCnt<GrAtlasTextStrike> {
      29             : public:
      30             :     /** Owner is the cache that owns this strike. */
      31             :     GrAtlasTextStrike(GrAtlasGlyphCache* owner, const SkDescriptor& fontScalerKey);
      32             :     ~GrAtlasTextStrike();
      33             : 
      34           0 :     inline GrGlyph* getGlyph(const SkGlyph& skGlyph, GrGlyph::PackedID packed,
      35             :                              SkGlyphCache* cache) {
      36           0 :         GrGlyph* glyph = fCache.find(packed);
      37           0 :         if (nullptr == glyph) {
      38           0 :             glyph = this->generateGlyph(skGlyph, packed, cache);
      39             :         }
      40           0 :         return glyph;
      41             :     }
      42             : 
      43             :     // This variant of the above function is called by GrAtlasTextOp. At this point, it is possible
      44             :     // that the maskformat of the glyph differs from what we expect.  In these cases we will just
      45             :     // draw a clear square.
      46             :     // skbug:4143 crbug:510931
      47           0 :     inline GrGlyph* getGlyph(GrGlyph::PackedID packed,
      48             :                              GrMaskFormat expectedMaskFormat,
      49             :                              SkGlyphCache* cache) {
      50           0 :         GrGlyph* glyph = fCache.find(packed);
      51           0 :         if (nullptr == glyph) {
      52             :             // We could return this to the caller, but in practice it adds code complexity for
      53             :             // potentially little benefit(ie, if the glyph is not in our font cache, then its not
      54             :             // in the atlas and we're going to be doing a texture upload anyways).
      55           0 :             const SkGlyph& skGlyph = GrToSkGlyph(cache, packed);
      56           0 :             glyph = this->generateGlyph(skGlyph, packed, cache);
      57           0 :             glyph->fMaskFormat = expectedMaskFormat;
      58             :         }
      59           0 :         return glyph;
      60             :     }
      61             : 
      62             :     // returns true if glyph successfully added to texture atlas, false otherwise.  If the glyph's
      63             :     // mask format has changed, then addGlyphToAtlas will draw a clear box.  This will almost never
      64             :     // happen.
      65             :     // TODO we can handle some of these cases if we really want to, but the long term solution is to
      66             :     // get the actual glyph image itself when we get the glyph metrics.
      67             :     bool addGlyphToAtlas(GrDrawOp::Target*, GrGlyph*, SkGlyphCache*,
      68             :                          GrMaskFormat expectedMaskFormat);
      69             : 
      70             :     // testing
      71             :     int countGlyphs() const { return fCache.count(); }
      72             : 
      73             :     // remove any references to this plot
      74             :     void removeID(GrDrawOpAtlas::AtlasID);
      75             : 
      76             :     // If a TextStrike is abandoned by the cache, then the caller must get a new strike
      77           0 :     bool isAbandoned() const { return fIsAbandoned; }
      78             : 
      79           0 :     static const SkDescriptor& GetKey(const GrAtlasTextStrike& ts) {
      80           0 :         return *ts.fFontScalerKey.getDesc();
      81             :     }
      82             : 
      83           0 :     static uint32_t Hash(const SkDescriptor& desc) { return desc.getChecksum(); }
      84             : 
      85             : private:
      86             :     SkTDynamicHash<GrGlyph, GrGlyph::PackedID> fCache;
      87             :     SkAutoDescriptor fFontScalerKey;
      88             :     SkVarAlloc fPool;
      89             : 
      90             :     GrAtlasGlyphCache* fAtlasGlyphCache;
      91             :     int fAtlasedGlyphs;
      92             :     bool fIsAbandoned;
      93             : 
      94           0 :     static const SkGlyph& GrToSkGlyph(SkGlyphCache* cache, GrGlyph::PackedID id) {
      95           0 :         return cache->getGlyphIDMetrics(GrGlyph::UnpackID(id),
      96             :                                         GrGlyph::UnpackFixedX(id),
      97           0 :                                         GrGlyph::UnpackFixedY(id));
      98             :     }
      99             : 
     100             :     GrGlyph* generateGlyph(const SkGlyph&, GrGlyph::PackedID, SkGlyphCache*);
     101             : 
     102             :     friend class GrAtlasGlyphCache;
     103             : };
     104             : 
     105             : /**
     106             :  * GrAtlasGlyphCache manages strikes which are indexed by a SkGlyphCache. These strikes can then be
     107             :  * used to generate individual Glyph Masks. The GrAtlasGlyphCache also manages GrDrawOpAtlases,
     108             :  * though this is more or less transparent to the client(aside from atlasGeneration, described
     109             :  * below).
     110             :  */
     111             : class GrAtlasGlyphCache {
     112             : public:
     113             :     GrAtlasGlyphCache(GrContext*);
     114             :     ~GrAtlasGlyphCache();
     115             :     // The user of the cache may hold a long-lived ref to the returned strike. However, actions by
     116             :     // another client of the cache may cause the strike to be purged while it is still reffed.
     117             :     // Therefore, the caller must check GrAtlasTextStrike::isAbandoned() if there are other
     118             :     // interactions with the cache since the strike was received.
     119           0 :     inline GrAtlasTextStrike* getStrike(const SkGlyphCache* cache) {
     120           0 :         GrAtlasTextStrike* strike = fCache.find(cache->getDescriptor());
     121           0 :         if (nullptr == strike) {
     122           0 :             strike = this->generateStrike(cache);
     123             :         }
     124           0 :         return strike;
     125             :     }
     126             : 
     127             :     void freeAll();
     128             : 
     129             :     // if getProxy returns nullptr, the client must not try to use other functions on the
     130             :     // GrAtlasGlyphCache which use the atlas.  This function *must* be called first, before other
     131             :     // functions which use the atlas.
     132           0 :     sk_sp<GrTextureProxy> getProxy(GrMaskFormat format) {
     133           0 :         if (this->initAtlas(format)) {
     134           0 :             return this->getAtlas(format)->getProxy();
     135             :         }
     136           0 :         return nullptr;
     137             :     }
     138             : 
     139           0 :     bool hasGlyph(GrGlyph* glyph) {
     140           0 :         SkASSERT(glyph);
     141           0 :         return this->getAtlas(glyph->fMaskFormat)->hasID(glyph->fID);
     142             :     }
     143             : 
     144             :     // To ensure the GrDrawOpAtlas does not evict the Glyph Mask from its texture backing store,
     145             :     // the client must pass in the current op token along with the GrGlyph.
     146             :     // A BulkUseTokenUpdater is used to manage bulk last use token updating in the Atlas.
     147             :     // For convenience, this function will also set the use token for the current glyph if required
     148             :     // NOTE: the bulk uploader is only valid if the subrun has a valid atlasGeneration
     149           0 :     void addGlyphToBulkAndSetUseToken(GrDrawOpAtlas::BulkUseTokenUpdater* updater, GrGlyph* glyph,
     150             :                                       GrDrawOpUploadToken token) {
     151           0 :         SkASSERT(glyph);
     152           0 :         updater->add(glyph->fID);
     153           0 :         this->getAtlas(glyph->fMaskFormat)->setLastUseToken(glyph->fID, token);
     154           0 :     }
     155             : 
     156           0 :     void setUseTokenBulk(const GrDrawOpAtlas::BulkUseTokenUpdater& updater,
     157             :                          GrDrawOpUploadToken token,
     158             :                          GrMaskFormat format) {
     159           0 :         this->getAtlas(format)->setLastUseTokenBulk(updater, token);
     160           0 :     }
     161             : 
     162             :     // add to texture atlas that matches this format
     163           0 :     bool addToAtlas(GrAtlasTextStrike* strike, GrDrawOpAtlas::AtlasID* id, GrDrawOp::Target* target,
     164             :                     GrMaskFormat format, int width, int height, const void* image,
     165             :                     SkIPoint16* loc) {
     166           0 :         fPreserveStrike = strike;
     167           0 :         return this->getAtlas(format)->addToAtlas(id, target, width, height, image, loc);
     168             :     }
     169             : 
     170             :     // Some clients may wish to verify the integrity of the texture backing store of the
     171             :     // GrDrawOpAtlas. The atlasGeneration returned below is a monotonically increasing number which
     172             :     // changes every time something is removed from the texture backing store.
     173           0 :     uint64_t atlasGeneration(GrMaskFormat format) const {
     174           0 :         return this->getAtlas(format)->atlasGeneration();
     175             :     }
     176             : 
     177           0 :     int log2Width(GrMaskFormat format) { return fAtlasConfigs[format].fLog2Width; }
     178           0 :     int log2Height(GrMaskFormat format) { return fAtlasConfigs[format].fLog2Height; }
     179             : 
     180             :     ///////////////////////////////////////////////////////////////////////////
     181             :     // Functions intended debug only
     182             : #ifdef SK_DEBUG
     183             :     void dump() const;
     184             : #endif
     185             : 
     186             :     void setAtlasSizes_ForTesting(const GrDrawOpAtlasConfig configs[3]);
     187             : 
     188           0 :     GrContext* context() const { return fContext; }
     189             : 
     190             : private:
     191           0 :     static GrPixelConfig MaskFormatToPixelConfig(GrMaskFormat format, const GrCaps& caps) {
     192           0 :         switch (format) {
     193             :             case kA8_GrMaskFormat:
     194           0 :                 return kAlpha_8_GrPixelConfig;
     195             :             case kA565_GrMaskFormat:
     196           0 :                 return kRGB_565_GrPixelConfig;
     197             :             case kARGB_GrMaskFormat:
     198           0 :                 return caps.srgbSupport() ? kSRGBA_8888_GrPixelConfig : kRGBA_8888_GrPixelConfig;
     199             :             default:
     200           0 :                 SkDEBUGFAIL("unsupported GrMaskFormat");
     201           0 :                 return kAlpha_8_GrPixelConfig;
     202             :         }
     203             :     }
     204             : 
     205             :     // There is a 1:1 mapping between GrMaskFormats and atlas indices
     206           0 :     static int MaskFormatToAtlasIndex(GrMaskFormat format) {
     207             :         static const int sAtlasIndices[] = {
     208             :             kA8_GrMaskFormat,
     209             :             kA565_GrMaskFormat,
     210             :             kARGB_GrMaskFormat,
     211             :         };
     212             :         static_assert(SK_ARRAY_COUNT(sAtlasIndices) == kMaskFormatCount, "array_size_mismatch");
     213             : 
     214           0 :         SkASSERT(sAtlasIndices[format] < kMaskFormatCount);
     215           0 :         return sAtlasIndices[format];
     216             :     }
     217             : 
     218             :     bool initAtlas(GrMaskFormat);
     219             : 
     220           0 :     GrAtlasTextStrike* generateStrike(const SkGlyphCache* cache) {
     221           0 :         GrAtlasTextStrike* strike = new GrAtlasTextStrike(this, cache->getDescriptor());
     222           0 :         fCache.add(strike);
     223           0 :         return strike;
     224             :     }
     225             : 
     226           0 :     GrDrawOpAtlas* getAtlas(GrMaskFormat format) const {
     227           0 :         int atlasIndex = MaskFormatToAtlasIndex(format);
     228           0 :         SkASSERT(fAtlases[atlasIndex]);
     229           0 :         return fAtlases[atlasIndex].get();
     230             :     }
     231             : 
     232             :     static void HandleEviction(GrDrawOpAtlas::AtlasID, void*);
     233             : 
     234             :     using StrikeHash = SkTDynamicHash<GrAtlasTextStrike, SkDescriptor>;
     235             :     GrContext* fContext;
     236             :     StrikeHash fCache;
     237             :     std::unique_ptr<GrDrawOpAtlas> fAtlases[kMaskFormatCount];
     238             :     GrAtlasTextStrike* fPreserveStrike;
     239             :     GrDrawOpAtlasConfig fAtlasConfigs[kMaskFormatCount];
     240             : };
     241             : 
     242             : #endif

Generated by: LCOV version 1.13