• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/text/GrAtlasManager.h"
9 
10 #include "src/gpu/GrGlyph.h"
11 #include "src/gpu/text/GrStrikeCache.h"
12 
GrAtlasManager(GrProxyProvider * proxyProvider,GrStrikeCache * glyphCache,size_t maxTextureBytes,GrDrawOpAtlas::AllowMultitexturing allowMultitexturing)13 GrAtlasManager::GrAtlasManager(GrProxyProvider* proxyProvider, GrStrikeCache* glyphCache,
14                                size_t maxTextureBytes,
15                                GrDrawOpAtlas::AllowMultitexturing allowMultitexturing)
16             : fAllowMultitexturing{allowMultitexturing}
17             , fProxyProvider{proxyProvider}
18             , fCaps{fProxyProvider->refCaps()}
19             , fGlyphCache{glyphCache}
20             , fAtlasConfig{fCaps->maxTextureSize(), maxTextureBytes} { }
21 
22 GrAtlasManager::~GrAtlasManager() = default;
23 
mask_format_to_gr_color_type(GrMaskFormat format)24 static GrColorType mask_format_to_gr_color_type(GrMaskFormat format) {
25     switch (format) {
26         case kA8_GrMaskFormat:
27             return GrColorType::kAlpha_8;
28         case kA565_GrMaskFormat:
29             return GrColorType::kBGR_565;
30         case kARGB_GrMaskFormat:
31             return GrColorType::kRGBA_8888;
32         default:
33             SkDEBUGFAIL("unsupported GrMaskFormat");
34             return GrColorType::kAlpha_8;
35     }
36 }
37 
freeAll()38 void GrAtlasManager::freeAll() {
39     for (int i = 0; i < kMaskFormatCount; ++i) {
40         fAtlases[i] = nullptr;
41     }
42 }
43 
hasGlyph(GrGlyph * glyph)44 bool GrAtlasManager::hasGlyph(GrGlyph* glyph) {
45     SkASSERT(glyph);
46     return this->getAtlas(glyph->fMaskFormat)->hasID(glyph->fID);
47 }
48 
49 // add to texture atlas that matches this format
addToAtlas(GrResourceProvider * resourceProvider,GrStrikeCache * glyphCache,GrTextStrike * strike,GrDrawOpAtlas::AtlasID * id,GrDeferredUploadTarget * target,GrMaskFormat format,int width,int height,const void * image,SkIPoint16 * loc)50 GrDrawOpAtlas::ErrorCode GrAtlasManager::addToAtlas(
51                                 GrResourceProvider* resourceProvider,
52                                 GrStrikeCache* glyphCache,
53                                 GrTextStrike* strike, GrDrawOpAtlas::AtlasID* id,
54                                 GrDeferredUploadTarget* target, GrMaskFormat format,
55                                 int width, int height, const void* image, SkIPoint16* loc) {
56     glyphCache->setStrikeToPreserve(strike);
57     return this->getAtlas(format)->addToAtlas(resourceProvider, id, target, width, height,
58                                               image, loc);
59 }
60 
addGlyphToBulkAndSetUseToken(GrDrawOpAtlas::BulkUseTokenUpdater * updater,GrGlyph * glyph,GrDeferredUploadToken token)61 void GrAtlasManager::addGlyphToBulkAndSetUseToken(GrDrawOpAtlas::BulkUseTokenUpdater* updater,
62                                                   GrGlyph* glyph,
63                                                   GrDeferredUploadToken token) {
64     SkASSERT(glyph);
65     if (updater->add(glyph->fID)) {
66         this->getAtlas(glyph->fMaskFormat)->setLastUseToken(glyph->fID, token);
67     }
68 }
69 
70 #ifdef SK_DEBUG
71 #include "src/gpu/GrContextPriv.h"
72 #include "src/gpu/GrSurfaceContext.h"
73 #include "src/gpu/GrSurfaceProxy.h"
74 #include "src/gpu/GrTextureProxy.h"
75 
76 #include "include/core/SkBitmap.h"
77 #include "include/core/SkImageEncoder.h"
78 #include "include/core/SkStream.h"
79 #include <stdio.h>
80 
81 /**
82   * Write the contents of the surface proxy to a PNG. Returns true if successful.
83   * @param filename      Full path to desired file
84   */
save_pixels(GrContext * context,GrSurfaceProxy * sProxy,GrColorType colorType,const char * filename)85 static bool save_pixels(GrContext* context, GrSurfaceProxy* sProxy, GrColorType colorType,
86                         const char* filename) {
87     if (!sProxy) {
88         return false;
89     }
90 
91     SkImageInfo ii = SkImageInfo::Make(sProxy->width(), sProxy->height(),
92                                        kRGBA_8888_SkColorType, kPremul_SkAlphaType);
93     SkBitmap bm;
94     if (!bm.tryAllocPixels(ii)) {
95         return false;
96     }
97 
98     sk_sp<GrSurfaceContext> sContext(context->priv().makeWrappedSurfaceContext(
99             sk_ref_sp(sProxy), colorType, kUnknown_SkAlphaType));
100     if (!sContext || !sContext->asTextureProxy()) {
101         return false;
102     }
103 
104     bool result = sContext->readPixels(ii, bm.getPixels(), bm.rowBytes(), {0, 0});
105     if (!result) {
106         SkDebugf("------ failed to read pixels for %s\n", filename);
107         return false;
108     }
109 
110     // remove any previous version of this file
111     remove(filename);
112 
113     SkFILEWStream file(filename);
114     if (!file.isValid()) {
115         SkDebugf("------ failed to create file: %s\n", filename);
116         remove(filename);   // remove any partial file
117         return false;
118     }
119 
120     if (!SkEncodeImage(&file, bm, SkEncodedImageFormat::kPNG, 100)) {
121         SkDebugf("------ failed to encode %s\n", filename);
122         remove(filename);   // remove any partial file
123         return false;
124     }
125 
126     return true;
127 }
128 
dump(GrContext * context) const129 void GrAtlasManager::dump(GrContext* context) const {
130     static int gDumpCount = 0;
131     for (int i = 0; i < kMaskFormatCount; ++i) {
132         if (fAtlases[i]) {
133             const sk_sp<GrTextureProxy>* proxies = fAtlases[i]->getProxies();
134             for (uint32_t pageIdx = 0; pageIdx < fAtlases[i]->numActivePages(); ++pageIdx) {
135                 SkASSERT(proxies[pageIdx]);
136                 SkString filename;
137 #ifdef SK_BUILD_FOR_ANDROID
138                 filename.printf("/sdcard/fontcache_%d%d%d.png", gDumpCount, i, pageIdx);
139 #else
140                 filename.printf("fontcache_%d%d%d.png", gDumpCount, i, pageIdx);
141 #endif
142                 auto ct = mask_format_to_gr_color_type(AtlasIndexToMaskFormat(i));
143                 save_pixels(context, proxies[pageIdx].get(), ct, filename.c_str());
144             }
145         }
146     }
147     ++gDumpCount;
148 }
149 #endif
150 
setAtlasSizesToMinimum_ForTesting()151 void GrAtlasManager::setAtlasSizesToMinimum_ForTesting() {
152     // Delete any old atlases.
153     // This should be safe to do as long as we are not in the middle of a flush.
154     for (int i = 0; i < kMaskFormatCount; i++) {
155         fAtlases[i] = nullptr;
156     }
157 
158     // Set all the atlas sizes to 1x1 plot each.
159     new (&fAtlasConfig) GrDrawOpAtlasConfig{};
160 }
161 
initAtlas(GrMaskFormat format)162 bool GrAtlasManager::initAtlas(GrMaskFormat format) {
163     int index = MaskFormatToAtlasIndex(format);
164     if (fAtlases[index] == nullptr) {
165         GrColorType grColorType = mask_format_to_gr_color_type(format);
166         SkISize atlasDimensions = fAtlasConfig.atlasDimensions(format);
167         SkISize plotDimensions = fAtlasConfig.plotDimensions(format);
168 
169         const GrBackendFormat format = fCaps->getDefaultBackendFormat(grColorType,
170                                                                       GrRenderable::kNo);
171 
172         fAtlases[index] = GrDrawOpAtlas::Make(
173                 fProxyProvider, format, grColorType,
174                 atlasDimensions.width(), atlasDimensions.height(),
175                 plotDimensions.width(), plotDimensions.height(),
176                 fAllowMultitexturing, &GrStrikeCache::HandleEviction, fGlyphCache);
177         if (!fAtlases[index]) {
178             return false;
179         }
180     }
181     return true;
182 }
183