Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
GrAtlasManager.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2018 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
9
10#include "include/core/SkSize.h"
11#include "include/core/SkSpan.h"
16#include "src/core/SkGlyph.h"
17#include "src/core/SkMask.h"
18#include "src/core/SkMasks.h"
23#include "src/text/gpu/Glyph.h"
26
27#include <cstring>
28#include <tuple>
29
30enum SkColorType : int;
31
34
36 size_t maxTextureBytes,
37 GrDrawOpAtlas::AllowMultitexturing allowMultitexturing,
38 bool supportBilerpAtlas)
39 : fAllowMultitexturing{allowMultitexturing}
40 , fSupportBilerpAtlas{supportBilerpAtlas}
41 , fProxyProvider{proxyProvider}
42 , fCaps{fProxyProvider->refCaps()}
43 , fAtlasConfig{fCaps->maxTextureSize(), maxTextureBytes} { }
44
46
48 for (int i = 0; i < skgpu::kMaskFormatCount; ++i) {
49 fAtlases[i] = nullptr;
50 }
51}
52
54 SkASSERT(glyph);
55 return this->getAtlas(format)->hasID(glyph->fAtlasLocator.plotLocator());
56}
57
58template <typename INT_TYPE>
59static void expand_bits(INT_TYPE* dst,
60 const uint8_t* src,
61 int width,
62 int height,
63 int dstRowBytes,
64 int srcRowBytes) {
65 for (int y = 0; y < height; ++y) {
66 int rowWritesLeft = width;
67 const uint8_t* s = src;
68 INT_TYPE* d = dst;
69 while (rowWritesLeft > 0) {
70 unsigned mask = *s++;
71 for (int x = 7; x >= 0 && rowWritesLeft; --x, --rowWritesLeft) {
72 *d++ = (mask & (1 << x)) ? (INT_TYPE)(~0UL) : 0;
73 }
74 }
75 dst = reinterpret_cast<INT_TYPE*>(reinterpret_cast<intptr_t>(dst) + dstRowBytes);
76 src += srcRowBytes;
77 }
78}
79
81 const SkGlyph& glyph, int dstRB, MaskFormat expectedMaskFormat, void* dst) {
82 const int width = glyph.width();
83 const int height = glyph.height();
84 const void* src = glyph.image();
85 SkASSERT(src != nullptr);
86
88 if (maskFormat == expectedMaskFormat) {
89 int srcRB = glyph.rowBytes();
90 // Notice this comparison is with the glyphs raw mask format, and not its MaskFormat.
91 if (glyph.maskFormat() != SkMask::kBW_Format) {
92 if (srcRB != dstRB) {
93 const int bbp = MaskFormatBytesPerPixel(expectedMaskFormat);
94 for (int y = 0; y < height; y++) {
95 memcpy(dst, src, width * bbp);
96 src = (const char*) src + srcRB;
97 dst = (char*) dst + dstRB;
98 }
99 } else {
100 memcpy(dst, src, dstRB * height);
101 }
102 } else {
103 // Handle 8-bit format by expanding the mask to the expected format.
104 const uint8_t* bits = reinterpret_cast<const uint8_t*>(src);
105 switch (expectedMaskFormat) {
106 case MaskFormat::kA8: {
107 uint8_t* bytes = reinterpret_cast<uint8_t*>(dst);
108 expand_bits(bytes, bits, width, height, dstRB, srcRB);
109 break;
110 }
111 case MaskFormat::kA565: {
112 uint16_t* rgb565 = reinterpret_cast<uint16_t*>(dst);
113 expand_bits(rgb565, bits, width, height, dstRB, srcRB);
114 break;
115 }
116 default:
117 SK_ABORT("Invalid MaskFormat");
118 }
119 }
120 } else if (maskFormat == MaskFormat::kA565 &&
121 expectedMaskFormat == MaskFormat::kARGB) {
122 // Convert if the glyph uses a 565 mask format since it is using LCD text rendering
123 // but the expected format is 8888 (will happen on macOS with Metal since that
124 // combination does not support 565).
125 static constexpr SkMasks masks{
126 {0b1111'1000'0000'0000, 11, 5}, // Red
127 {0b0000'0111'1110'0000, 5, 6}, // Green
128 {0b0000'0000'0001'1111, 0, 5}, // Blue
129 {0, 0, 0} // Alpha
130 };
131 constexpr int a565Bpp = MaskFormatBytesPerPixel(MaskFormat::kA565);
132 constexpr int argbBpp = MaskFormatBytesPerPixel(MaskFormat::kARGB);
133 char* dstRow = (char*)dst;
134 for (int y = 0; y < height; y++) {
135 dst = dstRow;
136 for (int x = 0; x < width; x++) {
137 uint16_t color565 = 0;
138 memcpy(&color565, src, a565Bpp);
139 uint32_t colorRGBA = GrColorPackRGBA(masks.getRed(color565),
140 masks.getGreen(color565),
141 masks.getBlue(color565),
142 0xFF);
143 memcpy(dst, &colorRGBA, argbBpp);
144 src = (const char*)src + a565Bpp;
145 dst = (char*)dst + argbBpp;
146 }
147 dstRow += dstRB;
148 }
149 } else {
151 }
152}
153
154// returns true if glyph successfully added to texture atlas, false otherwise.
156 Glyph* glyph,
157 int srcPadding,
158 GrResourceProvider* resourceProvider,
159 GrDeferredUploadTarget* uploadTarget) {
160#if !defined(SK_DISABLE_SDF_TEXT)
161 SkASSERT(0 <= srcPadding && srcPadding <= SK_DistanceFieldInset);
162#else
163 SkASSERT(0 <= srcPadding);
164#endif
165
166 if (skGlyph.image() == nullptr) {
168 }
169 SkASSERT(glyph != nullptr);
170
171 MaskFormat glyphFormat = Glyph::FormatFromSkGlyph(skGlyph.maskFormat());
172 MaskFormat expectedMaskFormat = this->resolveMaskFormat(glyphFormat);
173 int bytesPerPixel = MaskFormatBytesPerPixel(expectedMaskFormat);
174
175 int padding;
176 switch (srcPadding) {
177 case 0:
178 // The direct mask/image case.
179 padding = 0;
180 if (fSupportBilerpAtlas) {
181 // Force direct masks (glyph with no padding) to have padding.
182 padding = 1;
183 srcPadding = 1;
184 }
185 break;
186 case 1:
187 // The transformed mask/image case.
188 padding = 1;
189 break;
190#if !defined(SK_DISABLE_SDF_TEXT)
192 // The SDFT case.
193 // If the srcPadding == SK_DistanceFieldInset (SDFT case) then the padding is built
194 // into the image on the glyph; no extra padding needed.
195 // TODO: can the SDFT glyph image in the cache be reduced by the padding?
196 padding = 0;
197 break;
198#endif
199 default:
200 // The padding is not one of the know forms.
202 }
203
204 const int width = skGlyph.width() + 2*padding;
205 const int height = skGlyph.height() + 2*padding;
206 int rowBytes = width * bytesPerPixel;
207 size_t size = height * rowBytes;
208
209 // Temporary storage for normalizing glyph image.
210 SkAutoSMalloc<1024> storage(size);
211 void* dataPtr = storage.get();
212 if (padding > 0) {
213 sk_bzero(dataPtr, size);
214 // Advance in one row and one column.
215 dataPtr = (char*)(dataPtr) + rowBytes + bytesPerPixel;
216 }
217
218 get_packed_glyph_image(skGlyph, rowBytes, expectedMaskFormat, dataPtr);
219
220 auto errorCode = this->addToAtlas(resourceProvider,
221 uploadTarget,
222 expectedMaskFormat,
223 width,
224 height,
225 storage.get(),
226 &glyph->fAtlasLocator);
227
228 if (errorCode == GrDrawOpAtlas::ErrorCode::kSucceeded) {
229 glyph->fAtlasLocator.insetSrc(srcPadding);
230 }
231
232 return errorCode;
233}
234
235// add to texture atlas that matches this format
239 int width, int height, const void* image,
240 skgpu::AtlasLocator* atlasLocator) {
241 return this->getAtlas(format)->addToAtlas(resourceProvider, target, width, height, image,
242 atlasLocator);
243}
244
246 MaskFormat format, Glyph* glyph,
247 skgpu::AtlasToken token) {
248 SkASSERT(glyph);
249 if (updater->add(glyph->fAtlasLocator)) {
250 this->getAtlas(format)->setLastUseToken(glyph->fAtlasLocator, token);
251 }
252}
253
254bool GrAtlasManager::initAtlas(MaskFormat format) {
255 int index = MaskFormatToAtlasIndex(format);
256 if (fAtlases[index] == nullptr) {
257 SkColorType colorType = MaskFormatToColorType(format);
259 SkISize atlasDimensions = fAtlasConfig.atlasDimensions(format);
260 SkISize plotDimensions = fAtlasConfig.plotDimensions(format);
261
262 const GrBackendFormat backendFormat =
263 fCaps->getDefaultBackendFormat(grColorType, GrRenderable::kNo);
264
265 fAtlases[index] = GrDrawOpAtlas::Make(fProxyProvider, backendFormat,
266 GrColorTypeToSkColorType(grColorType),
267 GrColorTypeBytesPerPixel(grColorType),
268 atlasDimensions.width(), atlasDimensions.height(),
269 plotDimensions.width(), plotDimensions.height(),
270 this,
271 fAllowMultitexturing,
272 nullptr,
273 /*label=*/"TextAtlas");
274 if (!fAtlases[index]) {
275 return false;
276 }
277 }
278 return true;
279}
280
281////////////////////////////////////////////////////////////////////////////////////////////////
282
283namespace sktext::gpu {
284
285std::tuple<bool, int> GlyphVector::regenerateAtlasForGanesh(
286 int begin, int end, MaskFormat maskFormat, int srcPadding, GrMeshDrawTarget* target) {
287 GrAtlasManager* atlasManager = target->atlasManager();
288 GrDeferredUploadTarget* uploadTarget = target->deferredUploadTarget();
289
290 uint64_t currentAtlasGen = atlasManager->atlasGeneration(maskFormat);
291
292 this->packedGlyphIDToGlyph(target->strikeCache());
293
294 if (fAtlasGeneration != currentAtlasGen) {
295 // Calculate the texture coordinates for the vertexes during first use (fAtlasGeneration
296 // is set to kInvalidAtlasGeneration) or the atlas has changed in subsequent calls..
297 fBulkUseUpdater.reset();
298
299 SkBulkGlyphMetricsAndImages metricsAndImages{fTextStrike->strikeSpec()};
300
301 // Update the atlas information in the GrStrike.
302 auto tokenTracker = uploadTarget->tokenTracker();
303 auto glyphs = fGlyphs.subspan(begin, end - begin);
304 int glyphsPlacedInAtlas = 0;
305 bool success = true;
306 for (const Variant& variant : glyphs) {
307 Glyph* gpuGlyph = variant.glyph;
308 SkASSERT(gpuGlyph != nullptr);
309
310 if (!atlasManager->hasGlyph(maskFormat, gpuGlyph)) {
311 const SkGlyph& skGlyph = *metricsAndImages.glyph(gpuGlyph->fPackedID);
312 auto code = atlasManager->addGlyphToAtlas(
313 skGlyph, gpuGlyph, srcPadding, target->resourceProvider(), uploadTarget);
316 break;
317 }
318 }
319 atlasManager->addGlyphToBulkAndSetUseToken(
320 &fBulkUseUpdater, maskFormat, gpuGlyph,
321 tokenTracker->nextDrawToken());
322 glyphsPlacedInAtlas++;
323 }
324
325 // Update atlas generation if there are no more glyphs to put in the atlas.
326 if (success && begin + glyphsPlacedInAtlas == SkCount(fGlyphs)) {
327 // Need to get the freshest value of the atlas' generation because
328 // updateTextureCoordinates may have changed it.
329 fAtlasGeneration = atlasManager->atlasGeneration(maskFormat);
330 }
331
332 return {success, glyphsPlacedInAtlas};
333 } else {
334 // The atlas hasn't changed, so our texture coordinates are still valid.
335 if (end == SkCount(fGlyphs)) {
336 // The atlas hasn't changed and the texture coordinates are all still valid. Update
337 // all the plots used to the new use token.
338 atlasManager->setUseTokenBulk(fBulkUseUpdater,
339 uploadTarget->tokenTracker()->nextDrawToken(),
340 maskFormat);
341 }
342 return {true, end - begin};
343 }
344}
345
346} // namespace sktext::gpu
static void get_packed_glyph_image(const SkGlyph &glyph, int dstRB, MaskFormat expectedMaskFormat, void *dst)
static void expand_bits(INT_TYPE *dst, const uint8_t *src, int width, int height, int dstRowBytes, int srcRowBytes)
static GrColor GrColorPackRGBA(unsigned r, unsigned g, unsigned b, unsigned a)
Definition GrColor.h:46
static constexpr size_t GrColorTypeBytesPerPixel(GrColorType ct)
static constexpr SkColorType GrColorTypeToSkColorType(GrColorType ct)
GrColorType
static constexpr GrColorType SkColorTypeToGrColorType(SkColorType ct)
static const uint16_t rgb565[kNumPixels]
#define SkUNREACHABLE
Definition SkAssert.h:135
#define SK_ABORT(message,...)
Definition SkAssert.h:70
#define SkASSERT(cond)
Definition SkAssert.h:116
SkColorType
Definition SkColorType.h:19
#define SK_DistanceFieldInset
static SkColorType colorType(AImageDecoder *decoder, const AImageDecoderHeaderInfo *headerInfo)
static void sk_bzero(void *buffer, size_t size)
Definition SkMalloc.h:105
constexpr int SkCount(const Container &c)
Definition SkTLogic.h:54
Type::kYUV Type::kRGBA() int(0.7 *637)
void addGlyphToBulkAndSetUseToken(skgpu::BulkUsePlotUpdater *, skgpu::MaskFormat, sktext::gpu::Glyph *, skgpu::AtlasToken)
~GrAtlasManager() override
void setUseTokenBulk(const skgpu::BulkUsePlotUpdater &updater, skgpu::AtlasToken token, skgpu::MaskFormat format)
uint64_t atlasGeneration(skgpu::MaskFormat format) const
bool hasGlyph(skgpu::MaskFormat, sktext::gpu::Glyph *)
GrDrawOpAtlas::ErrorCode addGlyphToAtlas(const SkGlyph &, sktext::gpu::Glyph *, int srcPadding, GrResourceProvider *, GrDeferredUploadTarget *)
GrAtlasManager(GrProxyProvider *, size_t maxTextureBytes, GrDrawOpAtlas::AllowMultitexturing, bool supportBilerpAtlas)
GrDrawOpAtlas::ErrorCode addToAtlas(GrResourceProvider *, GrDeferredUploadTarget *, skgpu::MaskFormat, int width, int height, const void *image, skgpu::AtlasLocator *)
GrBackendFormat getDefaultBackendFormat(GrColorType, GrRenderable) const
Definition GrCaps.cpp:400
virtual const skgpu::TokenTracker * tokenTracker()=0
SkISize atlasDimensions(skgpu::MaskFormat type) const
SkISize plotDimensions(skgpu::MaskFormat type) const
static std::unique_ptr< GrDrawOpAtlas > Make(GrProxyProvider *proxyProvider, const GrBackendFormat &format, SkColorType ct, size_t bpp, int width, int height, int plotWidth, int plotHeight, skgpu::AtlasGenerationCounter *generationCounter, AllowMultitexturing allowMultitexturing, skgpu::PlotEvictionCallback *evictor, std::string_view label)
void setLastUseToken(const skgpu::AtlasLocator &atlasLocator, skgpu::AtlasToken token)
bool hasID(const skgpu::PlotLocator &plotLocator)
ErrorCode addToAtlas(GrResourceProvider *, GrDeferredUploadTarget *, int width, int height, const void *image, skgpu::AtlasLocator *)
virtual sktext::gpu::StrikeCache * strikeCache() const =0
void * get() const
size_t rowBytes() const
Definition SkGlyph.cpp:233
SkMask::Format maskFormat() const
Definition SkGlyph.h:500
int height() const
Definition SkGlyph.h:513
int width() const
Definition SkGlyph.h:512
const void * image() const
Definition SkGlyph.h:465
void insetSrc(int padding)
Definition AtlasTypes.h:327
PlotLocator plotLocator() const
Definition AtlasTypes.h:301
bool add(const skgpu::AtlasLocator &atlasLocator)
Definition AtlasTypes.h:387
AtlasToken nextDrawToken() const
Definition AtlasTypes.h:214
SkSpan< const Glyph * > glyphs() const
void packedGlyphIDToGlyph(StrikeCache *cache)
skgpu::AtlasLocator fAtlasLocator
Definition Glyph.h:40
static skgpu::MaskFormat FormatFromSkGlyph(SkMask::Format format)
Definition Glyph.h:19
const SkPackedGlyphID fPackedID
Definition Glyph.h:39
static const char * begin(const StringSlice &s)
Definition editor.cpp:252
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition main.cc:19
sk_sp< SkImage > image
Definition examples.cpp:29
struct MyStruct s
glong glong end
uint32_t uint32_t * format
uint32_t * target
double y
double x
static const int kMaskFormatCount
Definition AtlasTypes.h:105
int32_t height
int32_t width
constexpr int32_t width() const
Definition SkSize.h:36
constexpr int32_t height() const
Definition SkSize.h:37
@ kBW_Format
1bit per pixel mask (e.g. monochrome)
Definition SkMask.h:27