OLD | NEW |
| (Empty) |
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 "GrBatchFontCache.h" | |
9 #include "GrContext.h" | |
10 #include "GrGpu.h" | |
11 #include "GrRectanizer.h" | |
12 #include "GrResourceProvider.h" | |
13 #include "GrSurfacePriv.h" | |
14 #include "SkString.h" | |
15 | |
16 #include "SkDistanceFieldGen.h" | |
17 | |
18 /////////////////////////////////////////////////////////////////////////////// | |
19 | |
20 bool GrBatchFontCache::initAtlas(GrMaskFormat format) { | |
21 int index = MaskFormatToAtlasIndex(format); | |
22 if (!fAtlases[index]) { | |
23 GrPixelConfig config = MaskFormatToPixelConfig(format); | |
24 int width = fAtlasConfigs[index].fWidth; | |
25 int height = fAtlasConfigs[index].fHeight; | |
26 int numPlotsX = fAtlasConfigs[index].numPlotsX(); | |
27 int numPlotsY = fAtlasConfigs[index].numPlotsY(); | |
28 | |
29 fAtlases[index] = | |
30 fContext->resourceProvider()->createAtlas(config, width, height, | |
31 numPlotsX, numPlotsY, | |
32 &GrBatchFontCache::Han
dleEviction, | |
33 (void*)this); | |
34 if (!fAtlases[index]) { | |
35 return false; | |
36 } | |
37 } | |
38 return true; | |
39 } | |
40 | |
41 GrBatchFontCache::GrBatchFontCache(GrContext* context) | |
42 : fContext(context) | |
43 , fPreserveStrike(nullptr) { | |
44 for (int i = 0; i < kMaskFormatCount; ++i) { | |
45 fAtlases[i] = nullptr; | |
46 } | |
47 | |
48 // setup default atlas configs | |
49 fAtlasConfigs[kA8_GrMaskFormat].fWidth = 2048; | |
50 fAtlasConfigs[kA8_GrMaskFormat].fHeight = 2048; | |
51 fAtlasConfigs[kA8_GrMaskFormat].fPlotWidth = 512; | |
52 fAtlasConfigs[kA8_GrMaskFormat].fPlotHeight = 256; | |
53 | |
54 fAtlasConfigs[kA565_GrMaskFormat].fWidth = 1024; | |
55 fAtlasConfigs[kA565_GrMaskFormat].fHeight = 2048; | |
56 fAtlasConfigs[kA565_GrMaskFormat].fPlotWidth = 256; | |
57 fAtlasConfigs[kA565_GrMaskFormat].fPlotHeight = 256; | |
58 | |
59 fAtlasConfigs[kARGB_GrMaskFormat].fWidth = 1024; | |
60 fAtlasConfigs[kARGB_GrMaskFormat].fHeight = 2048; | |
61 fAtlasConfigs[kARGB_GrMaskFormat].fPlotWidth = 256; | |
62 fAtlasConfigs[kARGB_GrMaskFormat].fPlotHeight = 256; | |
63 } | |
64 | |
65 GrBatchFontCache::~GrBatchFontCache() { | |
66 SkTDynamicHash<GrBatchTextStrike, GrFontDescKey>::Iter iter(&fCache); | |
67 while (!iter.done()) { | |
68 (*iter).fIsAbandoned = true; | |
69 (*iter).unref(); | |
70 ++iter; | |
71 } | |
72 for (int i = 0; i < kMaskFormatCount; ++i) { | |
73 delete fAtlases[i]; | |
74 } | |
75 } | |
76 | |
77 void GrBatchFontCache::freeAll() { | |
78 SkTDynamicHash<GrBatchTextStrike, GrFontDescKey>::Iter iter(&fCache); | |
79 while (!iter.done()) { | |
80 (*iter).fIsAbandoned = true; | |
81 (*iter).unref(); | |
82 ++iter; | |
83 } | |
84 fCache.rewind(); | |
85 for (int i = 0; i < kMaskFormatCount; ++i) { | |
86 delete fAtlases[i]; | |
87 fAtlases[i] = nullptr; | |
88 } | |
89 } | |
90 | |
91 void GrBatchFontCache::HandleEviction(GrBatchAtlas::AtlasID id, void* ptr) { | |
92 GrBatchFontCache* fontCache = reinterpret_cast<GrBatchFontCache*>(ptr); | |
93 | |
94 SkTDynamicHash<GrBatchTextStrike, GrFontDescKey>::Iter iter(&fontCache->fCac
he); | |
95 for (; !iter.done(); ++iter) { | |
96 GrBatchTextStrike* strike = &*iter; | |
97 strike->removeID(id); | |
98 | |
99 // clear out any empty strikes. We will preserve the strike whose call
to addToAtlas | |
100 // triggered the eviction | |
101 if (strike != fontCache->fPreserveStrike && 0 == strike->fAtlasedGlyphs)
{ | |
102 fontCache->fCache.remove(*(strike->fFontScalerKey)); | |
103 strike->fIsAbandoned = true; | |
104 strike->unref(); | |
105 } | |
106 } | |
107 } | |
108 | |
109 void GrBatchFontCache::dump() const { | |
110 static int gDumpCount = 0; | |
111 for (int i = 0; i < kMaskFormatCount; ++i) { | |
112 if (fAtlases[i]) { | |
113 GrTexture* texture = fAtlases[i]->getTexture(); | |
114 if (texture) { | |
115 SkString filename; | |
116 #ifdef SK_BUILD_FOR_ANDROID | |
117 filename.printf("/sdcard/fontcache_%d%d.png", gDumpCount, i); | |
118 #else | |
119 filename.printf("fontcache_%d%d.png", gDumpCount, i); | |
120 #endif | |
121 texture->surfacePriv().savePixels(filename.c_str()); | |
122 } | |
123 } | |
124 } | |
125 ++gDumpCount; | |
126 } | |
127 | |
128 void GrBatchFontCache::setAtlasSizes_ForTesting(const GrBatchAtlasConfig configs
[3]) { | |
129 // delete any old atlases, this should be safe to do as long as we are not i
n the middle of a | |
130 // flush | |
131 for (int i = 0; i < kMaskFormatCount; i++) { | |
132 if (fAtlases[i]) { | |
133 delete fAtlases[i]; | |
134 fAtlases[i] = nullptr; | |
135 } | |
136 } | |
137 memcpy(fAtlasConfigs, configs, sizeof(fAtlasConfigs)); | |
138 } | |
139 | |
140 /////////////////////////////////////////////////////////////////////////////// | |
141 | |
142 /* | |
143 The text strike is specific to a given font/style/matrix setup, which is | |
144 represented by the GrHostFontScaler object we are given in getGlyph(). | |
145 | |
146 We map a 32bit glyphID to a GrGlyph record, which in turn points to a | |
147 atlas and a position within that texture. | |
148 */ | |
149 | |
150 GrBatchTextStrike::GrBatchTextStrike(GrBatchFontCache* cache, const GrFontDescKe
y* key) | |
151 : fFontScalerKey(SkRef(key)) | |
152 , fPool(9/*start allocations at 512 bytes*/) | |
153 , fAtlasedGlyphs(0) | |
154 , fIsAbandoned(false) { | |
155 | |
156 fBatchFontCache = cache; // no need to ref, it won't go away before we d
o | |
157 } | |
158 | |
159 GrBatchTextStrike::~GrBatchTextStrike() { | |
160 SkTDynamicHash<GrGlyph, GrGlyph::PackedID>::Iter iter(&fCache); | |
161 while (!iter.done()) { | |
162 (*iter).free(); | |
163 ++iter; | |
164 } | |
165 } | |
166 | |
167 GrGlyph* GrBatchTextStrike::generateGlyph(const SkGlyph& skGlyph, GrGlyph::Packe
dID packed, | |
168 GrFontScaler* scaler) { | |
169 SkIRect bounds; | |
170 if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(packed)) { | |
171 if (!scaler->getPackedGlyphDFBounds(skGlyph, &bounds)) { | |
172 return nullptr; | |
173 } | |
174 } else { | |
175 if (!scaler->getPackedGlyphBounds(skGlyph, &bounds)) { | |
176 return nullptr; | |
177 } | |
178 } | |
179 GrMaskFormat format = scaler->getPackedGlyphMaskFormat(skGlyph); | |
180 | |
181 GrGlyph* glyph = (GrGlyph*)fPool.alloc(sizeof(GrGlyph)); | |
182 glyph->init(packed, bounds, format); | |
183 fCache.add(glyph); | |
184 return glyph; | |
185 } | |
186 | |
187 void GrBatchTextStrike::removeID(GrBatchAtlas::AtlasID id) { | |
188 SkTDynamicHash<GrGlyph, GrGlyph::PackedID>::Iter iter(&fCache); | |
189 while (!iter.done()) { | |
190 if (id == (*iter).fID) { | |
191 (*iter).fID = GrBatchAtlas::kInvalidAtlasID; | |
192 fAtlasedGlyphs--; | |
193 SkASSERT(fAtlasedGlyphs >= 0); | |
194 } | |
195 ++iter; | |
196 } | |
197 } | |
198 | |
199 bool GrBatchTextStrike::addGlyphToAtlas(GrDrawBatch::Target* target, | |
200 GrGlyph* glyph, | |
201 GrFontScaler* scaler, | |
202 GrMaskFormat expectedMaskFormat) { | |
203 SkASSERT(glyph); | |
204 SkASSERT(scaler); | |
205 SkASSERT(fCache.find(glyph->fPackedID)); | |
206 | |
207 SkAutoUnref ar(SkSafeRef(scaler)); | |
208 | |
209 int bytesPerPixel = GrMaskFormatBytesPerPixel(expectedMaskFormat); | |
210 | |
211 size_t size = glyph->fBounds.area() * bytesPerPixel; | |
212 SkAutoSMalloc<1024> storage(size); | |
213 | |
214 const SkGlyph& skGlyph = scaler->grToSkGlyph(glyph->fPackedID); | |
215 if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(glyph->fPackedI
D)) { | |
216 if (!scaler->getPackedGlyphDFImage(skGlyph, glyph->width(), glyph->heigh
t(), | |
217 storage.get())) { | |
218 return false; | |
219 } | |
220 } else { | |
221 if (!scaler->getPackedGlyphImage(skGlyph, glyph->width(), glyph->height(
), | |
222 glyph->width() * bytesPerPixel, expecte
dMaskFormat, | |
223 storage.get())) { | |
224 return false; | |
225 } | |
226 } | |
227 | |
228 bool success = fBatchFontCache->addToAtlas(this, &glyph->fID, target, expect
edMaskFormat, | |
229 glyph->width(), glyph->height(), | |
230 storage.get(), &glyph->fAtlasLoca
tion); | |
231 if (success) { | |
232 SkASSERT(GrBatchAtlas::kInvalidAtlasID != glyph->fID); | |
233 fAtlasedGlyphs++; | |
234 } | |
235 return success; | |
236 } | |
OLD | NEW |