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 #ifndef GrAtlasManager_DEFINED 9 #define GrAtlasManager_DEFINED 10 11 #include "include/core/SkRefCnt.h" 12 #include "include/gpu/GpuTypes.h" 13 #include "include/gpu/ganesh/GrBackendSurface.h" 14 #include "include/gpu/ganesh/GrTypes.h" 15 #include "include/private/base/SkAssert.h" 16 #include "include/private/gpu/ganesh/GrTypesPriv.h" 17 #include "src/gpu/AtlasTypes.h" 18 #include "src/gpu/ganesh/GrCaps.h" 19 #include "src/gpu/ganesh/GrDrawOpAtlas.h" 20 #include "src/gpu/ganesh/GrOnFlushResourceProvider.h" 21 #include "src/gpu/ganesh/GrProxyProvider.h" 22 23 #include <cstddef> 24 #include <cstdint> 25 #include <memory> 26 27 class GrDeferredUploadTarget; 28 class GrResourceProvider; 29 class GrSurfaceProxyView; 30 class SkGlyph; 31 32 namespace sktext::gpu { 33 class Glyph; 34 } 35 36 ////////////////////////////////////////////////////////////////////////////////////////////////// 37 /** The GrAtlasManager manages the lifetime of and access to GrDrawOpAtlases. 38 * It is only available at flush and only via the GrOpFlushState. 39 * 40 * This implies that all of the advanced atlasManager functionality (i.e., 41 * adding glyphs to the atlas) are only available at flush time. 42 */ 43 class GrAtlasManager : public GrOnFlushCallbackObject, public skgpu::AtlasGenerationCounter { 44 public: 45 GrAtlasManager(GrProxyProvider*, 46 size_t maxTextureBytes, 47 GrDrawOpAtlas::AllowMultitexturing, 48 bool supportBilerpAtlas); 49 ~GrAtlasManager() override; 50 51 // if getViews returns nullptr, the client must not try to use other functions on the 52 // StrikeCache which use the atlas. This function *must* be called first, before other 53 // functions which use the atlas. Note that we can have proxies available but none active 54 // (i.e., none instantiated). getViews(skgpu::MaskFormat format,unsigned int * numActiveProxies)55 const GrSurfaceProxyView* getViews(skgpu::MaskFormat format, unsigned int* numActiveProxies) { 56 format = this->resolveMaskFormat(format); 57 if (this->initAtlas(format)) { 58 *numActiveProxies = this->getAtlas(format)->numActivePages(); 59 return this->getAtlas(format)->getViews(); 60 } 61 *numActiveProxies = 0; 62 return nullptr; 63 } 64 65 void freeAll(); 66 67 bool hasGlyph(skgpu::MaskFormat, sktext::gpu::Glyph*); 68 69 #if defined(SK_ENABLE_SMALL_PAGE) || defined(SK_DEBUG_ATLAS_HIT_RATE) incAtlasHitCount()70 void incAtlasHitCount() { fAtlasHitCount++; } incAtlasMissCount()71 void incAtlasMissCount() { fAtlasMissCount++; } atlasHitRate()72 float atlasHitRate() { 73 if (fAtlasHitCount + fAtlasMissCount == 0) { 74 return 0; 75 } 76 return (float)fAtlasHitCount / (fAtlasHitCount + fAtlasMissCount); 77 } resetHitCount()78 void resetHitCount() { 79 fAtlasHitCount = 0; 80 fAtlasMissCount = 0; 81 } 82 #endif 83 84 GrDrawOpAtlas::ErrorCode addGlyphToAtlas(const SkGlyph&, 85 sktext::gpu::Glyph*, 86 int srcPadding, 87 GrResourceProvider*, 88 GrDeferredUploadTarget*); 89 90 // To ensure the GrDrawOpAtlas does not evict the Glyph Mask from its texture backing store, 91 // the client must pass in the current op token along with the sktext::gpu::Glyph. 92 // A BulkUsePlotUpdater is used to manage bulk last use token updating in the Atlas. 93 // For convenience, this function will also set the use token for the current glyph if required 94 // NOTE: the bulk uploader is only valid if the subrun has a valid atlasGeneration 95 void addGlyphToBulkAndSetUseToken(skgpu::BulkUsePlotUpdater*, skgpu::MaskFormat, 96 sktext::gpu::Glyph*, skgpu::AtlasToken); 97 setUseTokenBulk(const skgpu::BulkUsePlotUpdater & updater,skgpu::AtlasToken token,skgpu::MaskFormat format)98 void setUseTokenBulk(const skgpu::BulkUsePlotUpdater& updater, 99 skgpu::AtlasToken token, 100 skgpu::MaskFormat format) { 101 this->getAtlas(format)->setLastUseTokenBulk(updater, token); 102 } 103 104 // add to texture atlas that matches this format 105 GrDrawOpAtlas::ErrorCode addToAtlas(GrResourceProvider*, GrDeferredUploadTarget*, 106 skgpu::MaskFormat, int width, int height, const void* image, 107 skgpu::AtlasLocator*); 108 109 // Some clients may wish to verify the integrity of the texture backing store of the 110 // GrDrawOpAtlas. The atlasGeneration returned below is a monotonically increasing number which 111 // changes every time something is removed from the texture backing store. atlasGeneration(skgpu::MaskFormat format)112 uint64_t atlasGeneration(skgpu::MaskFormat format) const { 113 return this->getAtlas(format)->atlasGeneration(); 114 } 115 116 // GrOnFlushCallbackObject overrides 117 preFlush(GrOnFlushResourceProvider * onFlushRP)118 bool preFlush(GrOnFlushResourceProvider* onFlushRP) override { 119 #if defined(GPU_TEST_UTILS) 120 if (onFlushRP->failFlushTimeCallbacks()) { 121 return false; 122 } 123 #endif 124 125 for (int i = 0; i < skgpu::kMaskFormatCount; ++i) { 126 if (fAtlases[i]) { 127 fAtlases[i]->instantiate(onFlushRP); 128 } 129 } 130 return true; 131 } 132 postFlush(skgpu::AtlasToken startTokenForNextFlush)133 void postFlush(skgpu::AtlasToken startTokenForNextFlush) override { 134 #if defined(SK_ENABLE_SMALL_PAGE) || defined(SK_DEBUG_ATLAS_HIT_RATE) 135 bool isRadicals = false; 136 static int count = 0; 137 count++; 138 if (count == 5) { 139 float hitRate = atlasHitRate(); 140 if (!(fabs(hitRate-0) <= 1.0e-6)) { 141 #ifdef SK_DEBUG_ATLAS_HIT_RATE 142 SkDebugf("----- last 5 flush AtlasHitRate = %{public}6.2f.", hitRate); 143 #endif 144 if (hitRate < 0.2) { 145 isRadicals = true; 146 } 147 } 148 resetHitCount(); 149 count = 0; 150 } 151 #endif 152 for (int i = 0; i < skgpu::kMaskFormatCount; ++i) { 153 if (fAtlases[i]) { 154 #ifdef SK_ENABLE_SMALL_PAGE 155 fAtlases[i]->setRadicalsCompactFlag(isRadicals); 156 #endif 157 fAtlases[i]->compact(startTokenForNextFlush); 158 } 159 } 160 } 161 162 // The AtlasGlyph cache always survives freeGpuResources so we want it to remain in the active 163 // OnFlushCallbackObject list retainOnFreeGpuResources()164 bool retainOnFreeGpuResources() override { return true; } 165 166 private: 167 friend class GrAtlasManagerTools; 168 bool initAtlas(skgpu::MaskFormat); 169 // Change an expected 565 mask format to 8888 if 565 is not supported (will happen when using 170 // Metal on macOS). The actual conversion of the data is handled in get_packed_glyph_image() in 171 // StrikeCache.cpp resolveMaskFormat(skgpu::MaskFormat format)172 skgpu::MaskFormat resolveMaskFormat(skgpu::MaskFormat format) const { 173 if (skgpu::MaskFormat::kA565 == format && 174 !fProxyProvider->caps()->getDefaultBackendFormat(GrColorType::kBGR_565, 175 GrRenderable::kNo).isValid()) { 176 format = skgpu::MaskFormat::kARGB; 177 } 178 return format; 179 } 180 181 // There is a 1:1 mapping between skgpu::MaskFormats and atlas indices MaskFormatToAtlasIndex(skgpu::MaskFormat format)182 static int MaskFormatToAtlasIndex(skgpu::MaskFormat format) { 183 return static_cast<int>(format); 184 } AtlasIndexToMaskFormat(int idx)185 static skgpu::MaskFormat AtlasIndexToMaskFormat(int idx) { 186 return static_cast<skgpu::MaskFormat>(idx); 187 } 188 getAtlas(skgpu::MaskFormat format)189 GrDrawOpAtlas* getAtlas(skgpu::MaskFormat format) const { 190 format = this->resolveMaskFormat(format); 191 int atlasIndex = MaskFormatToAtlasIndex(format); 192 SkASSERT(fAtlases[atlasIndex]); 193 return fAtlases[atlasIndex].get(); 194 } 195 196 GrDrawOpAtlas::AllowMultitexturing fAllowMultitexturing; 197 std::unique_ptr<GrDrawOpAtlas> fAtlases[skgpu::kMaskFormatCount]; 198 static_assert(skgpu::kMaskFormatCount == 3); 199 bool fSupportBilerpAtlas; 200 GrProxyProvider* fProxyProvider; 201 sk_sp<const GrCaps> fCaps; 202 GrDrawOpAtlasConfig fAtlasConfig; 203 204 #if defined(SK_ENABLE_SMALL_PAGE) || defined(SK_DEBUG_ATLAS_HIT_RATE) 205 int fAtlasHitCount = 0; 206 int fAtlasMissCount = 0; 207 #endif 208 using INHERITED = GrOnFlushCallbackObject; 209 }; 210 211 #endif // GrAtlasManager_DEFINED 212