Update rive-cpp to 2.0 version
[platform/core/uifw/rive-tizen.git] / submodule / skia / src / gpu / ganesh / text / GrAtlasManager.cpp
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
8 #include "src/gpu/ganesh/text/GrAtlasManager.h"
9
10 #include "include/core/SkColorSpace.h"
11 #include "src/codec/SkMasks.h"
12 #include "src/core/SkAutoMalloc.h"
13 #include "src/core/SkDistanceFieldGen.h"
14 #include "src/gpu/ganesh/GrImageInfo.h"
15 #include "src/gpu/ganesh/GrMeshDrawTarget.h"
16 #include "src/text/gpu/Glyph.h"
17 #include "src/text/gpu/GlyphVector.h"
18 #include "src/text/gpu/StrikeCache.h"
19
20 using Glyph = sktext::gpu::Glyph;
21 using MaskFormat = skgpu::MaskFormat;
22
23 GrAtlasManager::GrAtlasManager(GrProxyProvider* proxyProvider,
24                                size_t maxTextureBytes,
25                                GrDrawOpAtlas::AllowMultitexturing allowMultitexturing,
26                                bool supportBilerpAtlas)
27             : fAllowMultitexturing{allowMultitexturing}
28             , fSupportBilerpAtlas{supportBilerpAtlas}
29             , fProxyProvider{proxyProvider}
30             , fCaps{fProxyProvider->refCaps()}
31             , fAtlasConfig{fCaps->maxTextureSize(), maxTextureBytes} { }
32
33 GrAtlasManager::~GrAtlasManager() = default;
34
35 void GrAtlasManager::freeAll() {
36     for (int i = 0; i < skgpu::kMaskFormatCount; ++i) {
37         fAtlases[i] = nullptr;
38     }
39 }
40
41 bool GrAtlasManager::hasGlyph(MaskFormat format, Glyph* glyph) {
42     SkASSERT(glyph);
43     return this->getAtlas(format)->hasID(glyph->fAtlasLocator.plotLocator());
44 }
45
46 template <typename INT_TYPE>
47 static void expand_bits(INT_TYPE* dst,
48                         const uint8_t* src,
49                         int width,
50                         int height,
51                         int dstRowBytes,
52                         int srcRowBytes) {
53     for (int y = 0; y < height; ++y) {
54         int rowWritesLeft = width;
55         const uint8_t* s = src;
56         INT_TYPE* d = dst;
57         while (rowWritesLeft > 0) {
58             unsigned mask = *s++;
59             for (int x = 7; x >= 0 && rowWritesLeft; --x, --rowWritesLeft) {
60                 *d++ = (mask & (1 << x)) ? (INT_TYPE)(~0UL) : 0;
61             }
62         }
63         dst = reinterpret_cast<INT_TYPE*>(reinterpret_cast<intptr_t>(dst) + dstRowBytes);
64         src += srcRowBytes;
65     }
66 }
67
68 static void get_packed_glyph_image(
69         const SkGlyph& glyph, int dstRB, MaskFormat expectedMaskFormat, void* dst) {
70     const int width = glyph.width();
71     const int height = glyph.height();
72     const void* src = glyph.image();
73     SkASSERT(src != nullptr);
74
75     MaskFormat maskFormat = Glyph::FormatFromSkGlyph(glyph.maskFormat());
76     if (maskFormat == expectedMaskFormat) {
77         int srcRB = glyph.rowBytes();
78         // Notice this comparison is with the glyphs raw mask format, and not its MaskFormat.
79         if (glyph.maskFormat() != SkMask::kBW_Format) {
80             if (srcRB != dstRB) {
81                 const int bbp = MaskFormatBytesPerPixel(expectedMaskFormat);
82                 for (int y = 0; y < height; y++) {
83                     memcpy(dst, src, width * bbp);
84                     src = (const char*) src + srcRB;
85                     dst = (char*) dst + dstRB;
86                 }
87             } else {
88                 memcpy(dst, src, dstRB * height);
89             }
90         } else {
91             // Handle 8-bit format by expanding the mask to the expected format.
92             const uint8_t* bits = reinterpret_cast<const uint8_t*>(src);
93             switch (expectedMaskFormat) {
94                 case MaskFormat::kA8: {
95                     uint8_t* bytes = reinterpret_cast<uint8_t*>(dst);
96                     expand_bits(bytes, bits, width, height, dstRB, srcRB);
97                     break;
98                 }
99                 case MaskFormat::kA565: {
100                     uint16_t* rgb565 = reinterpret_cast<uint16_t*>(dst);
101                     expand_bits(rgb565, bits, width, height, dstRB, srcRB);
102                     break;
103                 }
104                 default:
105                     SK_ABORT("Invalid MaskFormat");
106             }
107         }
108     } else if (maskFormat == MaskFormat::kA565 &&
109                expectedMaskFormat == MaskFormat::kARGB) {
110         // Convert if the glyph uses a 565 mask format since it is using LCD text rendering
111         // but the expected format is 8888 (will happen on macOS with Metal since that
112         // combination does not support 565).
113         static constexpr SkMasks masks{
114                 {0b1111'1000'0000'0000, 11, 5},  // Red
115                 {0b0000'0111'1110'0000,  5, 6},  // Green
116                 {0b0000'0000'0001'1111,  0, 5},  // Blue
117                 {0, 0, 0}                        // Alpha
118         };
119         constexpr int a565Bpp = MaskFormatBytesPerPixel(MaskFormat::kA565);
120         constexpr int argbBpp = MaskFormatBytesPerPixel(MaskFormat::kARGB);
121         for (int y = 0; y < height; y++) {
122             for (int x = 0; x < width; x++) {
123                 uint16_t color565 = 0;
124                 memcpy(&color565, src, a565Bpp);
125                 uint32_t colorRGBA = GrColorPackRGBA(masks.getRed(color565),
126                                                      masks.getGreen(color565),
127                                                      masks.getBlue(color565),
128                                                      0xFF);
129                 memcpy(dst, &colorRGBA, argbBpp);
130                 src = (char*)src + a565Bpp;
131                 dst = (char*)dst + argbBpp;
132             }
133         }
134     } else {
135         // crbug:510931
136         // Retrieving the image from the cache can actually change the mask format. This case is
137         // very uncommon so for now we just draw a clear box for these glyphs.
138         const int bpp = MaskFormatBytesPerPixel(expectedMaskFormat);
139         for (int y = 0; y < height; y++) {
140             sk_bzero(dst, width * bpp);
141             dst = (char*)dst + dstRB;
142         }
143     }
144 }
145
146 // returns true if glyph successfully added to texture atlas, false otherwise.  If the glyph's
147 // mask format has changed, then addGlyphToAtlas will draw a clear box.  This will almost never
148 // happen.
149 // TODO we can handle some of these cases if we really want to, but the long term solution is to
150 // get the actual glyph image itself when we get the glyph metrics.
151 GrDrawOpAtlas::ErrorCode GrAtlasManager::addGlyphToAtlas(const SkGlyph& skGlyph,
152                                                          Glyph* glyph,
153                                                          int srcPadding,
154                                                          GrResourceProvider* resourceProvider,
155                                                          GrDeferredUploadTarget* uploadTarget) {
156     SkASSERT(0 <= srcPadding && srcPadding <= SK_DistanceFieldInset);
157
158     if (skGlyph.image() == nullptr) {
159         return GrDrawOpAtlas::ErrorCode::kError;
160     }
161     SkASSERT(glyph != nullptr);
162
163     MaskFormat glyphFormat = Glyph::FormatFromSkGlyph(skGlyph.maskFormat());
164     MaskFormat expectedMaskFormat = this->resolveMaskFormat(glyphFormat);
165     int bytesPerPixel = MaskFormatBytesPerPixel(expectedMaskFormat);
166
167     int padding;
168     switch (srcPadding) {
169         case 0:
170             // The direct mask/image case.
171             padding = 0;
172             if (fSupportBilerpAtlas) {
173                 // Force direct masks (glyph with no padding) to have padding.
174                 padding = 1;
175                 srcPadding = 1;
176             }
177             break;
178         case 1:
179             // The transformed mask/image case.
180             padding = 1;
181             break;
182         case SK_DistanceFieldInset:
183             // The SDFT case.
184             // If the srcPadding == SK_DistanceFieldInset (SDFT case) then the padding is built
185             // into the image on the glyph; no extra padding needed.
186             // TODO: can the SDFT glyph image in the cache be reduced by the padding?
187             padding = 0;
188             break;
189         default:
190             // The padding is not one of the know forms.
191             return GrDrawOpAtlas::ErrorCode::kError;
192     }
193
194     const int width = skGlyph.width() + 2*padding;
195     const int height = skGlyph.height() + 2*padding;
196     int rowBytes = width * bytesPerPixel;
197     size_t size = height * rowBytes;
198
199     // Temporary storage for normalizing glyph image.
200     SkAutoSMalloc<1024> storage(size);
201     void* dataPtr = storage.get();
202     if (padding > 0) {
203         sk_bzero(dataPtr, size);
204         // Advance in one row and one column.
205         dataPtr = (char*)(dataPtr) + rowBytes + bytesPerPixel;
206     }
207
208     get_packed_glyph_image(skGlyph, rowBytes, expectedMaskFormat, dataPtr);
209
210     auto errorCode = this->addToAtlas(resourceProvider,
211                                       uploadTarget,
212                                       expectedMaskFormat,
213                                       width,
214                                       height,
215                                       storage.get(),
216                                       &glyph->fAtlasLocator);
217
218     if (errorCode == GrDrawOpAtlas::ErrorCode::kSucceeded) {
219         glyph->fAtlasLocator.insetSrc(srcPadding);
220     }
221
222     return errorCode;
223 }
224
225 // add to texture atlas that matches this format
226 GrDrawOpAtlas::ErrorCode GrAtlasManager::addToAtlas(GrResourceProvider* resourceProvider,
227                                                     GrDeferredUploadTarget* target,
228                                                     MaskFormat format,
229                                                     int width, int height, const void* image,
230                                                     skgpu::AtlasLocator* atlasLocator) {
231     return this->getAtlas(format)->addToAtlas(resourceProvider, target, width, height, image,
232                                               atlasLocator);
233 }
234
235 void GrAtlasManager::addGlyphToBulkAndSetUseToken(skgpu::BulkUsePlotUpdater* updater,
236                                                   MaskFormat format, Glyph* glyph,
237                                                   skgpu::DrawToken token) {
238     SkASSERT(glyph);
239     if (updater->add(glyph->fAtlasLocator)) {
240         this->getAtlas(format)->setLastUseToken(glyph->fAtlasLocator, token);
241     }
242 }
243
244 #ifdef SK_DEBUG
245 #include "include/gpu/GrDirectContext.h"
246 #include "src/gpu/ganesh/GrDirectContextPriv.h"
247 #include "src/gpu/ganesh/GrSurfaceProxy.h"
248 #include "src/gpu/ganesh/GrTextureProxy.h"
249 #include "src/gpu/ganesh/SurfaceContext.h"
250
251 #include "include/core/SkBitmap.h"
252 #include "include/core/SkImageEncoder.h"
253 #include "include/core/SkStream.h"
254 #include <stdio.h>
255
256 /**
257   * Write the contents of the surface proxy to a PNG. Returns true if successful.
258   * @param filename      Full path to desired file
259   */
260 static bool save_pixels(GrDirectContext* dContext, GrSurfaceProxyView view, GrColorType colorType,
261                         const char* filename) {
262     if (!view.proxy()) {
263         return false;
264     }
265
266     auto ii = SkImageInfo::Make(view.proxy()->dimensions(), kRGBA_8888_SkColorType,
267                                 kPremul_SkAlphaType);
268     SkBitmap bm;
269     if (!bm.tryAllocPixels(ii)) {
270         return false;
271     }
272
273     auto sContext = dContext->priv().makeSC(std::move(view),
274                                             {colorType, kUnknown_SkAlphaType, nullptr});
275     if (!sContext || !sContext->asTextureProxy()) {
276         return false;
277     }
278
279     bool result = sContext->readPixels(dContext, bm.pixmap(), {0, 0});
280     if (!result) {
281         SkDebugf("------ failed to read pixels for %s\n", filename);
282         return false;
283     }
284
285     // remove any previous version of this file
286     remove(filename);
287
288     SkFILEWStream file(filename);
289     if (!file.isValid()) {
290         SkDebugf("------ failed to create file: %s\n", filename);
291         remove(filename);   // remove any partial file
292         return false;
293     }
294
295     if (!SkEncodeImage(&file, bm, SkEncodedImageFormat::kPNG, 100)) {
296         SkDebugf("------ failed to encode %s\n", filename);
297         remove(filename);   // remove any partial file
298         return false;
299     }
300
301     return true;
302 }
303
304 void GrAtlasManager::dump(GrDirectContext* context) const {
305     static int gDumpCount = 0;
306     for (int i = 0; i < skgpu::kMaskFormatCount; ++i) {
307         if (fAtlases[i]) {
308             const GrSurfaceProxyView* views = fAtlases[i]->getViews();
309             for (uint32_t pageIdx = 0; pageIdx < fAtlases[i]->numActivePages(); ++pageIdx) {
310                 SkASSERT(views[pageIdx].proxy());
311                 SkString filename;
312 #ifdef SK_BUILD_FOR_ANDROID
313                 filename.printf("/sdcard/fontcache_%d%d%d.png", gDumpCount, i, pageIdx);
314 #else
315                 filename.printf("fontcache_%d%d%d.png", gDumpCount, i, pageIdx);
316 #endif
317                 SkColorType ct = MaskFormatToColorType(AtlasIndexToMaskFormat(i));
318                 save_pixels(context, views[pageIdx], SkColorTypeToGrColorType(ct),
319                             filename.c_str());
320             }
321         }
322     }
323     ++gDumpCount;
324 }
325 #endif
326
327 void GrAtlasManager::setAtlasDimensionsToMinimum_ForTesting() {
328     // Delete any old atlases.
329     // This should be safe to do as long as we are not in the middle of a flush.
330     for (int i = 0; i < skgpu::kMaskFormatCount; i++) {
331         fAtlases[i] = nullptr;
332     }
333
334     // Set all the atlas sizes to 1x1 plot each.
335     new (&fAtlasConfig) GrDrawOpAtlasConfig{};
336 }
337
338 bool GrAtlasManager::initAtlas(MaskFormat format) {
339     int index = MaskFormatToAtlasIndex(format);
340     if (fAtlases[index] == nullptr) {
341         SkColorType colorType = MaskFormatToColorType(format);
342         GrColorType grColorType = SkColorTypeToGrColorType(colorType);
343         SkISize atlasDimensions = fAtlasConfig.atlasDimensions(format);
344         SkISize plotDimensions = fAtlasConfig.plotDimensions(format);
345
346         const GrBackendFormat backendFormat =
347                 fCaps->getDefaultBackendFormat(grColorType, GrRenderable::kNo);
348
349         fAtlases[index] = GrDrawOpAtlas::Make(fProxyProvider, backendFormat,
350                                               GrColorTypeToSkColorType(grColorType),
351                                               GrColorTypeBytesPerPixel(grColorType),
352                                               atlasDimensions.width(), atlasDimensions.height(),
353                                               plotDimensions.width(), plotDimensions.height(),
354                                               this,
355                                               fAllowMultitexturing,
356                                               nullptr,
357                                               /*label=*/"TextAtlas");
358         if (!fAtlases[index]) {
359             return false;
360         }
361     }
362     return true;
363 }
364
365 ////////////////////////////////////////////////////////////////////////////////////////////////
366
367 namespace sktext::gpu {
368
369 std::tuple<bool, int> GlyphVector::regenerateAtlas(int begin, int end,
370                                                    MaskFormat maskFormat,
371                                                    int srcPadding,
372                                                    GrMeshDrawTarget* target) {
373     GrAtlasManager* atlasManager = target->atlasManager();
374     GrDeferredUploadTarget* uploadTarget = target->deferredUploadTarget();
375
376     uint64_t currentAtlasGen = atlasManager->atlasGeneration(maskFormat);
377
378     this->packedGlyphIDToGlyph(target->strikeCache());
379
380     if (fAtlasGeneration != currentAtlasGen) {
381         // Calculate the texture coordinates for the vertexes during first use (fAtlasGeneration
382         // is set to kInvalidAtlasGeneration) or the atlas has changed in subsequent calls..
383         fBulkUseUpdater.reset();
384
385         SkBulkGlyphMetricsAndImages metricsAndImages{fTextStrike->strikeSpec()};
386
387         // Update the atlas information in the GrStrike.
388         auto tokenTracker = uploadTarget->tokenTracker();
389         auto glyphs = fGlyphs.subspan(begin, end - begin);
390         int glyphsPlacedInAtlas = 0;
391         bool success = true;
392         for (const Variant& variant : glyphs) {
393             Glyph* gpuGlyph = variant.glyph;
394             SkASSERT(gpuGlyph != nullptr);
395
396             if (!atlasManager->hasGlyph(maskFormat, gpuGlyph)) {
397                 const SkGlyph& skGlyph = *metricsAndImages.glyph(gpuGlyph->fPackedID);
398                 auto code = atlasManager->addGlyphToAtlas(
399                         skGlyph, gpuGlyph, srcPadding, target->resourceProvider(), uploadTarget);
400                 if (code != GrDrawOpAtlas::ErrorCode::kSucceeded) {
401                     success = code != GrDrawOpAtlas::ErrorCode::kError;
402                     break;
403                 }
404             }
405             atlasManager->addGlyphToBulkAndSetUseToken(
406                     &fBulkUseUpdater, maskFormat, gpuGlyph,
407                     tokenTracker->nextDrawToken());
408             glyphsPlacedInAtlas++;
409         }
410
411         // Update atlas generation if there are no more glyphs to put in the atlas.
412         if (success && begin + glyphsPlacedInAtlas == SkCount(fGlyphs)) {
413             // Need to get the freshest value of the atlas' generation because
414             // updateTextureCoordinates may have changed it.
415             fAtlasGeneration = atlasManager->atlasGeneration(maskFormat);
416         }
417
418         return {success, glyphsPlacedInAtlas};
419     } else {
420         // The atlas hasn't changed, so our texture coordinates are still valid.
421         if (end == SkCount(fGlyphs)) {
422             // The atlas hasn't changed and the texture coordinates are all still valid. Update
423             // all the plots used to the new use token.
424             atlasManager->setUseTokenBulk(fBulkUseUpdater,
425                                           uploadTarget->tokenTracker()->nextDrawToken(),
426                                           maskFormat);
427         }
428         return {true, end - begin};
429     }
430 }
431
432 }  // namespace sktext::gpu