• 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,int plotOldThreshold)13 GrAtlasManager::GrAtlasManager(GrProxyProvider* proxyProvider, GrStrikeCache* glyphCache,
14                                size_t maxTextureBytes,
15                                GrDrawOpAtlas::AllowMultitexturing allowMultitexturing,
16                                int plotOldThreshold)
17             : fAllowMultitexturing{allowMultitexturing}
18             , fProxyProvider{proxyProvider}
19             , fCaps{fProxyProvider->refCaps()}
20             , fGlyphCache{glyphCache}
21             , fAtlasConfig{fCaps->maxTextureSize(), maxTextureBytes}
22             , fPlotOldThreshold(plotOldThreshold)
23             , fAtlasHitCount(0)
24             , fAtlasMissCount(0) { }
25 
26 GrAtlasManager::~GrAtlasManager() = default;
27 
mask_format_to_gr_color_type(GrMaskFormat format)28 static GrColorType mask_format_to_gr_color_type(GrMaskFormat format) {
29     switch (format) {
30         case kA8_GrMaskFormat:
31             return GrColorType::kAlpha_8;
32         case kA565_GrMaskFormat:
33             return GrColorType::kBGR_565;
34         case kARGB_GrMaskFormat:
35             return GrColorType::kRGBA_8888;
36         default:
37             SkDEBUGFAIL("unsupported GrMaskFormat");
38             return GrColorType::kAlpha_8;
39     }
40 }
41 
freeAll()42 void GrAtlasManager::freeAll() {
43     for (int i = 0; i < kMaskFormatCount; ++i) {
44         fAtlases[i] = nullptr;
45     }
46 }
47 
hasGlyph(GrGlyph * glyph)48 bool GrAtlasManager::hasGlyph(GrGlyph* glyph) {
49     SkASSERT(glyph);
50     return this->getAtlas(glyph->fMaskFormat)->hasID(glyph->fID);
51 }
52 
53 // 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)54 GrDrawOpAtlas::ErrorCode GrAtlasManager::addToAtlas(
55                                 GrResourceProvider* resourceProvider,
56                                 GrStrikeCache* glyphCache,
57                                 GrTextStrike* strike, GrDrawOpAtlas::AtlasID* id,
58                                 GrDeferredUploadTarget* target, GrMaskFormat format,
59                                 int width, int height, const void* image, SkIPoint16* loc) {
60     glyphCache->setStrikeToPreserve(strike);
61     return this->getAtlas(format)->addToAtlas(resourceProvider, id, target, width, height,
62                                               image, loc);
63 }
64 
addGlyphToBulkAndSetUseToken(GrDrawOpAtlas::BulkUseTokenUpdater * updater,GrGlyph * glyph,GrDeferredUploadToken token)65 void GrAtlasManager::addGlyphToBulkAndSetUseToken(GrDrawOpAtlas::BulkUseTokenUpdater* updater,
66                                                   GrGlyph* glyph,
67                                                   GrDeferredUploadToken token) {
68     SkASSERT(glyph);
69     if (updater->add(glyph->fID)) {
70         this->getAtlas(glyph->fMaskFormat)->setLastUseToken(glyph->fID, token);
71     }
72 }
73 
postFlush(GrDeferredUploadToken startTokenForNextFlush,const uint32_t * opListIDs,int numOpListIDs)74 void GrAtlasManager::postFlush(GrDeferredUploadToken startTokenForNextFlush,
75                    const uint32_t* opListIDs, int numOpListIDs) {
76     bool isRadicals = false;
77     static int count = 0;
78     count++;
79     if (count == 5) {
80         float hitRate = atlasHitRate();
81         if (!(fabs(hitRate-0) <= 1.0e-6)) {
82 #ifdef SK_DEGUB_ATLAS_HIT_RATE
83             SkDebugf("----- last 5 flush AtlasHitRate = %{public}6.2f.", hitRate);
84 #endif
85 #ifdef SK_ENABLE_SMALL_PAGE
86             if (hitRate < 0.2) {
87                 isRadicals = true;
88             }
89 #endif
90         }
91         resetHitCount();
92         count = 0;
93     }
94 
95     for (int i = 0; i < kMaskFormatCount; ++i) {
96         if (fAtlases[i]) {
97             fAtlases[i]->compact(startTokenForNextFlush, isRadicals);
98         }
99     }
100 }
101 
102 #ifdef SK_DUMP_ATLAS_IMAGE
103 #include "src/gpu/GrContextPriv.h"
104 #include "src/gpu/GrSurfaceContext.h"
105 #include "src/gpu/GrSurfaceProxy.h"
106 #include "src/gpu/GrTextureProxy.h"
107 
108 #include "include/core/SkBitmap.h"
109 #include "include/core/SkImageEncoder.h"
110 #include "include/core/SkStream.h"
111 #include <stdio.h>
112 
113 /**
114   * Write the contents of the surface proxy to a PNG. Returns true if successful.
115   * @param filename      Full path to desired file
116   */
save_pixels(GrContext * context,GrSurfaceProxy * sProxy,GrColorType colorType,const char * filename)117 static bool save_pixels(GrContext* context, GrSurfaceProxy* sProxy, GrColorType colorType,
118                         const char* filename) {
119     if (!sProxy) {
120         return false;
121     }
122 
123     SkImageInfo ii = SkImageInfo::Make(sProxy->width(), sProxy->height(),
124                                        kRGBA_8888_SkColorType, kPremul_SkAlphaType);
125     SkBitmap bm;
126     if (!bm.tryAllocPixels(ii)) {
127         return false;
128     }
129 
130     sk_sp<GrSurfaceContext> sContext(context->priv().makeWrappedSurfaceContext(
131             sk_ref_sp(sProxy), colorType, kUnknown_SkAlphaType));
132     if (!sContext || !sContext->asTextureProxy()) {
133         return false;
134     }
135 
136     bool result = sContext->readPixels(ii, bm.getPixels(), bm.rowBytes(), {0, 0});
137     if (!result) {
138         SkDebugf("------ failed to read pixels for %s\n", filename);
139         return false;
140     }
141 
142     // remove any previous version of this file
143     remove(filename);
144 
145     SkFILEWStream file(filename);
146     if (!file.isValid()) {
147         SkDebugf("------ failed to create file: %s\n", filename);
148         remove(filename);   // remove any partial file
149         return false;
150     }
151 
152     if (!SkEncodeImage(&file, bm, SkEncodedImageFormat::kPNG, 100)) {
153         SkDebugf("------ failed to encode %s\n", filename);
154         remove(filename);   // remove any partial file
155         return false;
156     }
157 
158     return true;
159 }
160 
dump(GrContext * context) const161 void GrAtlasManager::dump(GrContext* context) const {
162     static int gDumpCount = 0;
163     for (int i = 0; i < kMaskFormatCount; ++i) {
164         if (fAtlases[i]) {
165             const sk_sp<GrTextureProxy>* proxies = fAtlases[i]->getProxies();
166             for (uint32_t pageIdx = 0; pageIdx < fAtlases[i]->numActivePages(); ++pageIdx) {
167                 SkASSERT(proxies[pageIdx]);
168                 SkString filename;
169 #ifdef SK_BUILD_FOR_ANDROID
170                 filename.printf("/sdcard/fontcache_%d%d%d.png", gDumpCount, i, pageIdx);
171 #else
172                 filename.printf("/data/storage/el2/base/cache/fontcache_%d_%d_%d.png", gDumpCount, i, pageIdx);
173 #endif
174                 auto ct = mask_format_to_gr_color_type(AtlasIndexToMaskFormat(i));
175                 save_pixels(context, proxies[pageIdx].get(), ct, filename.c_str());
176             }
177         }
178     }
179     ++gDumpCount;
180 }
181 #endif
182 
setAtlasSizesToMinimum_ForTesting()183 void GrAtlasManager::setAtlasSizesToMinimum_ForTesting() {
184     // Delete any old atlases.
185     // This should be safe to do as long as we are not in the middle of a flush.
186     for (int i = 0; i < kMaskFormatCount; i++) {
187         fAtlases[i] = nullptr;
188     }
189 
190     // Set all the atlas sizes to 1x1 plot each.
191     new (&fAtlasConfig) GrDrawOpAtlasConfig{};
192 }
193 
initAtlas(GrMaskFormat format)194 bool GrAtlasManager::initAtlas(GrMaskFormat format) {
195     int index = MaskFormatToAtlasIndex(format);
196     if (fAtlases[index] == nullptr) {
197         GrColorType grColorType = mask_format_to_gr_color_type(format);
198         int pageNum = 4; // The maximum number of texture pages in the original skia code is 4
199 #ifdef SK_ENABLE_SMALL_PAGE
200         if (format == kA8_GrMaskFormat && fAtlasConfig.getARGBDimensions().width() > 512) {
201             // reset fAtlasConfig to suit small page.
202             pageNum = fAtlasConfig.resetAsSmallPage();
203         }
204 #endif
205         SkISize atlasDimensions = fAtlasConfig.atlasDimensions(format);
206         SkISize plotDimensions = fAtlasConfig.plotDimensions(format);
207 
208         const GrBackendFormat format = fCaps->getDefaultBackendFormat(grColorType,
209                                                                       GrRenderable::kNo);
210 
211         fAtlases[index] = GrDrawOpAtlas::Make(
212                 fProxyProvider, format, grColorType,
213                 atlasDimensions.width(), atlasDimensions.height(),
214                 plotDimensions.width(), plotDimensions.height(),
215                 fAllowMultitexturing, pageNum, fPlotOldThreshold, &GrStrikeCache::HandleEviction, fGlyphCache);
216         if (!fAtlases[index]) {
217             return false;
218         }
219     }
220     return true;
221 }
222