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