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