• 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 "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