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