blob: 293ba29cd787b766c71bce4a10aed13117a128b1 [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
Herb Derby081e6f32019-01-16 13:46:02 -05008#include "GrStrikeCache.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
Herb Derby081e6f32019-01-16 13:46:02 -050017GrStrikeCache::GrStrikeCache(const GrCaps* caps, size_t maxTextureBytes)
Timothy Liang91e260f2018-06-15 13:28:35 -040018 : fPreserveStrike(nullptr)
Timothy Liang91e260f2018-06-15 13:28:35 -040019 , f565Masks(SkMasks::CreateMasks({0xF800, 0x07E0, 0x001F, 0},
Mike Klein65e84172019-02-13 12:25:55 -050020 GrMaskFormatBytesPerPixel(kA565_GrMaskFormat))) { }
joshualitt62db8ba2015-04-09 08:22:37 -070021
Herb Derby081e6f32019-01-16 13:46:02 -050022GrStrikeCache::~GrStrikeCache() {
bsalomonc5fd5c42016-05-17 11:58:24 -070023 StrikeHash::Iter iter(&fCache);
joshualitt7c3a2f82015-03-31 13:32:05 -070024 while (!iter.done()) {
joshualitta5f1d5a2015-05-22 13:09:57 -070025 (*iter).fIsAbandoned = true;
joshualittae32c102015-04-21 09:37:57 -070026 (*iter).unref();
joshualitt7c3a2f82015-03-31 13:32:05 -070027 ++iter;
28 }
joshualitt7c3a2f82015-03-31 13:32:05 -070029}
30
Herb Derby081e6f32019-01-16 13:46:02 -050031void GrStrikeCache::freeAll() {
bsalomonc5fd5c42016-05-17 11:58:24 -070032 StrikeHash::Iter iter(&fCache);
joshualitt7c3a2f82015-03-31 13:32:05 -070033 while (!iter.done()) {
joshualitta5f1d5a2015-05-22 13:09:57 -070034 (*iter).fIsAbandoned = true;
joshualittae32c102015-04-21 09:37:57 -070035 (*iter).unref();
joshualitt7c3a2f82015-03-31 13:32:05 -070036 ++iter;
37 }
38 fCache.rewind();
joshualitt7c3a2f82015-03-31 13:32:05 -070039}
40
Herb Derby081e6f32019-01-16 13:46:02 -050041void GrStrikeCache::HandleEviction(GrDrawOpAtlas::AtlasID id, void* ptr) {
42 GrStrikeCache* glyphCache = reinterpret_cast<GrStrikeCache*>(ptr);
joshualitt7c3a2f82015-03-31 13:32:05 -070043
Robert Phillipsc4039ea2018-03-01 11:36:45 -050044 StrikeHash::Iter iter(&glyphCache->fCache);
joshualitt7c3a2f82015-03-31 13:32:05 -070045 for (; !iter.done(); ++iter) {
Robert Phillipscaf1ebb2018-03-01 14:28:44 -050046 GrTextStrike* strike = &*iter;
joshualitt7c3a2f82015-03-31 13:32:05 -070047 strike->removeID(id);
48
49 // clear out any empty strikes. We will preserve the strike whose call to addToAtlas
50 // triggered the eviction
Robert Phillipsc4039ea2018-03-01 11:36:45 -050051 if (strike != glyphCache->fPreserveStrike && 0 == strike->fAtlasedGlyphs) {
Robert Phillipscaf1ebb2018-03-01 14:28:44 -050052 glyphCache->fCache.remove(GrTextStrike::GetKey(*strike));
joshualittae32c102015-04-21 09:37:57 -070053 strike->fIsAbandoned = true;
54 strike->unref();
joshualitt7c3a2f82015-03-31 13:32:05 -070055 }
56 }
57}
58
bsalomonc2878e22016-05-17 13:18:03 -070059// expands each bit in a bitmask to 0 or ~0 of type INT_TYPE. Used to expand a BW glyph mask to
60// A8, RGB565, or RGBA8888.
61template <typename INT_TYPE>
62static void expand_bits(INT_TYPE* dst,
63 const uint8_t* src,
64 int width,
65 int height,
66 int dstRowBytes,
67 int srcRowBytes) {
68 for (int i = 0; i < height; ++i) {
69 int rowWritesLeft = width;
70 const uint8_t* s = src;
71 INT_TYPE* d = dst;
72 while (rowWritesLeft > 0) {
73 unsigned mask = *s++;
74 for (int i = 7; i >= 0 && rowWritesLeft; --i, --rowWritesLeft) {
75 *d++ = (mask & (1 << i)) ? (INT_TYPE)(~0UL) : 0;
76 }
77 }
78 dst = reinterpret_cast<INT_TYPE*>(reinterpret_cast<intptr_t>(dst) + dstRowBytes);
79 src += srcRowBytes;
80 }
81}
82
Herb Derby5fd955e2019-01-16 11:23:29 -050083static bool get_packed_glyph_image(SkStrike* cache, const SkGlyph& glyph, int width,
bsalomonc2878e22016-05-17 13:18:03 -070084 int height, int dstRB, GrMaskFormat expectedMaskFormat,
Timothy Liang91e260f2018-06-15 13:28:35 -040085 void* dst, const SkMasks& masks) {
bsalomonc2878e22016-05-17 13:18:03 -070086 SkASSERT(glyph.fWidth == width);
87 SkASSERT(glyph.fHeight == height);
88 const void* src = cache->findImage(glyph);
89 if (nullptr == src) {
90 return false;
91 }
92
Timothy Liang91e260f2018-06-15 13:28:35 -040093 // Convert if the glyph uses a 565 mask format since it is using LCD text rendering but the
94 // expected format is 8888 (will happen on macOS with Metal since that combination does not
95 // support 565).
Herb Derby5a3fdee2018-12-20 14:47:03 -050096 if (kA565_GrMaskFormat == GrGlyph::FormatFromSkGlyph(glyph) &&
Timothy Liang91e260f2018-06-15 13:28:35 -040097 kARGB_GrMaskFormat == expectedMaskFormat) {
98 const int a565Bpp = GrMaskFormatBytesPerPixel(kA565_GrMaskFormat);
99 const int argbBpp = GrMaskFormatBytesPerPixel(kARGB_GrMaskFormat);
100 for (int y = 0; y < height; y++) {
101 for (int x = 0; x < width; x++) {
102 uint16_t color565 = 0;
103 memcpy(&color565, src, a565Bpp);
104 uint32_t colorRGBA = GrColorPackRGBA(masks.getRed(color565),
105 masks.getGreen(color565),
106 masks.getBlue(color565),
107 0xFF);
108 memcpy(dst, &colorRGBA, argbBpp);
109 src = (char*)src + a565Bpp;
110 dst = (char*)dst + argbBpp;
111 }
112 }
113 return true;
114 }
115
bsalomonc2878e22016-05-17 13:18:03 -0700116 // crbug:510931
117 // Retrieving the image from the cache can actually change the mask format. This case is very
118 // uncommon so for now we just draw a clear box for these glyphs.
Herb Derby5a3fdee2018-12-20 14:47:03 -0500119 if (GrGlyph::FormatFromSkGlyph(glyph) != expectedMaskFormat) {
bsalomonc2878e22016-05-17 13:18:03 -0700120 const int bpp = GrMaskFormatBytesPerPixel(expectedMaskFormat);
121 for (int y = 0; y < height; y++) {
122 sk_bzero(dst, width * bpp);
123 dst = (char*)dst + dstRB;
124 }
125 return true;
126 }
127
128 int srcRB = glyph.rowBytes();
129 // The windows font host sometimes has BW glyphs in a non-BW strike. So it is important here to
130 // check the glyph's format, not the strike's format, and to be able to convert to any of the
131 // GrMaskFormats.
132 if (SkMask::kBW_Format == glyph.fMaskFormat) {
133 // expand bits to our mask type
134 const uint8_t* bits = reinterpret_cast<const uint8_t*>(src);
135 switch (expectedMaskFormat) {
136 case kA8_GrMaskFormat:{
137 uint8_t* bytes = reinterpret_cast<uint8_t*>(dst);
138 expand_bits(bytes, bits, width, height, dstRB, srcRB);
139 break;
140 }
141 case kA565_GrMaskFormat: {
142 uint16_t* rgb565 = reinterpret_cast<uint16_t*>(dst);
143 expand_bits(rgb565, bits, width, height, dstRB, srcRB);
144 break;
145 }
146 default:
Ben Wagnerb4aab9a2017-08-16 10:53:04 -0400147 SK_ABORT("Invalid GrMaskFormat");
bsalomonc2878e22016-05-17 13:18:03 -0700148 }
149 } else if (srcRB == dstRB) {
150 memcpy(dst, src, dstRB * height);
151 } else {
152 const int bbp = GrMaskFormatBytesPerPixel(expectedMaskFormat);
153 for (int y = 0; y < height; y++) {
154 memcpy(dst, src, width * bbp);
155 src = (const char*)src + srcRB;
156 dst = (char*)dst + dstRB;
157 }
158 }
159 return true;
160}
161
bsalomonc2878e22016-05-17 13:18:03 -0700162///////////////////////////////////////////////////////////////////////////////
163
joshualitt7c3a2f82015-03-31 13:32:05 -0700164/*
165 The text strike is specific to a given font/style/matrix setup, which is
166 represented by the GrHostFontScaler object we are given in getGlyph().
167
168 We map a 32bit glyphID to a GrGlyph record, which in turn points to a
169 atlas and a position within that texture.
170 */
171
Robert Phillipscaf1ebb2018-03-01 14:28:44 -0500172GrTextStrike::GrTextStrike(const SkDescriptor& key)
Herbert Derby83ea5222018-11-28 14:39:29 -0500173 : fFontScalerKey(key) {}
joshualitt7c3a2f82015-03-31 13:32:05 -0700174
Herb Derby4c35be02018-12-20 14:03:47 -0500175GrGlyph* GrTextStrike::generateGlyph(const SkGlyph& skGlyph) {
Herb Derby5a3fdee2018-12-20 14:47:03 -0500176 GrGlyph* grGlyph = fAlloc.make<GrGlyph>(skGlyph);
177 fCache.add(grGlyph);
178 return grGlyph;
joshualitt7c3a2f82015-03-31 13:32:05 -0700179}
180
Robert Phillipscaf1ebb2018-03-01 14:28:44 -0500181void GrTextStrike::removeID(GrDrawOpAtlas::AtlasID id) {
Herb Derby5a3fdee2018-12-20 14:47:03 -0500182 SkTDynamicHash<GrGlyph, SkPackedGlyphID>::Iter iter(&fCache);
joshualitt7c3a2f82015-03-31 13:32:05 -0700183 while (!iter.done()) {
184 if (id == (*iter).fID) {
Brian Salomon2ee084e2016-12-16 18:59:19 -0500185 (*iter).fID = GrDrawOpAtlas::kInvalidAtlasID;
joshualitt7c3a2f82015-03-31 13:32:05 -0700186 fAtlasedGlyphs--;
187 SkASSERT(fAtlasedGlyphs >= 0);
188 }
189 ++iter;
190 }
191}
192
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500193GrDrawOpAtlas::ErrorCode GrTextStrike::addGlyphToAtlas(
194 GrResourceProvider* resourceProvider,
Robert Phillipscaf1ebb2018-03-01 14:28:44 -0500195 GrDeferredUploadTarget* target,
Herb Derby081e6f32019-01-16 13:46:02 -0500196 GrStrikeCache* glyphCache,
Robert Phillipscaf1ebb2018-03-01 14:28:44 -0500197 GrAtlasManager* fullAtlasManager,
198 GrGlyph* glyph,
Herb Derby5fd955e2019-01-16 11:23:29 -0500199 SkStrike* cache,
Jim Van Verthcf838c72018-03-05 14:40:36 -0500200 GrMaskFormat expectedMaskFormat,
201 bool isScaledGlyph) {
joshualitt7c3a2f82015-03-31 13:32:05 -0700202 SkASSERT(glyph);
bsalomonc2878e22016-05-17 13:18:03 -0700203 SkASSERT(cache);
joshualitt7c3a2f82015-03-31 13:32:05 -0700204 SkASSERT(fCache.find(glyph->fPackedID));
joshualitt7c3a2f82015-03-31 13:32:05 -0700205
Timothy Liang91e260f2018-06-15 13:28:35 -0400206 expectedMaskFormat = fullAtlasManager->resolveMaskFormat(expectedMaskFormat);
joshualitt4f19ca32015-07-30 07:59:20 -0700207 int bytesPerPixel = GrMaskFormatBytesPerPixel(expectedMaskFormat);
Jim Van Verthcf838c72018-03-05 14:40:36 -0500208 int width = glyph->width();
209 int height = glyph->height();
210 int rowBytes = width * bytesPerPixel;
joshualitt7c3a2f82015-03-31 13:32:05 -0700211
212 size_t size = glyph->fBounds.area() * bytesPerPixel;
Herb Derby37e21f62018-12-19 19:56:02 -0500213 bool isSDFGlyph = GrGlyph::kDistance_MaskStyle == glyph->maskStyle();
Jim Van Verthcf838c72018-03-05 14:40:36 -0500214 bool addPad = isScaledGlyph && !isSDFGlyph;
215 if (addPad) {
216 width += 2;
217 rowBytes += 2*bytesPerPixel;
218 size += 2 * rowBytes;
219 height += 2;
220 size += 2 * (height + 2) * bytesPerPixel;
221 }
joshualitt29f86792015-05-29 08:06:48 -0700222 SkAutoSMalloc<1024> storage(size);
joshualitt7c3a2f82015-03-31 13:32:05 -0700223
bsalomonc2878e22016-05-17 13:18:03 -0700224 const SkGlyph& skGlyph = GrToSkGlyph(cache, glyph->fPackedID);
Jim Van Verthd401da62018-05-03 10:40:30 -0400225 void* dataPtr = storage.get();
226 if (addPad) {
227 sk_bzero(dataPtr, size);
228 dataPtr = (char*)(dataPtr) + rowBytes + bytesPerPixel;
229 }
230 if (!get_packed_glyph_image(cache, skGlyph, glyph->width(), glyph->height(),
231 rowBytes, expectedMaskFormat,
Timothy Liang91e260f2018-06-15 13:28:35 -0400232 dataPtr, glyphCache->getMasks())) {
Jim Van Verthd401da62018-05-03 10:40:30 -0400233 return GrDrawOpAtlas::ErrorCode::kError;
joshualitt7c3a2f82015-03-31 13:32:05 -0700234 }
235
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500236 GrDrawOpAtlas::ErrorCode result = fullAtlasManager->addToAtlas(
237 resourceProvider, glyphCache, this,
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500238 &glyph->fID, target, expectedMaskFormat,
Jim Van Verthcf838c72018-03-05 14:40:36 -0500239 width, height,
Robert Phillipsc4039ea2018-03-01 11:36:45 -0500240 storage.get(), &glyph->fAtlasLocation);
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500241 if (GrDrawOpAtlas::ErrorCode::kSucceeded == result) {
Jim Van Verthcf838c72018-03-05 14:40:36 -0500242 if (addPad) {
243 glyph->fAtlasLocation.fX += 1;
244 glyph->fAtlasLocation.fY += 1;
245 }
Brian Salomon2ee084e2016-12-16 18:59:19 -0500246 SkASSERT(GrDrawOpAtlas::kInvalidAtlasID != glyph->fID);
joshualitt7c3a2f82015-03-31 13:32:05 -0700247 fAtlasedGlyphs++;
248 }
Robert Phillipsd2e9f762018-03-07 11:54:37 -0500249 return result;
joshualitt7c3a2f82015-03-31 13:32:05 -0700250}