blob: 933a1c04348c1dc4da41bc2d66e724f5b9181043 [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
Robert Phillipsc4039ea2018-03-01 11:36:45 -05008#include "GrGlyphCache.h"
Khushalfa8ff092018-06-06 17:46:38 -07009#include "GrAtlasManager.h"
10#include "GrCaps.h"
Timothy Liang91e260f2018-06-15 13:28:35 -040011#include "GrColor.h"
Khushalfa8ff092018-06-06 17:46:38 -070012#include "GrDistanceFieldGenFromVector.h"
Robert Phillipsf95b1752017-08-31 08:56:07 -040013
Hal Canary95e3c052017-01-11 12:44:43 -050014#include "SkAutoMalloc.h"
Robert Phillipsf95b1752017-08-31 08:56:07 -040015#include "SkDistanceFieldGen.h"
joshualitt7c3a2f82015-03-31 13:32:05 -070016
Khushalfa8ff092018-06-06 17:46:38 -070017GrGlyphCache::GrGlyphCache(const GrCaps* caps, size_t maxTextureBytes)
Timothy Liang91e260f2018-06-15 13:28:35 -040018 : fPreserveStrike(nullptr)
19 , fGlyphSizeLimit(0)
20 , f565Masks(SkMasks::CreateMasks({0xF800, 0x07E0, 0x001F, 0},
21 GrMaskFormatBytesPerPixel(kA565_GrMaskFormat) * 8)) {
Khushalfa8ff092018-06-06 17:46:38 -070022 fGlyphSizeLimit = ComputeGlyphSizeLimit(caps->maxTextureSize(), maxTextureBytes);
joshualitt62db8ba2015-04-09 08:22:37 -070023}
24
Robert Phillipsc4039ea2018-03-01 11:36:45 -050025GrGlyphCache::~GrGlyphCache() {
bsalomonc5fd5c42016-05-17 11:58:24 -070026 StrikeHash::Iter iter(&fCache);
joshualitt7c3a2f82015-03-31 13:32:05 -070027 while (!iter.done()) {
joshualitta5f1d5a2015-05-22 13:09:57 -070028 (*iter).fIsAbandoned = true;
joshualittae32c102015-04-21 09:37:57 -070029 (*iter).unref();
joshualitt7c3a2f82015-03-31 13:32:05 -070030 ++iter;
31 }
joshualitt7c3a2f82015-03-31 13:32:05 -070032}
33
Robert Phillipsc4039ea2018-03-01 11:36:45 -050034void GrGlyphCache::freeAll() {
bsalomonc5fd5c42016-05-17 11:58:24 -070035 StrikeHash::Iter iter(&fCache);
joshualitt7c3a2f82015-03-31 13:32:05 -070036 while (!iter.done()) {
joshualitta5f1d5a2015-05-22 13:09:57 -070037 (*iter).fIsAbandoned = true;
joshualittae32c102015-04-21 09:37:57 -070038 (*iter).unref();
joshualitt7c3a2f82015-03-31 13:32:05 -070039 ++iter;
40 }
41 fCache.rewind();
joshualitt7c3a2f82015-03-31 13:32:05 -070042}
43
Khushalfa8ff092018-06-06 17:46:38 -070044SkScalar GrGlyphCache::ComputeGlyphSizeLimit(int maxTextureSize, size_t maxTextureBytes) {
Herb Derby3c4d5332018-09-07 15:27:57 -040045 return SkGlyphCacheCommon::kSkSideTooBigForAtlas;
Khushalfa8ff092018-06-06 17:46:38 -070046}
47
Robert Phillipsc4039ea2018-03-01 11:36:45 -050048void GrGlyphCache::HandleEviction(GrDrawOpAtlas::AtlasID id, void* ptr) {
49 GrGlyphCache* glyphCache = reinterpret_cast<GrGlyphCache*>(ptr);
joshualitt7c3a2f82015-03-31 13:32:05 -070050
Robert Phillipsc4039ea2018-03-01 11:36:45 -050051 StrikeHash::Iter iter(&glyphCache->fCache);
joshualitt7c3a2f82015-03-31 13:32:05 -070052 for (; !iter.done(); ++iter) {
Robert Phillipscaf1ebb2018-03-01 14:28:44 -050053 GrTextStrike* strike = &*iter;
joshualitt7c3a2f82015-03-31 13:32:05 -070054 strike->removeID(id);
55
56 // clear out any empty strikes. We will preserve the strike whose call to addToAtlas
57 // triggered the eviction
Robert Phillipsc4039ea2018-03-01 11:36:45 -050058 if (strike != glyphCache->fPreserveStrike && 0 == strike->fAtlasedGlyphs) {
Robert Phillipscaf1ebb2018-03-01 14:28:44 -050059 glyphCache->fCache.remove(GrTextStrike::GetKey(*strike));
joshualittae32c102015-04-21 09:37:57 -070060 strike->fIsAbandoned = true;
61 strike->unref();
joshualitt7c3a2f82015-03-31 13:32:05 -070062 }
63 }
64}
65
bsalomonc2878e22016-05-17 13:18:03 -070066static inline GrMaskFormat get_packed_glyph_mask_format(const SkGlyph& glyph) {
67 SkMask::Format format = static_cast<SkMask::Format>(glyph.fMaskFormat);
68 switch (format) {
69 case SkMask::kBW_Format:
Jim Van Verthd401da62018-05-03 10:40:30 -040070 case SkMask::kSDF_Format:
71 // fall through to kA8 -- we store BW and SDF glyphs in our 8-bit cache
bsalomonc2878e22016-05-17 13:18:03 -070072 case SkMask::kA8_Format:
73 return kA8_GrMaskFormat;
Ben Wagner339b84e2017-11-10 16:24:50 -050074 case SkMask::k3D_Format:
75 return kA8_GrMaskFormat; // ignore the mul and add planes, just use the mask
bsalomonc2878e22016-05-17 13:18:03 -070076 case SkMask::kLCD16_Format:
77 return kA565_GrMaskFormat;
78 case SkMask::kARGB32_Format:
79 return kARGB_GrMaskFormat;
80 default:
81 SkDEBUGFAIL("unsupported SkMask::Format");
82 return kA8_GrMaskFormat;
83 }
84}
85
86static inline bool get_packed_glyph_bounds(SkGlyphCache* cache, const SkGlyph& glyph,
87 SkIRect* bounds) {
88#if 1
89 // crbug:510931
90 // Retrieving the image from the cache can actually change the mask format.
91 cache->findImage(glyph);
92#endif
93 bounds->setXYWH(glyph.fLeft, glyph.fTop, glyph.fWidth, glyph.fHeight);
94
95 return true;
96}
97
bsalomonc2878e22016-05-17 13:18:03 -070098// expands each bit in a bitmask to 0 or ~0 of type INT_TYPE. Used to expand a BW glyph mask to
99// A8, RGB565, or RGBA8888.
100template <typename INT_TYPE>
101static void expand_bits(INT_TYPE* dst,
102 const uint8_t* src,
103 int width,
104 int height,
105 int dstRowBytes,
106 int srcRowBytes) {
107 for (int i = 0; i < height; ++i) {
108 int rowWritesLeft = width;
109 const uint8_t* s = src;
110 INT_TYPE* d = dst;
111 while (rowWritesLeft > 0) {
112 unsigned mask = *s++;
113 for (int i = 7; i >= 0 && rowWritesLeft; --i, --rowWritesLeft) {
114 *d++ = (mask & (1 << i)) ? (INT_TYPE)(~0UL) : 0;
115 }
116 }
117 dst = reinterpret_cast<INT_TYPE*>(reinterpret_cast<intptr_t>(dst) + dstRowBytes);
118 src += srcRowBytes;
119 }
120}
121
122static bool get_packed_glyph_image(SkGlyphCache* cache, const SkGlyph& glyph, int width,
123 int height, int dstRB, GrMaskFormat expectedMaskFormat,
Timothy Liang91e260f2018-06-15 13:28:35 -0400124 void* dst, const SkMasks& masks) {
bsalomonc2878e22016-05-17 13:18:03 -0700125 SkASSERT(glyph.fWidth == width);
126 SkASSERT(glyph.fHeight == height);
127 const void* src = cache->findImage(glyph);
128 if (nullptr == src) {
129 return false;
130 }
131
Timothy Liang91e260f2018-06-15 13:28:35 -0400132 // Convert if the glyph uses a 565 mask format since it is using LCD text rendering but the
133 // expected format is 8888 (will happen on macOS with Metal since that combination does not
134 // support 565).
135 if (kA565_GrMaskFormat == get_packed_glyph_mask_format(glyph) &&
136 kARGB_GrMaskFormat == expectedMaskFormat) {
137 const int a565Bpp = GrMaskFormatBytesPerPixel(kA565_GrMaskFormat);
138 const int argbBpp = GrMaskFormatBytesPerPixel(kARGB_GrMaskFormat);
139 for (int y = 0; y < height; y++) {
140 for (int x = 0; x < width; x++) {
141 uint16_t color565 = 0;
142 memcpy(&color565, src, a565Bpp);
143 uint32_t colorRGBA = GrColorPackRGBA(masks.getRed(color565),
144 masks.getGreen(color565),
145 masks.getBlue(color565),
146 0xFF);
147 memcpy(dst, &colorRGBA, argbBpp);
148 src = (char*)src + a565Bpp;
149 dst = (char*)dst + argbBpp;
150 }
151 }
152 return true;
153 }
154
bsalomonc2878e22016-05-17 13:18:03 -0700155 // crbug:510931
156 // Retrieving the image from the cache can actually change the mask format. This case is very
157 // uncommon so for now we just draw a clear box for these glyphs.
158 if (get_packed_glyph_mask_format(glyph) != expectedMaskFormat) {
159 const int bpp = GrMaskFormatBytesPerPixel(expectedMaskFormat);
160 for (int y = 0; y < height; y++) {
161 sk_bzero(dst, width * bpp);
162 dst = (char*)dst + dstRB;
163 }
164 return true;
165 }
166
167 int srcRB = glyph.rowBytes();
168 // The windows font host sometimes has BW glyphs in a non-BW strike. So it is important here to
169 // check the glyph's format, not the strike's format, and to be able to convert to any of the
170 // GrMaskFormats.
171 if (SkMask::kBW_Format == glyph.fMaskFormat) {
172 // expand bits to our mask type
173 const uint8_t* bits = reinterpret_cast<const uint8_t*>(src);
174 switch (expectedMaskFormat) {
175 case kA8_GrMaskFormat:{
176 uint8_t* bytes = reinterpret_cast<uint8_t*>(dst);
177 expand_bits(bytes, bits, width, height, dstRB, srcRB);
178 break;
179 }
180 case kA565_GrMaskFormat: {
181 uint16_t* rgb565 = reinterpret_cast<uint16_t*>(dst);
182 expand_bits(rgb565, bits, width, height, dstRB, srcRB);
183 break;
184 }
185 default:
Ben Wagnerb4aab9a2017-08-16 10:53:04 -0400186 SK_ABORT("Invalid GrMaskFormat");
bsalomonc2878e22016-05-17 13:18:03 -0700187 }
188 } else if (srcRB == dstRB) {
189 memcpy(dst, src, dstRB * height);
190 } else {
191 const int bbp = GrMaskFormatBytesPerPixel(expectedMaskFormat);
192 for (int y = 0; y < height; y++) {
193 memcpy(dst, src, width * bbp);
194 src = (const char*)src + srcRB;
195 dst = (char*)dst + dstRB;
196 }
197 }
198 return true;
199}
200
bsalomonc2878e22016-05-17 13:18:03 -0700201///////////////////////////////////////////////////////////////////////////////
202
joshualitt7c3a2f82015-03-31 13:32:05 -0700203/*
204 The text strike is specific to a given font/style/matrix setup, which is
205 represented by the GrHostFontScaler object we are given in getGlyph().
206
207 We map a 32bit glyphID to a GrGlyph record, which in turn points to a
208 atlas and a position within that texture.
209 */
210
Robert Phillipscaf1ebb2018-03-01 14:28:44 -0500211GrTextStrike::GrTextStrike(const SkDescriptor& key)
bsalomonc5fd5c42016-05-17 11:58:24 -0700212 : fFontScalerKey(key)
joshualitt7c3a2f82015-03-31 13:32:05 -0700213 , fPool(9/*start allocations at 512 bytes*/)
joshualittae32c102015-04-21 09:37:57 -0700214 , fAtlasedGlyphs(0)
bsalomonc5fd5c42016-05-17 11:58:24 -0700215 , fIsAbandoned(false) {}
joshualitt7c3a2f82015-03-31 13:32:05 -0700216
Robert Phillipscaf1ebb2018-03-01 14:28:44 -0500217GrTextStrike::~GrTextStrike() {
joshualitt7c3a2f82015-03-31 13:32:05 -0700218 SkTDynamicHash<GrGlyph, GrGlyph::PackedID>::Iter iter(&fCache);
219 while (!iter.done()) {
mtklein852f15d2016-03-17 10:51:27 -0700220 (*iter).reset();
joshualitt7c3a2f82015-03-31 13:32:05 -0700221 ++iter;
222 }
223}
224
Robert Phillipscaf1ebb2018-03-01 14:28:44 -0500225GrGlyph* GrTextStrike::generateGlyph(const SkGlyph& skGlyph, GrGlyph::PackedID packed,
226 SkGlyphCache* cache) {
joshualitt7c3a2f82015-03-31 13:32:05 -0700227 SkIRect bounds;
Jim Van Verthd401da62018-05-03 10:40:30 -0400228 if (!get_packed_glyph_bounds(cache, skGlyph, &bounds)) {
229 return nullptr;
joshualitt7c3a2f82015-03-31 13:32:05 -0700230 }
bsalomonc2878e22016-05-17 13:18:03 -0700231 GrMaskFormat format = get_packed_glyph_mask_format(skGlyph);
joshualitt6c2c2b02015-07-24 10:37:00 -0700232
Herb Derby9428a372017-04-10 11:25:30 -0400233 GrGlyph* glyph = fPool.make<GrGlyph>();
joshualitt7c3a2f82015-03-31 13:32:05 -0700234 glyph->init(packed, bounds, format);
235 fCache.add(glyph);
236 return glyph;
237}
238
Robert Phillipscaf1ebb2018-03-01 14:28:44 -0500239void GrTextStrike::removeID(GrDrawOpAtlas::AtlasID id) {
joshualitt7c3a2f82015-03-31 13:32:05 -0700240 SkTDynamicHash<GrGlyph, GrGlyph::PackedID>::Iter iter(&fCache);
241 while (!iter.done()) {
242 if (id == (*iter).fID) {
Brian Salomon2ee084e2016-12-16 18:59:19 -0500243 (*iter).fID = GrDrawOpAtlas::kInvalidAtlasID;
joshualitt7c3a2f82015-03-31 13:32:05 -0700244 fAtlasedGlyphs--;
245 SkASSERT(fAtlasedGlyphs >= 0);
246 }
247 ++iter;
248 }
249}
250
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500251GrDrawOpAtlas::ErrorCode GrTextStrike::addGlyphToAtlas(
252 GrResourceProvider* resourceProvider,
Robert Phillipscaf1ebb2018-03-01 14:28:44 -0500253 GrDeferredUploadTarget* target,
254 GrGlyphCache* glyphCache,
255 GrAtlasManager* fullAtlasManager,
256 GrGlyph* glyph,
257 SkGlyphCache* cache,
Jim Van Verthcf838c72018-03-05 14:40:36 -0500258 GrMaskFormat expectedMaskFormat,
259 bool isScaledGlyph) {
joshualitt7c3a2f82015-03-31 13:32:05 -0700260 SkASSERT(glyph);
bsalomonc2878e22016-05-17 13:18:03 -0700261 SkASSERT(cache);
joshualitt7c3a2f82015-03-31 13:32:05 -0700262 SkASSERT(fCache.find(glyph->fPackedID));
joshualitt7c3a2f82015-03-31 13:32:05 -0700263
Timothy Liang91e260f2018-06-15 13:28:35 -0400264 expectedMaskFormat = fullAtlasManager->resolveMaskFormat(expectedMaskFormat);
joshualitt4f19ca32015-07-30 07:59:20 -0700265 int bytesPerPixel = GrMaskFormatBytesPerPixel(expectedMaskFormat);
Jim Van Verthcf838c72018-03-05 14:40:36 -0500266 int width = glyph->width();
267 int height = glyph->height();
268 int rowBytes = width * bytesPerPixel;
joshualitt7c3a2f82015-03-31 13:32:05 -0700269
270 size_t size = glyph->fBounds.area() * bytesPerPixel;
Jim Van Verthcf838c72018-03-05 14:40:36 -0500271 bool isSDFGlyph = GrGlyph::kDistance_MaskStyle == GrGlyph::UnpackMaskStyle(glyph->fPackedID);
272 bool addPad = isScaledGlyph && !isSDFGlyph;
273 if (addPad) {
274 width += 2;
275 rowBytes += 2*bytesPerPixel;
276 size += 2 * rowBytes;
277 height += 2;
278 size += 2 * (height + 2) * bytesPerPixel;
279 }
joshualitt29f86792015-05-29 08:06:48 -0700280 SkAutoSMalloc<1024> storage(size);
joshualitt7c3a2f82015-03-31 13:32:05 -0700281
bsalomonc2878e22016-05-17 13:18:03 -0700282 const SkGlyph& skGlyph = GrToSkGlyph(cache, glyph->fPackedID);
Jim Van Verthd401da62018-05-03 10:40:30 -0400283 void* dataPtr = storage.get();
284 if (addPad) {
285 sk_bzero(dataPtr, size);
286 dataPtr = (char*)(dataPtr) + rowBytes + bytesPerPixel;
287 }
288 if (!get_packed_glyph_image(cache, skGlyph, glyph->width(), glyph->height(),
289 rowBytes, expectedMaskFormat,
Timothy Liang91e260f2018-06-15 13:28:35 -0400290 dataPtr, glyphCache->getMasks())) {
Jim Van Verthd401da62018-05-03 10:40:30 -0400291 return GrDrawOpAtlas::ErrorCode::kError;
joshualitt7c3a2f82015-03-31 13:32:05 -0700292 }
293
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500294 GrDrawOpAtlas::ErrorCode result = fullAtlasManager->addToAtlas(
295 resourceProvider, glyphCache, this,
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500296 &glyph->fID, target, expectedMaskFormat,
Jim Van Verthcf838c72018-03-05 14:40:36 -0500297 width, height,
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500298 storage.get(), &glyph->fAtlasLocation);
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500299 if (GrDrawOpAtlas::ErrorCode::kSucceeded == result) {
Jim Van Verthcf838c72018-03-05 14:40:36 -0500300 if (addPad) {
301 glyph->fAtlasLocation.fX += 1;
302 glyph->fAtlasLocation.fY += 1;
303 }
Brian Salomon2ee084e2016-12-16 18:59:19 -0500304 SkASSERT(GrDrawOpAtlas::kInvalidAtlasID != glyph->fID);
joshualitt7c3a2f82015-03-31 13:32:05 -0700305 fAtlasedGlyphs++;
306 }
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500307 return result;
joshualitt7c3a2f82015-03-31 13:32:05 -0700308}