blob: 33f313c912730eb14064eca77ce481b5331fb3bf [file] [log] [blame]
joshualitt7c3a2f82015-03-31 13:32:05 -07001/*
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 GrBatchFontCache_DEFINED
9#define GrBatchFontCache_DEFINED
10
11#include "GrBatchAtlas.h"
joshualitt7c3a2f82015-03-31 13:32:05 -070012#include "GrFontScaler.h"
13#include "GrGlyph.h"
joshualitt6c2c2b02015-07-24 10:37:00 -070014#include "SkGlyph.h"
joshualitt7c3a2f82015-03-31 13:32:05 -070015#include "SkTDynamicHash.h"
16#include "SkVarAlloc.h"
17
18class GrBatchFontCache;
19class GrBatchTarget;
20class GrGpu;
21
22/**
joshualitt4765bdc2015-07-23 10:58:48 -070023 * The GrBatchTextStrike manages a pool of CPU backing memory for GrGlyphs. This backing memory
24 * is indexed by a PackedID and GrFontScaler. The GrFontScaler is what actually creates the mask.
joshualitt7c3a2f82015-03-31 13:32:05 -070025 */
joshualittae32c102015-04-21 09:37:57 -070026class GrBatchTextStrike : public SkNVRefCnt<GrBatchTextStrike> {
joshualitt7c3a2f82015-03-31 13:32:05 -070027public:
28 GrBatchTextStrike(GrBatchFontCache*, const GrFontDescKey* fontScalerKey);
29 ~GrBatchTextStrike();
30
31 const GrFontDescKey* getFontScalerKey() const { return fFontScalerKey; }
32 GrBatchFontCache* getBatchFontCache() const { return fBatchFontCache; }
33
joshualitt6c2c2b02015-07-24 10:37:00 -070034 inline GrGlyph* getGlyph(const SkGlyph& skGlyph, GrGlyph::PackedID packed,
35 GrFontScaler* scaler) {
joshualitt7c3a2f82015-03-31 13:32:05 -070036 GrGlyph* glyph = fCache.find(packed);
37 if (NULL == glyph) {
joshualitt6c2c2b02015-07-24 10:37:00 -070038 glyph = this->generateGlyph(skGlyph, packed, scaler);
joshualitt7c3a2f82015-03-31 13:32:05 -070039 }
40 return glyph;
41 }
42
joshualitt7c3a2f82015-03-31 13:32:05 -070043 // returns true if glyph successfully added to texture atlas, false otherwise
joshualitt6c2c2b02015-07-24 10:37:00 -070044 bool addGlyphToAtlas(GrBatchTarget*, GrGlyph*, GrFontScaler*, const SkGlyph&);
joshualitt7c3a2f82015-03-31 13:32:05 -070045
46 // testing
47 int countGlyphs() const { return fCache.count(); }
48
49 // remove any references to this plot
50 void removeID(GrBatchAtlas::AtlasID);
51
joshualittae32c102015-04-21 09:37:57 -070052 // If a TextStrike is abandoned by the cache, then the caller must get a new strike
53 bool isAbandoned() const { return fIsAbandoned; }
54
joshualitt7c3a2f82015-03-31 13:32:05 -070055 static const GrFontDescKey& GetKey(const GrBatchTextStrike& ts) {
56 return *(ts.fFontScalerKey);
57 }
58 static uint32_t Hash(const GrFontDescKey& key) {
59 return key.getHash();
60 }
61
62private:
63 SkTDynamicHash<GrGlyph, GrGlyph::PackedID> fCache;
64 SkAutoTUnref<const GrFontDescKey> fFontScalerKey;
65 SkVarAlloc fPool;
66
67 GrBatchFontCache* fBatchFontCache;
68 int fAtlasedGlyphs;
joshualittae32c102015-04-21 09:37:57 -070069 bool fIsAbandoned;
joshualitt7c3a2f82015-03-31 13:32:05 -070070
joshualitt6c2c2b02015-07-24 10:37:00 -070071 GrGlyph* generateGlyph(const SkGlyph&, GrGlyph::PackedID, GrFontScaler*);
joshualitt7c3a2f82015-03-31 13:32:05 -070072
73 friend class GrBatchFontCache;
74};
75
76/*
77 * GrBatchFontCache manages strikes which are indexed by a GrFontScaler. These strikes can then be
78 * used to individual Glyph Masks. The GrBatchFontCache also manages GrBatchAtlases, though this is
joshualitt62db8ba2015-04-09 08:22:37 -070079 * more or less transparent to the client(aside from atlasGeneration, described below).
80 * Note - we used to initialize the backing atlas for the GrBatchFontCache at initialization time.
81 * However, this caused a regression, even when the GrBatchFontCache was unused. We now initialize
82 * the backing atlases lazily. Its not immediately clear why this improves the situation.
joshualitt7c3a2f82015-03-31 13:32:05 -070083 */
84class GrBatchFontCache {
85public:
joshualitt62db8ba2015-04-09 08:22:37 -070086 GrBatchFontCache(GrContext*);
joshualitt7c3a2f82015-03-31 13:32:05 -070087 ~GrBatchFontCache();
joshualittae32c102015-04-21 09:37:57 -070088 // The user of the cache may hold a long-lived ref to the returned strike. However, actions by
89 // another client of the cache may cause the strike to be purged while it is still reffed.
90 // Therefore, the caller must check GrBatchTextStrike::isAbandoned() if there are other
91 // interactions with the cache since the strike was received.
joshualitt7c3a2f82015-03-31 13:32:05 -070092 inline GrBatchTextStrike* getStrike(GrFontScaler* scaler) {
joshualitt7c3a2f82015-03-31 13:32:05 -070093 GrBatchTextStrike* strike = fCache.find(*(scaler->getKey()));
94 if (NULL == strike) {
95 strike = this->generateStrike(scaler);
96 }
97 return strike;
98 }
99
joshualitt62db8ba2015-04-09 08:22:37 -0700100 void freeAll();
101
102 // if getTexture returns NULL, the client must not try to use other functions on the
103 // GrBatchFontCache which use the atlas. This function *must* be called first, before other
104 // functions which use the atlas.
105 GrTexture* getTexture(GrMaskFormat format) {
106 if (this->initAtlas(format)) {
107 return this->getAtlas(format)->getTexture();
108 }
109 return NULL;
110 }
111
112 bool hasGlyph(GrGlyph* glyph) {
113 SkASSERT(glyph);
114 return this->getAtlas(glyph->fMaskFormat)->hasID(glyph->fID);
115 }
joshualitt7c3a2f82015-03-31 13:32:05 -0700116
117 // To ensure the GrBatchAtlas does not evict the Glyph Mask from its texture backing store,
joshualittb4c507e2015-04-08 08:07:59 -0700118 // the client must pass in the currentToken from the GrBatchTarget along with the GrGlyph.
119 // A BulkUseTokenUpdater is used to manage bulk last use token updating in the Atlas.
120 // For convenience, this function will also set the use token for the current glyph if required
121 // NOTE: the bulk uploader is only valid if the subrun has a valid atlasGeneration
joshualitt62db8ba2015-04-09 08:22:37 -0700122 void addGlyphToBulkAndSetUseToken(GrBatchAtlas::BulkUseTokenUpdater* updater,
123 GrGlyph* glyph, GrBatchAtlas::BatchToken token) {
124 SkASSERT(glyph);
125 updater->add(glyph->fID);
126 this->getAtlas(glyph->fMaskFormat)->setLastUseToken(glyph->fID, token);
127 }
joshualittb4c507e2015-04-08 08:07:59 -0700128
joshualitt62db8ba2015-04-09 08:22:37 -0700129 void setUseTokenBulk(const GrBatchAtlas::BulkUseTokenUpdater& updater,
130 GrBatchAtlas::BatchToken token,
131 GrMaskFormat format) {
132 this->getAtlas(format)->setLastUseTokenBulk(updater, token);
133 }
joshualitt7c3a2f82015-03-31 13:32:05 -0700134
135 // add to texture atlas that matches this format
joshualitt62db8ba2015-04-09 08:22:37 -0700136 bool addToAtlas(GrBatchTextStrike* strike, GrBatchAtlas::AtlasID* id,
137 GrBatchTarget* batchTarget,
138 GrMaskFormat format, int width, int height, const void* image,
139 SkIPoint16* loc) {
140 fPreserveStrike = strike;
141 return this->getAtlas(format)->addToAtlas(id, batchTarget, width, height, image, loc);
142 }
joshualitt7c3a2f82015-03-31 13:32:05 -0700143
144 // Some clients may wish to verify the integrity of the texture backing store of the
145 // GrBatchAtlas. The atlasGeneration returned below is a monitonically increasing number which
146 // changes everytime something is removed from the texture backing store.
joshualitt62db8ba2015-04-09 08:22:37 -0700147 uint64_t atlasGeneration(GrMaskFormat format) const {
148 return this->getAtlas(format)->atlasGeneration();
149 }
joshualitt7c3a2f82015-03-31 13:32:05 -0700150
joshualitt7c3a2f82015-03-31 13:32:05 -0700151 void dump() const;
152
153private:
bsalomon265697d2015-07-22 10:17:26 -0700154 static GrPixelConfig MaskFormatToPixelConfig(GrMaskFormat format) {
155 static const GrPixelConfig kPixelConfigs[] = {
156 kAlpha_8_GrPixelConfig,
157 kRGB_565_GrPixelConfig,
158 kSkia8888_GrPixelConfig
159 };
160 SK_COMPILE_ASSERT(SK_ARRAY_COUNT(kPixelConfigs) == kMaskFormatCount, array_size_mismatch);
161
162 return kPixelConfigs[format];
163 }
164
joshualitt7c3a2f82015-03-31 13:32:05 -0700165 // There is a 1:1 mapping between GrMaskFormats and atlas indices
joshualitt62db8ba2015-04-09 08:22:37 -0700166 static int MaskFormatToAtlasIndex(GrMaskFormat format) {
167 static const int sAtlasIndices[] = {
168 kA8_GrMaskFormat,
169 kA565_GrMaskFormat,
170 kARGB_GrMaskFormat,
171 };
172 SK_COMPILE_ASSERT(SK_ARRAY_COUNT(sAtlasIndices) == kMaskFormatCount, array_size_mismatch);
joshualitt7c3a2f82015-03-31 13:32:05 -0700173
joshualitt62db8ba2015-04-09 08:22:37 -0700174 SkASSERT(sAtlasIndices[format] < kMaskFormatCount);
175 return sAtlasIndices[format];
176 }
joshualitt7c3a2f82015-03-31 13:32:05 -0700177
joshualitt62db8ba2015-04-09 08:22:37 -0700178 bool initAtlas(GrMaskFormat);
179
180 GrBatchTextStrike* generateStrike(GrFontScaler* scaler) {
181 GrBatchTextStrike* strike = SkNEW_ARGS(GrBatchTextStrike, (this, scaler->getKey()));
182 fCache.add(strike);
183 return strike;
184 }
185
186 GrBatchAtlas* getAtlas(GrMaskFormat format) const {
187 int atlasIndex = MaskFormatToAtlasIndex(format);
188 SkASSERT(fAtlases[atlasIndex]);
189 return fAtlases[atlasIndex];
190 }
joshualitt7c3a2f82015-03-31 13:32:05 -0700191
192 static void HandleEviction(GrBatchAtlas::AtlasID, void*);
193
joshualitt62db8ba2015-04-09 08:22:37 -0700194 GrContext* fContext;
joshualitt7c3a2f82015-03-31 13:32:05 -0700195 SkTDynamicHash<GrBatchTextStrike, GrFontDescKey> fCache;
joshualitt7c3a2f82015-03-31 13:32:05 -0700196 GrBatchAtlas* fAtlases[kMaskFormatCount];
197 GrBatchTextStrike* fPreserveStrike;
198};
199
200#endif