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 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 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 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 53 void GrAtlasManager::freeAll() { 54 for (int i = 0; i < kMaskFormatCount; ++i) { 55 fAtlases[i] = nullptr; 56 } 57 } 58 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 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 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 */ 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 143 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 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 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