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