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 |
| 163 // know when we can 'piggy back' uploads, ie if the last upload hasn't b
een flushed to gpu, |
| 164 // we don't need to issue a new upload even if we update the cpu backing
store. We use |
| 165 // lastUse to determine when we can evict a plot from the cache, ie if t
he last use has |
| 166 // already flushed 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 |