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