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 : #include "GrAtlasGlyphCache.h"
9 : #include "GrContext.h"
10 : #include "GrGpu.h"
11 : #include "GrRectanizer.h"
12 : #include "GrResourceProvider.h"
13 : #include "GrSurfacePriv.h"
14 : #include "SkAutoMalloc.h"
15 : #include "SkString.h"
16 :
17 : #include "SkDistanceFieldGen.h"
18 : #include "GrDistanceFieldGenFromVector.h"
19 :
20 0 : bool GrAtlasGlyphCache::initAtlas(GrMaskFormat format) {
21 0 : int index = MaskFormatToAtlasIndex(format);
22 0 : if (!fAtlases[index]) {
23 0 : GrPixelConfig config = MaskFormatToPixelConfig(format, *fContext->caps());
24 0 : int width = fAtlasConfigs[index].fWidth;
25 0 : int height = fAtlasConfigs[index].fHeight;
26 0 : int numPlotsX = fAtlasConfigs[index].numPlotsX();
27 0 : int numPlotsY = fAtlasConfigs[index].numPlotsY();
28 :
29 0 : fAtlases[index] = GrDrawOpAtlas::Make(
30 : fContext, config, width, height, numPlotsX, numPlotsY,
31 0 : &GrAtlasGlyphCache::HandleEviction, (void*)this);
32 0 : if (!fAtlases[index]) {
33 0 : return false;
34 : }
35 : }
36 0 : return true;
37 : }
38 :
39 0 : GrAtlasGlyphCache::GrAtlasGlyphCache(GrContext* context)
40 : : fContext(context)
41 0 : , fPreserveStrike(nullptr) {
42 :
43 : // setup default atlas configs
44 0 : fAtlasConfigs[kA8_GrMaskFormat].fWidth = 2048;
45 0 : fAtlasConfigs[kA8_GrMaskFormat].fHeight = 2048;
46 0 : fAtlasConfigs[kA8_GrMaskFormat].fLog2Width = 11;
47 0 : fAtlasConfigs[kA8_GrMaskFormat].fLog2Height = 11;
48 0 : fAtlasConfigs[kA8_GrMaskFormat].fPlotWidth = 512;
49 0 : fAtlasConfigs[kA8_GrMaskFormat].fPlotHeight = 256;
50 :
51 0 : fAtlasConfigs[kA565_GrMaskFormat].fWidth = 1024;
52 0 : fAtlasConfigs[kA565_GrMaskFormat].fHeight = 2048;
53 0 : fAtlasConfigs[kA565_GrMaskFormat].fLog2Width = 10;
54 0 : fAtlasConfigs[kA565_GrMaskFormat].fLog2Height = 11;
55 0 : fAtlasConfigs[kA565_GrMaskFormat].fPlotWidth = 256;
56 0 : fAtlasConfigs[kA565_GrMaskFormat].fPlotHeight = 256;
57 :
58 0 : fAtlasConfigs[kARGB_GrMaskFormat].fWidth = 1024;
59 0 : fAtlasConfigs[kARGB_GrMaskFormat].fHeight = 2048;
60 0 : fAtlasConfigs[kARGB_GrMaskFormat].fLog2Width = 10;
61 0 : fAtlasConfigs[kARGB_GrMaskFormat].fLog2Height = 11;
62 0 : fAtlasConfigs[kARGB_GrMaskFormat].fPlotWidth = 256;
63 0 : fAtlasConfigs[kARGB_GrMaskFormat].fPlotHeight = 256;
64 0 : }
65 :
66 0 : GrAtlasGlyphCache::~GrAtlasGlyphCache() {
67 0 : StrikeHash::Iter iter(&fCache);
68 0 : while (!iter.done()) {
69 0 : (*iter).fIsAbandoned = true;
70 0 : (*iter).unref();
71 0 : ++iter;
72 : }
73 0 : }
74 :
75 0 : void GrAtlasGlyphCache::freeAll() {
76 0 : StrikeHash::Iter iter(&fCache);
77 0 : while (!iter.done()) {
78 0 : (*iter).fIsAbandoned = true;
79 0 : (*iter).unref();
80 0 : ++iter;
81 : }
82 0 : fCache.rewind();
83 0 : for (int i = 0; i < kMaskFormatCount; ++i) {
84 0 : fAtlases[i] = nullptr;
85 : }
86 0 : }
87 :
88 0 : void GrAtlasGlyphCache::HandleEviction(GrDrawOpAtlas::AtlasID id, void* ptr) {
89 0 : GrAtlasGlyphCache* fontCache = reinterpret_cast<GrAtlasGlyphCache*>(ptr);
90 :
91 0 : StrikeHash::Iter iter(&fontCache->fCache);
92 0 : for (; !iter.done(); ++iter) {
93 0 : GrAtlasTextStrike* strike = &*iter;
94 0 : strike->removeID(id);
95 :
96 : // clear out any empty strikes. We will preserve the strike whose call to addToAtlas
97 : // triggered the eviction
98 0 : if (strike != fontCache->fPreserveStrike && 0 == strike->fAtlasedGlyphs) {
99 0 : fontCache->fCache.remove(GrAtlasTextStrike::GetKey(*strike));
100 0 : strike->fIsAbandoned = true;
101 0 : strike->unref();
102 : }
103 : }
104 0 : }
105 :
106 : #ifdef SK_DEBUG
107 : #include "GrContextPriv.h"
108 : #include "GrSurfaceProxy.h"
109 : #include "GrSurfaceContext.h"
110 : #include "GrTextureProxy.h"
111 :
112 : #include "SkBitmap.h"
113 : #include "SkImageEncoder.h"
114 : #include "SkStream.h"
115 : #include <stdio.h>
116 :
117 : /**
118 : * Write the contents of the surface proxy to a PNG. Returns true if successful.
119 : * @param filename Full path to desired file
120 : */
121 0 : static bool save_pixels(GrContext* context, GrSurfaceProxy* sProxy, const char* filename) {
122 0 : if (!sProxy) {
123 0 : return false;
124 : }
125 :
126 : SkImageInfo ii = SkImageInfo::Make(sProxy->width(), sProxy->height(),
127 0 : kRGBA_8888_SkColorType, kPremul_SkAlphaType);
128 0 : SkBitmap bm;
129 0 : if (!bm.tryAllocPixels(ii)) {
130 0 : return false;
131 : }
132 :
133 0 : sk_sp<GrSurfaceContext> sContext(context->contextPriv().makeWrappedSurfaceContext(
134 0 : sk_ref_sp(sProxy),
135 0 : nullptr));
136 0 : if (!sContext || !sContext->asTextureProxy()) {
137 0 : return false;
138 : }
139 :
140 0 : bool result = sContext->readPixels(ii, bm.getPixels(), bm.rowBytes(), 0, 0);
141 0 : if (!result) {
142 0 : SkDebugf("------ failed to read pixels for %s\n", filename);
143 0 : return false;
144 : }
145 :
146 : // remove any previous version of this file
147 0 : remove(filename);
148 :
149 0 : SkFILEWStream file(filename);
150 0 : if (!file.isValid()) {
151 0 : SkDebugf("------ failed to create file: %s\n", filename);
152 0 : remove(filename); // remove any partial file
153 0 : return false;
154 : }
155 :
156 0 : if (!SkEncodeImage(&file, bm, SkEncodedImageFormat::kPNG, 100)) {
157 0 : SkDebugf("------ failed to encode %s\n", filename);
158 0 : remove(filename); // remove any partial file
159 0 : return false;
160 : }
161 :
162 0 : return true;
163 : }
164 :
165 0 : void GrAtlasGlyphCache::dump() const {
166 : static int gDumpCount = 0;
167 0 : for (int i = 0; i < kMaskFormatCount; ++i) {
168 0 : if (fAtlases[i]) {
169 0 : sk_sp<GrTextureProxy> proxy = fAtlases[i]->getProxy();
170 0 : if (proxy) {
171 0 : SkString filename;
172 : #ifdef SK_BUILD_FOR_ANDROID
173 : filename.printf("/sdcard/fontcache_%d%d.png", gDumpCount, i);
174 : #else
175 0 : filename.printf("fontcache_%d%d.png", gDumpCount, i);
176 : #endif
177 :
178 0 : save_pixels(fContext, proxy.get(), filename.c_str());
179 : }
180 : }
181 : }
182 0 : ++gDumpCount;
183 0 : }
184 : #endif
185 :
186 0 : void GrAtlasGlyphCache::setAtlasSizes_ForTesting(const GrDrawOpAtlasConfig configs[3]) {
187 : // Delete any old atlases.
188 : // This should be safe to do as long as we are not in the middle of a flush.
189 0 : for (int i = 0; i < kMaskFormatCount; i++) {
190 0 : fAtlases[i] = nullptr;
191 : }
192 0 : memcpy(fAtlasConfigs, configs, sizeof(fAtlasConfigs));
193 0 : }
194 :
195 : ///////////////////////////////////////////////////////////////////////////////
196 :
197 0 : static inline GrMaskFormat get_packed_glyph_mask_format(const SkGlyph& glyph) {
198 0 : SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
199 0 : switch (format) {
200 : case SkMask::kBW_Format:
201 : // fall through to kA8 -- we store BW glyphs in our 8-bit cache
202 : case SkMask::kA8_Format:
203 0 : return kA8_GrMaskFormat;
204 : case SkMask::kLCD16_Format:
205 0 : return kA565_GrMaskFormat;
206 : case SkMask::kARGB32_Format:
207 0 : return kARGB_GrMaskFormat;
208 : default:
209 0 : SkDEBUGFAIL("unsupported SkMask::Format");
210 0 : return kA8_GrMaskFormat;
211 : }
212 : }
213 :
214 0 : static inline bool get_packed_glyph_bounds(SkGlyphCache* cache, const SkGlyph& glyph,
215 : SkIRect* bounds) {
216 : #if 1
217 : // crbug:510931
218 : // Retrieving the image from the cache can actually change the mask format.
219 0 : cache->findImage(glyph);
220 : #endif
221 0 : bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight);
222 :
223 0 : return true;
224 : }
225 :
226 0 : static inline bool get_packed_glyph_df_bounds(SkGlyphCache* cache, const SkGlyph& glyph,
227 : SkIRect* bounds) {
228 : #if 1
229 : // crbug:510931
230 : // Retrieving the image from the cache can actually change the mask format.
231 0 : cache->findImage(glyph);
232 : #endif
233 0 : bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight);
234 0 : bounds->outset(SK_DistanceFieldPad, SK_DistanceFieldPad);
235 :
236 0 : return true;
237 : }
238 :
239 : // expands each bit in a bitmask to 0 or ~0 of type INT_TYPE. Used to expand a BW glyph mask to
240 : // A8, RGB565, or RGBA8888.
241 : template <typename INT_TYPE>
242 0 : static void expand_bits(INT_TYPE* dst,
243 : const uint8_t* src,
244 : int width,
245 : int height,
246 : int dstRowBytes,
247 : int srcRowBytes) {
248 0 : for (int i = 0; i < height; ++i) {
249 0 : int rowWritesLeft = width;
250 0 : const uint8_t* s = src;
251 0 : INT_TYPE* d = dst;
252 0 : while (rowWritesLeft > 0) {
253 0 : unsigned mask = *s++;
254 0 : for (int i = 7; i >= 0 && rowWritesLeft; --i, --rowWritesLeft) {
255 0 : *d++ = (mask & (1 << i)) ? (INT_TYPE)(~0UL) : 0;
256 : }
257 : }
258 0 : dst = reinterpret_cast<INT_TYPE*>(reinterpret_cast<intptr_t>(dst) + dstRowBytes);
259 0 : src += srcRowBytes;
260 : }
261 0 : }
262 :
263 0 : static bool get_packed_glyph_image(SkGlyphCache* cache, const SkGlyph& glyph, int width,
264 : int height, int dstRB, GrMaskFormat expectedMaskFormat,
265 : void* dst) {
266 0 : SkASSERT(glyph.fWidth == width);
267 0 : SkASSERT(glyph.fHeight == height);
268 0 : const void* src = cache->findImage(glyph);
269 0 : if (nullptr == src) {
270 0 : return false;
271 : }
272 :
273 : // crbug:510931
274 : // Retrieving the image from the cache can actually change the mask format. This case is very
275 : // uncommon so for now we just draw a clear box for these glyphs.
276 0 : if (get_packed_glyph_mask_format(glyph) != expectedMaskFormat) {
277 0 : const int bpp = GrMaskFormatBytesPerPixel(expectedMaskFormat);
278 0 : for (int y = 0; y < height; y++) {
279 0 : sk_bzero(dst, width * bpp);
280 0 : dst = (char*)dst + dstRB;
281 : }
282 0 : return true;
283 : }
284 :
285 0 : int srcRB = glyph.rowBytes();
286 : // The windows font host sometimes has BW glyphs in a non-BW strike. So it is important here to
287 : // check the glyph's format, not the strike's format, and to be able to convert to any of the
288 : // GrMaskFormats.
289 0 : if (SkMask::kBW_Format == glyph.fMaskFormat) {
290 : // expand bits to our mask type
291 0 : const uint8_t* bits = reinterpret_cast<const uint8_t*>(src);
292 0 : switch (expectedMaskFormat) {
293 : case kA8_GrMaskFormat:{
294 0 : uint8_t* bytes = reinterpret_cast<uint8_t*>(dst);
295 0 : expand_bits(bytes, bits, width, height, dstRB, srcRB);
296 0 : break;
297 : }
298 : case kA565_GrMaskFormat: {
299 0 : uint16_t* rgb565 = reinterpret_cast<uint16_t*>(dst);
300 0 : expand_bits(rgb565, bits, width, height, dstRB, srcRB);
301 0 : break;
302 : }
303 : default:
304 0 : SkFAIL("Invalid GrMaskFormat");
305 : }
306 0 : } else if (srcRB == dstRB) {
307 0 : memcpy(dst, src, dstRB * height);
308 : } else {
309 0 : const int bbp = GrMaskFormatBytesPerPixel(expectedMaskFormat);
310 0 : for (int y = 0; y < height; y++) {
311 0 : memcpy(dst, src, width * bbp);
312 0 : src = (const char*)src + srcRB;
313 0 : dst = (char*)dst + dstRB;
314 : }
315 : }
316 0 : return true;
317 : }
318 :
319 0 : static bool get_packed_glyph_df_image(SkGlyphCache* cache, const SkGlyph& glyph,
320 : int width, int height, void* dst) {
321 0 : SkASSERT(glyph.fWidth + 2*SK_DistanceFieldPad == width);
322 0 : SkASSERT(glyph.fHeight + 2*SK_DistanceFieldPad == height);
323 :
324 : #ifndef SK_USE_LEGACY_DISTANCE_FIELDS
325 : const SkPath* path = cache->findPath(glyph);
326 : if (nullptr == path) {
327 : return false;
328 : }
329 :
330 : SkDEBUGCODE(SkRect glyphBounds = SkRect::MakeXYWH(glyph.fLeft,
331 : glyph.fTop,
332 : glyph.fWidth,
333 : glyph.fHeight));
334 : SkASSERT(glyphBounds.contains(path->getBounds()));
335 :
336 : // now generate the distance field
337 : SkASSERT(dst);
338 : SkMatrix drawMatrix;
339 : drawMatrix.setTranslate((SkScalar)-glyph.fLeft, (SkScalar)-glyph.fTop);
340 :
341 : // Generate signed distance field directly from SkPath
342 : bool succeed = GrGenerateDistanceFieldFromPath((unsigned char*)dst,
343 : *path, drawMatrix,
344 : width, height, width * sizeof(unsigned char));
345 :
346 : if (!succeed) {
347 : #endif
348 0 : const void* image = cache->findImage(glyph);
349 0 : if (nullptr == image) {
350 0 : return false;
351 : }
352 :
353 : // now generate the distance field
354 0 : SkASSERT(dst);
355 0 : SkMask::Format maskFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
356 0 : if (SkMask::kA8_Format == maskFormat) {
357 : // make the distance field from the image
358 0 : SkGenerateDistanceFieldFromA8Image((unsigned char*)dst,
359 : (unsigned char*)image,
360 0 : glyph.fWidth, glyph.fHeight,
361 0 : glyph.rowBytes());
362 0 : } else if (SkMask::kBW_Format == maskFormat) {
363 : // make the distance field from the image
364 0 : SkGenerateDistanceFieldFromBWImage((unsigned char*)dst,
365 : (unsigned char*)image,
366 0 : glyph.fWidth, glyph.fHeight,
367 0 : glyph.rowBytes());
368 : } else {
369 0 : return false;
370 : }
371 : #ifndef SK_USE_LEGACY_DISTANCE_FIELDS
372 : }
373 : #endif
374 0 : return true;
375 : }
376 :
377 : ///////////////////////////////////////////////////////////////////////////////
378 :
379 : /*
380 : The text strike is specific to a given font/style/matrix setup, which is
381 : represented by the GrHostFontScaler object we are given in getGlyph().
382 :
383 : We map a 32bit glyphID to a GrGlyph record, which in turn points to a
384 : atlas and a position within that texture.
385 : */
386 :
387 0 : GrAtlasTextStrike::GrAtlasTextStrike(GrAtlasGlyphCache* owner, const SkDescriptor& key)
388 : : fFontScalerKey(key)
389 : , fPool(9/*start allocations at 512 bytes*/)
390 : , fAtlasGlyphCache(owner) // no need to ref, it won't go away before we do
391 : , fAtlasedGlyphs(0)
392 0 : , fIsAbandoned(false) {}
393 :
394 0 : GrAtlasTextStrike::~GrAtlasTextStrike() {
395 0 : SkTDynamicHash<GrGlyph, GrGlyph::PackedID>::Iter iter(&fCache);
396 0 : while (!iter.done()) {
397 0 : (*iter).reset();
398 0 : ++iter;
399 : }
400 0 : }
401 :
402 0 : GrGlyph* GrAtlasTextStrike::generateGlyph(const SkGlyph& skGlyph, GrGlyph::PackedID packed,
403 : SkGlyphCache* cache) {
404 : SkIRect bounds;
405 0 : if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(packed)) {
406 0 : if (!get_packed_glyph_df_bounds(cache, skGlyph, &bounds)) {
407 0 : return nullptr;
408 : }
409 : } else {
410 0 : if (!get_packed_glyph_bounds(cache, skGlyph, &bounds)) {
411 0 : return nullptr;
412 : }
413 : }
414 0 : GrMaskFormat format = get_packed_glyph_mask_format(skGlyph);
415 :
416 0 : GrGlyph* glyph = (GrGlyph*)fPool.alloc(sizeof(GrGlyph));
417 0 : glyph->init(packed, bounds, format);
418 0 : fCache.add(glyph);
419 0 : return glyph;
420 : }
421 :
422 0 : void GrAtlasTextStrike::removeID(GrDrawOpAtlas::AtlasID id) {
423 0 : SkTDynamicHash<GrGlyph, GrGlyph::PackedID>::Iter iter(&fCache);
424 0 : while (!iter.done()) {
425 0 : if (id == (*iter).fID) {
426 0 : (*iter).fID = GrDrawOpAtlas::kInvalidAtlasID;
427 0 : fAtlasedGlyphs--;
428 0 : SkASSERT(fAtlasedGlyphs >= 0);
429 : }
430 0 : ++iter;
431 : }
432 0 : }
433 :
434 0 : bool GrAtlasTextStrike::addGlyphToAtlas(GrDrawOp::Target* target,
435 : GrGlyph* glyph,
436 : SkGlyphCache* cache,
437 : GrMaskFormat expectedMaskFormat) {
438 0 : SkASSERT(glyph);
439 0 : SkASSERT(cache);
440 0 : SkASSERT(fCache.find(glyph->fPackedID));
441 :
442 0 : int bytesPerPixel = GrMaskFormatBytesPerPixel(expectedMaskFormat);
443 :
444 0 : size_t size = glyph->fBounds.area() * bytesPerPixel;
445 0 : SkAutoSMalloc<1024> storage(size);
446 :
447 0 : const SkGlyph& skGlyph = GrToSkGlyph(cache, glyph->fPackedID);
448 0 : if (GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(glyph->fPackedID)) {
449 0 : if (!get_packed_glyph_df_image(cache, skGlyph, glyph->width(), glyph->height(),
450 : storage.get())) {
451 0 : return false;
452 : }
453 : } else {
454 0 : if (!get_packed_glyph_image(cache, skGlyph, glyph->width(), glyph->height(),
455 0 : glyph->width() * bytesPerPixel, expectedMaskFormat,
456 : storage.get())) {
457 0 : return false;
458 : }
459 : }
460 :
461 0 : bool success = fAtlasGlyphCache->addToAtlas(this, &glyph->fID, target, expectedMaskFormat,
462 : glyph->width(), glyph->height(),
463 0 : storage.get(), &glyph->fAtlasLocation);
464 0 : if (success) {
465 0 : SkASSERT(GrDrawOpAtlas::kInvalidAtlasID != glyph->fID);
466 0 : fAtlasedGlyphs++;
467 : }
468 0 : return success;
469 : }
|