OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #ifndef GrBatchAtlas_DEFINED | 8 #ifndef GrBatchAtlas_DEFINED |
9 #define GrBatchAtlas_DEFINED | 9 #define GrBatchAtlas_DEFINED |
10 | 10 |
11 #include "GrTexture.h" | 11 #include "GrTexture.h" |
12 #include "batches/GrDrawBatch.h" | 12 #include "batches/GrDrawBatch.h" |
13 #include "SkPoint.h" | 13 #include "SkPoint.h" |
14 #include "SkTDArray.h" | 14 #include "SkTDArray.h" |
15 #include "SkTInternalLList.h" | 15 #include "SkTInternalLList.h" |
16 | 16 |
17 class BatchPlot; | |
18 class GrRectanizer; | 17 class GrRectanizer; |
19 | 18 |
20 struct GrBatchAtlasConfig { | 19 struct GrBatchAtlasConfig { |
21 int numPlotsX() const { return fWidth / fPlotWidth; } | 20 int numPlotsX() const { return fWidth / fPlotWidth; } |
22 int numPlotsY() const { return fHeight / fPlotWidth; } | 21 int numPlotsY() const { return fHeight / fPlotWidth; } |
23 int fWidth; | 22 int fWidth; |
24 int fHeight; | 23 int fHeight; |
25 int fPlotWidth; | 24 int fPlotWidth; |
26 int fPlotHeight; | 25 int fPlotHeight; |
27 }; | 26 }; |
(...skipping 20 matching lines...) Expand all Loading... | |
48 // If provided, the image data will be written to the CPU-side backing bitma p. | 47 // If provided, the image data will be written to the CPU-side backing bitma p. |
49 // NOTE: If the client intends to refer to the atlas, they should immediatel y call 'setUseToken' | 48 // NOTE: If the client intends to refer to the atlas, they should immediatel y call 'setUseToken' |
50 // with the currentToken from the batch target, otherwise the next call to a ddToAtlas might | 49 // with the currentToken from the batch target, otherwise the next call to a ddToAtlas might |
51 // cause an eviction | 50 // cause an eviction |
52 bool addToAtlas(AtlasID*, GrDrawBatch::Target*, int width, int height, const void* image, | 51 bool addToAtlas(AtlasID*, GrDrawBatch::Target*, int width, int height, const void* image, |
53 SkIPoint16* loc); | 52 SkIPoint16* loc); |
54 | 53 |
55 GrTexture* getTexture() const { return fTexture; } | 54 GrTexture* getTexture() const { return fTexture; } |
56 | 55 |
57 uint64_t atlasGeneration() const { return fAtlasGeneration; } | 56 uint64_t atlasGeneration() const { return fAtlasGeneration; } |
58 bool hasID(AtlasID id); | 57 |
58 inline bool hasID(AtlasID id) { | |
59 uint32_t index = GetIndexFromID(id); | |
60 SkASSERT(index < fNumPlots); | |
61 return fPlotArray[index]->genID() == GetGenerationFromID(id); | |
62 } | |
59 | 63 |
60 // To ensure the atlas does not evict a given entry, the client must set the last use token | 64 // To ensure the atlas does not evict a given entry, the client must set the last use token |
61 void setLastUseToken(AtlasID id, GrBatchToken batchToken); | 65 inline void setLastUseToken(AtlasID id, GrBatchToken batchToken) { |
62 void registerEvictionCallback(EvictionFunc func, void* userData) { | 66 SkASSERT(this->hasID(id)); |
67 uint32_t index = GetIndexFromID(id); | |
68 SkASSERT(index < fNumPlots); | |
69 this->makeMRU(fPlotArray[index]); | |
70 fPlotArray[index]->setLastUseToken(batchToken); | |
71 } | |
72 | |
73 inline void registerEvictionCallback(EvictionFunc func, void* userData) { | |
63 EvictionData* data = fEvictionCallbacks.append(); | 74 EvictionData* data = fEvictionCallbacks.append(); |
64 data->fFunc = func; | 75 data->fFunc = func; |
65 data->fData = userData; | 76 data->fData = userData; |
66 } | 77 } |
67 | 78 |
68 /* | 79 /* |
69 * A class which can be handed back to GrBatchAtlas for updating in bulk las t use tokens. The | 80 * A class which can be handed back to GrBatchAtlas for updating in bulk las t use tokens. The |
70 * current max number of plots the GrBatchAtlas can handle is 32, if in the future this is | 81 * current max number of plots the GrBatchAtlas can handle is 32, if in the future this is |
71 * insufficient then we can move to a 64 bit int | 82 * insufficient then we can move to a 64 bit int |
72 */ | 83 */ |
(...skipping 30 matching lines...) Expand all Loading... | |
103 } | 114 } |
104 | 115 |
105 static const int kMinItems = 4; | 116 static const int kMinItems = 4; |
106 static const int kMaxPlots = 32; | 117 static const int kMaxPlots = 32; |
107 SkSTArray<kMinItems, int, true> fPlotsToUpdate; | 118 SkSTArray<kMinItems, int, true> fPlotsToUpdate; |
108 uint32_t fPlotAlreadyUpdated; | 119 uint32_t fPlotAlreadyUpdated; |
109 | 120 |
110 friend class GrBatchAtlas; | 121 friend class GrBatchAtlas; |
111 }; | 122 }; |
112 | 123 |
113 void setLastUseTokenBulk(const BulkUseTokenUpdater& reffer, GrBatchToken); | 124 void setLastUseTokenBulk(const BulkUseTokenUpdater& updater, GrBatchToken ba tchToken) { |
125 int count = updater.fPlotsToUpdate.count(); | |
126 for (int i = 0; i < count; i++) { | |
127 BatchPlot* plot = fPlotArray[updater.fPlotsToUpdate[i]]; | |
128 this->makeMRU(plot); | |
129 plot->setLastUseToken(batchToken); | |
130 } | |
131 } | |
114 | 132 |
115 static const int kGlyphMaxDim = 256; | 133 static const int kGlyphMaxDim = 256; |
116 static bool GlyphTooLargeForAtlas(int width, int height) { | 134 static bool GlyphTooLargeForAtlas(int width, int height) { |
117 return width > kGlyphMaxDim || height > kGlyphMaxDim; | 135 return width > kGlyphMaxDim || height > kGlyphMaxDim; |
118 } | 136 } |
119 | 137 |
120 private: | 138 private: |
139 // The backing GrTexture for a GrBatchAtlas is broken into a spatial grid of BatchPlots. | |
140 // The BatchPlots keep track of subimage placement via their GrRectanizer. A BatchPlot | |
141 // manages the lifetime of its data using two tokens, a last use token and a last upload token. | |
142 // Once a BatchPlot is "full" (i.e. there is no room for the new subimage ac cording to the | |
143 // GrRectanizer), it can no longer be used unless the last use of the GrPlot has already been | |
144 // flushed through to the gpu. | |
145 class BatchPlot : public SkRefCnt { | |
146 SK_DECLARE_INTERNAL_LLIST_INTERFACE(BatchPlot); | |
147 | |
148 public: | |
149 // index() is a unique id for the plot relative to the owning GrAtlas. genID() is a | |
150 // monotonically incremented number which is bumped every time this plot is | |
151 // evicted from the cache (i.e., there is continuity in genID() across a tlas spills). | |
152 uint32_t index() const { return fIndex; } | |
153 uint64_t genID() const { return fGenID; } | |
154 GrBatchAtlas::AtlasID id() const { | |
155 SkASSERT(GrBatchAtlas::kInvalidAtlasID != fID); | |
156 return fID; | |
157 } | |
158 SkDEBUGCODE(size_t bpp() const { return fBytesPerPixel; }) | |
159 | |
160 bool addSubImage(int width, int height, const void* image, SkIPoint16* l oc); | |
161 | |
162 // To manage the lifetime of a plot, we use two tokens. We use the last upload token to know | |
bsalomon
2015/11/18 20:58:32
nit, wrap lines
| |
163 // when we can 'piggy back' uploads, ie if the last upload hasn't been f lushed to gpu, we don't | |
164 // need to issue a new upload even if we update the cpu backing store. We use lastUse to | |
165 // determine when we can evict a plot from the cache, ie if the last use has already flushed | |
166 // through the gpu then we can reuse the plot. | |
167 GrBatchToken lastUploadToken() const { return fLastUpload; } | |
168 GrBatchToken lastUseToken() const { return fLastUse; } | |
169 void setLastUploadToken(GrBatchToken batchToken) { | |
170 SkASSERT(batchToken >= fLastUpload); | |
171 fLastUpload = batchToken; | |
172 } | |
173 void setLastUseToken(GrBatchToken batchToken) { | |
174 SkASSERT(batchToken >= fLastUse); | |
175 fLastUse = batchToken; | |
176 } | |
177 | |
178 void uploadToTexture(GrBatchUploader::TextureUploader* uploader, GrTextu re* texture); | |
179 void resetRects(); | |
180 | |
181 private: | |
182 BatchPlot(int index, uint64_t genID, int offX, int offY, int width, int height, | |
183 GrPixelConfig config); | |
184 | |
185 ~BatchPlot() override; | |
186 | |
187 // Create a clone of this plot. The cloned plot will take the place of t he | |
188 // current plot in the atlas. | |
189 BatchPlot* clone() const { | |
190 return new BatchPlot(fIndex, fGenID+1, fX, fY, fWidth, fHeight, fCon fig); | |
191 } | |
192 | |
193 static GrBatchAtlas::AtlasID CreateId(uint32_t index, uint64_t generatio n) { | |
194 SkASSERT(index < (1 << 16)); | |
195 SkASSERT(generation < ((uint64_t)1 << 48)); | |
196 return generation << 16 | index; | |
197 } | |
198 | |
199 GrBatchToken fLastUpload; | |
200 GrBatchToken fLastUse; | |
201 | |
202 const uint32_t fIndex; | |
203 uint64_t fGenID; | |
204 GrBatchAtlas::AtlasID fID; | |
205 unsigned char* fData; | |
206 const int fWidth; | |
207 const int fHeight; | |
208 const int fX; | |
209 const int fY; | |
210 GrRectanizer* fRects; | |
211 const SkIPoint16 fOffset; // the offset of the plot in the b acking texture | |
212 const GrPixelConfig fConfig; | |
213 const size_t fBytesPerPixel; | |
214 SkIRect fDirtyRect; | |
215 SkDEBUGCODE(bool fDirty;) | |
216 | |
217 friend class GrBatchAtlas; | |
218 | |
219 typedef SkRefCnt INHERITED; | |
220 }; | |
221 | |
121 typedef SkTInternalLList<BatchPlot> GrBatchPlotList; | 222 typedef SkTInternalLList<BatchPlot> GrBatchPlotList; |
122 | 223 |
123 static uint32_t GetIndexFromID(AtlasID id) { | 224 static uint32_t GetIndexFromID(AtlasID id) { |
124 return id & 0xffff; | 225 return id & 0xffff; |
125 } | 226 } |
126 | 227 |
127 // top 48 bits are reserved for the generation ID | 228 // top 48 bits are reserved for the generation ID |
128 static uint64_t GetGenerationFromID(AtlasID id) { | 229 static uint64_t GetGenerationFromID(AtlasID id) { |
129 return (id >> 16) & 0xffffffffffff; | 230 return (id >> 16) & 0xffffffffffff; |
130 } | 231 } |
131 | 232 |
132 inline void updatePlot(GrDrawBatch::Target*, AtlasID*, BatchPlot*); | 233 inline void updatePlot(GrDrawBatch::Target*, AtlasID*, BatchPlot*); |
133 | 234 |
134 inline void makeMRU(BatchPlot* plot); | 235 inline void makeMRU(BatchPlot* plot) { |
236 if (fPlotList.head() == plot) { | |
237 return; | |
238 } | |
239 | |
240 fPlotList.remove(plot); | |
241 fPlotList.addToHead(plot); | |
242 } | |
135 | 243 |
136 inline void processEviction(AtlasID); | 244 inline void processEviction(AtlasID); |
137 | 245 |
246 friend class GrPlotUploader; // to access GrBatchPlot | |
247 | |
138 GrTexture* fTexture; | 248 GrTexture* fTexture; |
139 SkDEBUGCODE(uint32_t fNumPlots;) | 249 SkDEBUGCODE(uint32_t fNumPlots;) |
140 | 250 |
141 uint64_t fAtlasGeneration; | 251 uint64_t fAtlasGeneration; |
142 | 252 |
143 struct EvictionData { | 253 struct EvictionData { |
144 EvictionFunc fFunc; | 254 EvictionFunc fFunc; |
145 void* fData; | 255 void* fData; |
146 }; | 256 }; |
147 | 257 |
148 SkTDArray<EvictionData> fEvictionCallbacks; | 258 SkTDArray<EvictionData> fEvictionCallbacks; |
149 // allocated array of GrBatchPlots | 259 // allocated array of GrBatchPlots |
150 SkAutoTUnref<BatchPlot>* fPlotArray; | 260 SkAutoTUnref<BatchPlot>* fPlotArray; |
151 // LRU list of GrPlots (MRU at head - LRU at tail) | 261 // LRU list of GrPlots (MRU at head - LRU at tail) |
152 GrBatchPlotList fPlotList; | 262 GrBatchPlotList fPlotList; |
153 }; | 263 }; |
154 | 264 |
155 #endif | 265 #endif |
OLD | NEW |