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 #include "GrBatchAtlas.h" | 8 #include "GrBatchAtlas.h" |
9 #include "GrBatchFlushState.h" | 9 #include "GrBatchFlushState.h" |
10 #include "GrRectanizer.h" | 10 #include "GrRectanizer.h" |
11 #include "GrTracing.h" | 11 #include "GrTracing.h" |
12 #include "GrVertexBuffer.h" | 12 #include "GrVertexBuffer.h" |
13 | 13 |
14 static inline void adjust_for_offset(SkIPoint16* loc, const SkIPoint16& offset)
{ | 14 // The backing GrTexture for a GrBatchAtlas is broken into a spatial grid of Bat
chPlots. |
15 loc->fX += offset.fX; | 15 // The BatchPlots keep track of subimage placement via their GrRectanizer. A Bat
chPlot |
16 loc->fY += offset.fY; | 16 // manages the lifetime of its data using two tokens, a last use token and a las
t upload token. |
17 } | 17 // Once a BatchPlot is "full" (i.e. there is no room for the new subimage accord
ing to the |
18 | 18 // GrRectanizer), it can no longer be used unless the last use of the GrPlot has
already been |
19 static GrBatchAtlas::AtlasID create_id(uint32_t index, uint64_t generation) { | |
20 SkASSERT(index < (1 << 16)); | |
21 SkASSERT(generation < ((uint64_t)1 << 48)); | |
22 return generation << 16 | index; | |
23 } | |
24 | |
25 // The backing GrTexture for a GrBatchAtlas is broken into a spatial grid of GrB
atchPlots. | |
26 // The GrBatchPlots keep track of subimage placement via their GrRectanizer. In
turn, a GrBatchPlot | |
27 // manages the lifetime of its data using two tokens, a last ref toke and a last
upload token. | |
28 // Once a GrBatchPlot is "full" (i.e. there is no room for the new subimage acco
rding to the | |
29 // GrRectanizer), it can no longer be used unless the last ref on the GrPlot has
already been | |
30 // flushed through to the gpu. | 19 // flushed through to the gpu. |
31 | 20 |
32 class BatchPlot : public SkRefCnt { | 21 class BatchPlot : public SkRefCnt { |
33 public: | |
34 SK_DECLARE_INTERNAL_LLIST_INTERFACE(BatchPlot); | 22 SK_DECLARE_INTERNAL_LLIST_INTERFACE(BatchPlot); |
35 | 23 |
36 // index() refers to the index of the plot in the owning GrAtlas's plot arra
y. genID() is a | 24 public: |
37 // monotonically incrementing number which is bumped every time the cpu back
ing store is | 25 // index() is a unique id for the plot relative to the owning GrAtlas. genI
D() is a |
38 // wiped, or when the plot itself is evicted from the atlas(ie, there is con
tinuity in genID() | 26 // monotonically incremented number which is bumped every time this plot is |
39 // across atlas spills) | 27 // evicted from the cache (i.e., there is continuity in genID() across atlas
spills). |
40 uint32_t index() const { return fIndex; } | 28 uint32_t index() const { return fIndex; } |
41 uint64_t genID() const { return fGenID; } | 29 uint64_t genID() const { return fGenID; } |
42 GrBatchAtlas::AtlasID id() { | 30 GrBatchAtlas::AtlasID id() const { |
43 SkASSERT(GrBatchAtlas::kInvalidAtlasID != fID); | 31 SkASSERT(GrBatchAtlas::kInvalidAtlasID != fID); |
44 return fID; | 32 return fID; |
45 } | 33 } |
| 34 SkDEBUGCODE(size_t bpp() const { return fBytesPerPixel; }) |
46 | 35 |
47 GrTexture* texture() const { return fTexture; } | 36 bool addSubImage(int width, int height, const void* image, SkIPoint16* loc)
{ |
| 37 SkASSERT(width <= fWidth && height <= fHeight); |
48 | 38 |
49 bool addSubImage(int width, int height, const void* image, SkIPoint16* loc,
size_t rowBytes) { | 39 if (!fRects) { |
| 40 fRects = GrRectanizer::Factory(fWidth, fHeight); |
| 41 } |
| 42 |
50 if (!fRects->addRect(width, height, loc)) { | 43 if (!fRects->addRect(width, height, loc)) { |
51 return false; | 44 return false; |
52 } | 45 } |
53 | 46 |
54 if (!fData) { | 47 if (!fData) { |
55 fData = reinterpret_cast<unsigned char*>(sk_calloc_throw(fBytesPerPi
xel * fWidth * | 48 fData = reinterpret_cast<unsigned char*>(sk_calloc_throw(fBytesPerPi
xel * fWidth * |
56 fHeight)); | 49 fHeight)); |
57 } | 50 } |
| 51 size_t rowBytes = width * fBytesPerPixel; |
58 const unsigned char* imagePtr = (const unsigned char*)image; | 52 const unsigned char* imagePtr = (const unsigned char*)image; |
59 // point ourselves at the right starting spot | 53 // point ourselves at the right starting spot |
60 unsigned char* dataPtr = fData; | 54 unsigned char* dataPtr = fData; |
61 dataPtr += fBytesPerPixel * fWidth * loc->fY; | 55 dataPtr += fBytesPerPixel * fWidth * loc->fY; |
62 dataPtr += fBytesPerPixel * loc->fX; | 56 dataPtr += fBytesPerPixel * loc->fX; |
63 // copy into the data buffer | 57 // copy into the data buffer |
64 for (int i = 0; i < height; ++i) { | 58 for (int i = 0; i < height; ++i) { |
65 memcpy(dataPtr, imagePtr, rowBytes); | 59 memcpy(dataPtr, imagePtr, rowBytes); |
66 dataPtr += fBytesPerPixel * fWidth; | 60 dataPtr += fBytesPerPixel * fWidth; |
67 imagePtr += rowBytes; | 61 imagePtr += rowBytes; |
68 } | 62 } |
69 | 63 |
70 fDirtyRect.join(loc->fX, loc->fY, loc->fX + width, loc->fY + height); | 64 fDirtyRect.join(loc->fX, loc->fY, loc->fX + width, loc->fY + height); |
71 adjust_for_offset(loc, fOffset); | 65 |
| 66 loc->fX += fOffset.fX; |
| 67 loc->fY += fOffset.fY; |
72 SkDEBUGCODE(fDirty = true;) | 68 SkDEBUGCODE(fDirty = true;) |
73 | 69 |
74 return true; | 70 return true; |
75 } | 71 } |
76 | 72 |
77 // to manage the lifetime of a plot, we use two tokens. We use last upload
token to know when | 73 // To manage the lifetime of a plot, we use two tokens. We use the last upl
oad token to know |
78 // we can 'piggy back' uploads, ie if the last upload hasn't been flushed to
gpu, we don't need | 74 // when we can 'piggy back' uploads, ie if the last upload hasn't been flush
ed to gpu, we don't |
79 // to issue a new upload even if we update the cpu backing store. We use la
stref to determine | 75 // need to issue a new upload even if we update the cpu backing store. We u
se lastUse to |
80 // when we can evict a plot from the cache, ie if the last ref has already f
lushed through | 76 // determine when we can evict a plot from the cache, ie if the last use has
already flushed |
81 // the gpu then we can reuse the plot | 77 // through the gpu then we can reuse the plot. |
82 GrBatchToken lastUploadToken() const { return fLastUpload; } | 78 GrBatchToken lastUploadToken() const { return fLastUpload; } |
83 GrBatchToken lastUseToken() const { return fLastUse; } | 79 GrBatchToken lastUseToken() const { return fLastUse; } |
84 void setLastUploadToken(GrBatchToken batchToken) { | 80 void setLastUploadToken(GrBatchToken batchToken) { |
85 SkASSERT(batchToken >= fLastUpload); | 81 SkASSERT(batchToken >= fLastUpload); |
86 fLastUpload = batchToken; | 82 fLastUpload = batchToken; |
87 } | 83 } |
88 void setLastUseToken(GrBatchToken batchToken) { | 84 void setLastUseToken(GrBatchToken batchToken) { |
89 SkASSERT(batchToken >= fLastUse); | 85 SkASSERT(batchToken >= fLastUse); |
90 fLastUse = batchToken; | 86 fLastUse = batchToken; |
91 } | 87 } |
92 | 88 |
93 void uploadToTexture(GrBatchUploader::TextureUploader* uploader) { | 89 void uploadToTexture(GrBatchUploader::TextureUploader* uploader, GrTexture*
texture) { |
94 // We should only be issuing uploads if we are in fact dirty | 90 // We should only be issuing uploads if we are in fact dirty |
95 SkASSERT(fDirty && fData && fTexture); | 91 SkASSERT(fDirty && fData && texture); |
96 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), "GrBatchPlot::upload
ToTexture"); | 92 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), "GrBatchPlot::upload
ToTexture"); |
97 size_t rowBytes = fBytesPerPixel * fRects->width(); | 93 size_t rowBytes = fBytesPerPixel * fWidth; |
98 const unsigned char* dataPtr = fData; | 94 const unsigned char* dataPtr = fData; |
99 dataPtr += rowBytes * fDirtyRect.fTop; | 95 dataPtr += rowBytes * fDirtyRect.fTop; |
100 dataPtr += fBytesPerPixel * fDirtyRect.fLeft; | 96 dataPtr += fBytesPerPixel * fDirtyRect.fLeft; |
101 uploader->writeTexturePixels(fTexture, | 97 uploader->writeTexturePixels(texture, |
102 fOffset.fX + fDirtyRect.fLeft, fOffset.fY +
fDirtyRect.fTop, | 98 fOffset.fX + fDirtyRect.fLeft, fOffset.fY +
fDirtyRect.fTop, |
103 fDirtyRect.width(), fDirtyRect.height(), | 99 fDirtyRect.width(), fDirtyRect.height(), |
104 fTexture->config(), dataPtr, rowBytes); | 100 fConfig, dataPtr, rowBytes); |
105 fDirtyRect.setEmpty(); | 101 fDirtyRect.setEmpty(); |
106 SkDEBUGCODE(fDirty = false;) | 102 SkDEBUGCODE(fDirty = false;) |
107 } | 103 } |
108 | 104 |
109 void resetRects() { | 105 void resetRects() { |
110 SkASSERT(fRects); | 106 if (fRects) { |
111 fRects->reset(); | 107 fRects->reset(); |
| 108 } |
| 109 |
112 fGenID++; | 110 fGenID++; |
113 fID = create_id(fIndex, fGenID); | 111 fID = CreateId(fIndex, fGenID); |
114 | 112 |
115 // zero out the plot | 113 // zero out the plot |
116 if (fData) { | 114 if (fData) { |
117 sk_bzero(fData, fBytesPerPixel * fWidth * fHeight); | 115 sk_bzero(fData, fBytesPerPixel * fWidth * fHeight); |
118 } | 116 } |
119 | 117 |
120 fDirtyRect.setEmpty(); | 118 fDirtyRect.setEmpty(); |
121 SkDEBUGCODE(fDirty = false;) | 119 SkDEBUGCODE(fDirty = false;) |
122 } | 120 } |
123 | 121 |
124 uint32_t x() const { return fX; } | |
125 uint32_t y() const { return fY; } | |
126 | |
127 private: | 122 private: |
128 BatchPlot() | 123 BatchPlot(int index, uint64_t genID, int offX, int offY, int width, int heig
ht, |
| 124 GrPixelConfig config) |
129 : fLastUpload(0) | 125 : fLastUpload(0) |
130 , fLastUse(0) | 126 , fLastUse(0) |
131 , fIndex(-1) | 127 , fIndex(index) |
132 , fGenID(-1) | 128 , fGenID(genID) |
133 , fID(0) | 129 , fID(CreateId(fIndex, fGenID)) |
134 , fData(nullptr) | 130 , fData(nullptr) |
135 , fWidth(0) | 131 , fWidth(width) |
136 , fHeight(0) | 132 , fHeight(height) |
137 , fX(0) | 133 , fX(offX) |
138 , fY(0) | 134 , fY(offY) |
139 , fTexture(nullptr) | |
140 , fRects(nullptr) | 135 , fRects(nullptr) |
141 , fAtlas(nullptr) | 136 , fOffset(SkIPoint16::Make(fX * fWidth, fY * fHeight)) |
142 , fBytesPerPixel(1) | 137 , fConfig(config) |
| 138 , fBytesPerPixel(GrBytesPerPixel(config)) |
143 #ifdef SK_DEBUG | 139 #ifdef SK_DEBUG |
144 , fDirty(false) | 140 , fDirty(false) |
145 #endif | 141 #endif |
146 { | 142 { |
147 fOffset.set(0, 0); | 143 fDirtyRect.setEmpty(); |
148 } | 144 } |
149 | 145 |
150 ~BatchPlot() { | 146 ~BatchPlot() override { |
151 sk_free(fData); | 147 sk_free(fData); |
152 fData = nullptr; | |
153 delete fRects; | 148 delete fRects; |
154 } | 149 } |
155 | 150 |
156 void init(GrBatchAtlas* atlas, GrTexture* texture, int index, uint64_t gener
ation, | 151 // Create a clone of this plot. The cloned plot will take the place of the |
157 int offX, int offY, int width, int height, size_t bpp) { | 152 // current plot in the atlas. |
158 fIndex = index; | 153 BatchPlot* clone() const { |
159 fGenID = generation; | 154 return new BatchPlot(fIndex, fGenID+1, fX, fY, fWidth, fHeight, fConfig)
; |
160 fID = create_id(index, generation); | |
161 fWidth = width; | |
162 fHeight = height; | |
163 fX = offX; | |
164 fY = offY; | |
165 fRects = GrRectanizer::Factory(width, height); | |
166 fAtlas = atlas; | |
167 fOffset.set(offX * width, offY * height); | |
168 fBytesPerPixel = bpp; | |
169 fData = nullptr; | |
170 fDirtyRect.setEmpty(); | |
171 SkDEBUGCODE(fDirty = false;) | |
172 fTexture = texture; | |
173 } | 155 } |
174 | 156 |
175 GrBatchToken fLastUpload; | 157 static GrBatchAtlas::AtlasID CreateId(uint32_t index, uint64_t generation) { |
176 GrBatchToken fLastUse; | 158 SkASSERT(index < (1 << 16)); |
| 159 SkASSERT(generation < ((uint64_t)1 << 48)); |
| 160 return generation << 16 | index; |
| 161 } |
177 | 162 |
178 uint32_t fIndex; | 163 GrBatchToken fLastUpload; |
179 uint64_t fGenID; | 164 GrBatchToken fLastUse; |
| 165 |
| 166 const uint32_t fIndex; |
| 167 uint64_t fGenID; |
180 GrBatchAtlas::AtlasID fID; | 168 GrBatchAtlas::AtlasID fID; |
181 unsigned char* fData; | 169 unsigned char* fData; |
182 uint32_t fWidth; | 170 const int fWidth; |
183 uint32_t fHeight; | 171 const int fHeight; |
184 uint32_t fX; | 172 const int fX; |
185 uint32_t fY; | 173 const int fY; |
186 GrTexture* fTexture; | 174 GrRectanizer* fRects; |
187 GrRectanizer* fRects; | 175 const SkIPoint16 fOffset; // the offset of the plot in the backi
ng texture |
188 GrBatchAtlas* fAtlas; | 176 const GrPixelConfig fConfig; |
189 SkIPoint16 fOffset; // the offset of the plot in the backing texture | 177 const size_t fBytesPerPixel; |
190 size_t fBytesPerPixel; | 178 SkIRect fDirtyRect; |
191 SkIRect fDirtyRect; | 179 SkDEBUGCODE(bool fDirty;) |
192 SkDEBUGCODE(bool fDirty;) | |
193 | 180 |
194 friend class GrBatchAtlas; | 181 friend class GrBatchAtlas; |
195 | 182 |
196 typedef SkRefCnt INHERITED; | 183 typedef SkRefCnt INHERITED; |
197 }; | 184 }; |
198 | 185 |
199 //////////////////////////////////////////////////////////////////////////////// | 186 //////////////////////////////////////////////////////////////////////////////// |
200 | 187 |
201 class GrPlotUploader : public GrBatchUploader { | 188 class GrPlotUploader : public GrBatchUploader { |
202 public: | 189 public: |
203 GrPlotUploader(BatchPlot* plot) | 190 GrPlotUploader(BatchPlot* plot, GrTexture* texture) |
204 : INHERITED(plot->lastUploadToken()) | 191 : INHERITED(plot->lastUploadToken()) |
205 , fPlot(SkRef(plot)) { | 192 , fPlot(SkRef(plot)) |
| 193 , fTexture(texture) { |
206 SkASSERT(plot); | 194 SkASSERT(plot); |
207 } | 195 } |
208 | 196 |
209 void upload(TextureUploader* uploader) override { | 197 void upload(TextureUploader* uploader) override { |
210 fPlot->uploadToTexture(uploader); | 198 fPlot->uploadToTexture(uploader, fTexture); |
211 } | 199 } |
212 | 200 |
213 private: | 201 private: |
214 SkAutoTUnref<BatchPlot> fPlot; | 202 SkAutoTUnref<BatchPlot> fPlot; |
| 203 GrTexture* fTexture; |
215 | 204 |
216 typedef GrBatchUploader INHERITED; | 205 typedef GrBatchUploader INHERITED; |
217 }; | 206 }; |
218 | 207 |
219 /////////////////////////////////////////////////////////////////////////////// | 208 /////////////////////////////////////////////////////////////////////////////// |
220 | 209 |
221 GrBatchAtlas::GrBatchAtlas(GrTexture* texture, int numPlotsX, int numPlotsY) | 210 GrBatchAtlas::GrBatchAtlas(GrTexture* texture, int numPlotsX, int numPlotsY) |
222 : fTexture(texture) | 211 : fTexture(texture) |
223 , fNumPlotsX(numPlotsX) | |
224 , fNumPlotsY(numPlotsY) | |
225 , fPlotWidth(texture->width() / numPlotsX) | |
226 , fPlotHeight(texture->height() / numPlotsY) | |
227 , fAtlasGeneration(kInvalidAtlasGeneration + 1) { | 212 , fAtlasGeneration(kInvalidAtlasGeneration + 1) { |
228 SkASSERT(fNumPlotsX * fNumPlotsY <= BulkUseTokenUpdater::kMaxPlots); | 213 |
229 SkASSERT(fPlotWidth * fNumPlotsX == static_cast<uint32_t>(texture->width()))
; | 214 int plotWidth = texture->width() / numPlotsX; |
230 SkASSERT(fPlotHeight * fNumPlotsY == static_cast<uint32_t>(texture->height()
)); | 215 int plotHeight = texture->height() / numPlotsY; |
| 216 SkASSERT(numPlotsX * numPlotsY <= BulkUseTokenUpdater::kMaxPlots); |
| 217 SkASSERT(plotWidth * numPlotsX == texture->width()); |
| 218 SkASSERT(plotHeight * numPlotsY == texture->height()); |
| 219 |
| 220 SkDEBUGCODE(fNumPlots = numPlotsX * numPlotsY;) |
231 | 221 |
232 // We currently do not support compressed atlases... | 222 // We currently do not support compressed atlases... |
233 SkASSERT(!GrPixelConfigIsCompressed(texture->desc().fConfig)); | 223 SkASSERT(!GrPixelConfigIsCompressed(texture->desc().fConfig)); |
234 | 224 |
235 // set up allocated plots | 225 // set up allocated plots |
236 fBPP = GrBytesPerPixel(texture->desc().fConfig); | 226 fPlotArray = new SkAutoTUnref<BatchPlot>[numPlotsX * numPlotsY]; |
237 fPlotArray = new SkAutoTUnref<BatchPlot>[(fNumPlotsX * fNumPlotsY)]; | |
238 | 227 |
239 SkAutoTUnref<BatchPlot>* currPlot = fPlotArray; | 228 SkAutoTUnref<BatchPlot>* currPlot = fPlotArray; |
240 for (int y = fNumPlotsY - 1, r = 0; y >= 0; --y, ++r) { | 229 for (int y = numPlotsY - 1, r = 0; y >= 0; --y, ++r) { |
241 for (int x = fNumPlotsX - 1, c = 0; x >= 0; --x, ++c) { | 230 for (int x = numPlotsX - 1, c = 0; x >= 0; --x, ++c) { |
242 uint32_t id = r * fNumPlotsX + c; | 231 uint32_t index = r * numPlotsX + c; |
243 currPlot->reset(new BatchPlot); | 232 currPlot->reset(new BatchPlot(index, 1, x, y, plotWidth, plotHeight, |
244 (*currPlot)->init(this, texture, id, 1, x, y, fPlotWidth, fPlotHeigh
t, fBPP); | 233 texture->desc().fConfig)); |
245 | 234 |
246 // build LRU list | 235 // build LRU list |
247 fPlotList.addToHead(currPlot->get()); | 236 fPlotList.addToHead(currPlot->get()); |
248 ++currPlot; | 237 ++currPlot; |
249 } | 238 } |
250 } | 239 } |
251 } | 240 } |
252 | 241 |
253 GrBatchAtlas::~GrBatchAtlas() { | 242 GrBatchAtlas::~GrBatchAtlas() { |
254 SkSafeUnref(fTexture); | 243 SkSafeUnref(fTexture); |
(...skipping 16 matching lines...) Expand all Loading... |
271 } | 260 } |
272 | 261 |
273 inline void GrBatchAtlas::updatePlot(GrDrawBatch::Target* target, AtlasID* id, B
atchPlot* plot) { | 262 inline void GrBatchAtlas::updatePlot(GrDrawBatch::Target* target, AtlasID* id, B
atchPlot* plot) { |
274 this->makeMRU(plot); | 263 this->makeMRU(plot); |
275 | 264 |
276 // If our most recent upload has already occurred then we have to insert a n
ew | 265 // If our most recent upload has already occurred then we have to insert a n
ew |
277 // upload. Otherwise, we already have a scheduled upload that hasn't yet ocu
rred. | 266 // upload. Otherwise, we already have a scheduled upload that hasn't yet ocu
rred. |
278 // This new update will piggy back on that previously scheduled update. | 267 // This new update will piggy back on that previously scheduled update. |
279 if (target->hasTokenBeenFlushed(plot->lastUploadToken())) { | 268 if (target->hasTokenBeenFlushed(plot->lastUploadToken())) { |
280 plot->setLastUploadToken(target->asapToken()); | 269 plot->setLastUploadToken(target->asapToken()); |
281 SkAutoTUnref<GrPlotUploader> uploader(new GrPlotUploader(plot)); | 270 SkAutoTUnref<GrPlotUploader> uploader(new GrPlotUploader(plot, fTexture)
); |
282 target->upload(uploader); | 271 target->upload(uploader); |
283 } | 272 } |
284 *id = plot->id(); | 273 *id = plot->id(); |
285 } | 274 } |
286 | 275 |
287 bool GrBatchAtlas::addToAtlas(AtlasID* id, GrDrawBatch::Target* batchTarget, | 276 bool GrBatchAtlas::addToAtlas(AtlasID* id, GrDrawBatch::Target* batchTarget, |
288 int width, int height, const void* image, SkIPoint
16* loc) { | 277 int width, int height, const void* image, SkIPoint
16* loc) { |
289 // We should already have a texture, TODO clean this up | 278 // We should already have a texture, TODO clean this up |
290 SkASSERT(fTexture && | 279 SkASSERT(fTexture); |
291 static_cast<uint32_t>(width) <= fPlotWidth && | |
292 static_cast<uint32_t>(height) <= fPlotHeight); | |
293 | 280 |
294 // now look through all allocated plots for one we can share, in Most Recent
ly Refed order | 281 // now look through all allocated plots for one we can share, in Most Recent
ly Refed order |
295 GrBatchPlotList::Iter plotIter; | 282 GrBatchPlotList::Iter plotIter; |
296 plotIter.init(fPlotList, GrBatchPlotList::Iter::kHead_IterStart); | 283 plotIter.init(fPlotList, GrBatchPlotList::Iter::kHead_IterStart); |
297 BatchPlot* plot; | 284 BatchPlot* plot; |
298 while ((plot = plotIter.get())) { | 285 while ((plot = plotIter.get())) { |
299 if (plot->addSubImage(width, height, image, loc, fBPP * width)) { | 286 SkASSERT(GrBytesPerPixel(fTexture->desc().fConfig) == plot->bpp()); |
| 287 if (plot->addSubImage(width, height, image, loc)) { |
300 this->updatePlot(batchTarget, id, plot); | 288 this->updatePlot(batchTarget, id, plot); |
301 return true; | 289 return true; |
302 } | 290 } |
303 plotIter.next(); | 291 plotIter.next(); |
304 } | 292 } |
305 | 293 |
306 // If the above fails, then see if the least recently refed plot has already
been flushed to the | 294 // If the above fails, then see if the least recently refed plot has already
been flushed to the |
307 // gpu | 295 // gpu |
308 plotIter.init(fPlotList, GrBatchPlotList::Iter::kTail_IterStart); | 296 plot = fPlotList.tail(); |
309 plot = plotIter.get(); | |
310 SkASSERT(plot); | 297 SkASSERT(plot); |
311 if (batchTarget->hasTokenBeenFlushed(plot->lastUseToken())) { | 298 if (batchTarget->hasTokenBeenFlushed(plot->lastUseToken())) { |
312 this->processEviction(plot->id()); | 299 this->processEviction(plot->id()); |
313 plot->resetRects(); | 300 plot->resetRects(); |
314 SkDEBUGCODE(bool verify = )plot->addSubImage(width, height, image, loc,
fBPP * width); | 301 SkASSERT(GrBytesPerPixel(fTexture->desc().fConfig) == plot->bpp()); |
| 302 SkDEBUGCODE(bool verify = )plot->addSubImage(width, height, image, loc); |
315 SkASSERT(verify); | 303 SkASSERT(verify); |
316 this->updatePlot(batchTarget, id, plot); | 304 this->updatePlot(batchTarget, id, plot); |
317 fAtlasGeneration++; | 305 fAtlasGeneration++; |
318 return true; | 306 return true; |
319 } | 307 } |
320 | 308 |
321 // The least recently refed plot hasn't been flushed to the gpu yet, however
, if we have flushed | 309 // The least recently used plot hasn't been flushed to the gpu yet, however,
if we have flushed |
322 // it to the batch target than we can reuse it. Our last ref token is guara
nteed to be less | 310 // it to the batch target than we can reuse it. Our last use token is guara
nteed to be less |
323 // than or equal to the current token. If its 'less than' the current token
, than we can spin | 311 // than or equal to the current token. If its 'less than' the current token
, than we can spin |
324 // off the plot(ie let the batch target manage it) and create a new plot in
its place in our | 312 // off the plot (ie let the batch target manage it) and create a new plot in
its place in our |
325 // array. If it is equal to the currentToken, then the caller has to flush
draws to the batch | 313 // array. If it is equal to the currentToken, then the caller has to flush
draws to the batch |
326 // target so we can spin off the plot | 314 // target so we can spin off the plot |
327 if (plot->lastUseToken() == batchTarget->currentToken()) { | 315 if (plot->lastUseToken() == batchTarget->currentToken()) { |
328 return false; | 316 return false; |
329 } | 317 } |
330 | 318 |
331 // We take an extra ref here so our plot isn't deleted when we reset its ind
ex in the array. | 319 SkASSERT(plot->lastUseToken() < batchTarget->currentToken()); |
332 plot->ref(); | 320 SkASSERT(!batchTarget->hasTokenBeenFlushed(batchTarget->currentToken())); |
333 int index = plot->index(); | 321 |
334 int x = plot->x(); | 322 SkASSERT(!plot->unique()); // The GrPlotUpdater should have a ref too |
335 int y = plot->y(); | |
336 uint64_t generation = plot->genID(); | |
337 | 323 |
338 this->processEviction(plot->id()); | 324 this->processEviction(plot->id()); |
339 fPlotList.remove(plot); | 325 fPlotList.remove(plot); |
340 SkAutoTUnref<BatchPlot>& newPlot = fPlotArray[plot->index()]; | 326 SkAutoTUnref<BatchPlot>& newPlot = fPlotArray[plot->index()]; |
341 newPlot.reset(new BatchPlot); | 327 newPlot.reset(plot->clone()); |
342 newPlot->init(this, fTexture, index, ++generation, x, y, fPlotWidth, fPlotHe
ight, fBPP); | |
343 | 328 |
344 fPlotList.addToHead(newPlot.get()); | 329 fPlotList.addToHead(newPlot.get()); |
345 SkDEBUGCODE(bool verify = )newPlot->addSubImage(width, height, image, loc, f
BPP * width); | 330 SkASSERT(GrBytesPerPixel(fTexture->desc().fConfig) == newPlot->bpp()); |
| 331 SkDEBUGCODE(bool verify = )newPlot->addSubImage(width, height, image, loc); |
346 SkASSERT(verify); | 332 SkASSERT(verify); |
| 333 |
347 newPlot->setLastUploadToken(batchTarget->currentToken()); | 334 newPlot->setLastUploadToken(batchTarget->currentToken()); |
348 SkAutoTUnref<GrPlotUploader> uploader(new GrPlotUploader(newPlot)); | 335 SkAutoTUnref<GrPlotUploader> uploader(new GrPlotUploader(newPlot, fTexture))
; |
349 batchTarget->upload(uploader); | 336 batchTarget->upload(uploader); |
350 *id = newPlot->id(); | 337 *id = newPlot->id(); |
351 plot->unref(); | 338 |
352 fAtlasGeneration++; | 339 fAtlasGeneration++; |
353 return true; | 340 return true; |
354 } | 341 } |
355 | 342 |
356 bool GrBatchAtlas::hasID(AtlasID id) { | 343 bool GrBatchAtlas::hasID(AtlasID id) { |
357 uint32_t index = GetIndexFromID(id); | 344 uint32_t index = GetIndexFromID(id); |
358 SkASSERT(index < fNumPlotsX * fNumPlotsY); | 345 SkASSERT(index < fNumPlots); |
359 return fPlotArray[index]->genID() == GetGenerationFromID(id); | 346 return fPlotArray[index]->genID() == GetGenerationFromID(id); |
360 } | 347 } |
361 | 348 |
362 void GrBatchAtlas::setLastUseToken(AtlasID id, GrBatchToken batchToken) { | 349 void GrBatchAtlas::setLastUseToken(AtlasID id, GrBatchToken batchToken) { |
363 SkASSERT(this->hasID(id)); | 350 SkASSERT(this->hasID(id)); |
364 uint32_t index = GetIndexFromID(id); | 351 uint32_t index = GetIndexFromID(id); |
365 SkASSERT(index < fNumPlotsX * fNumPlotsY); | 352 SkASSERT(index < fNumPlots); |
366 this->makeMRU(fPlotArray[index]); | 353 this->makeMRU(fPlotArray[index]); |
367 fPlotArray[index]->setLastUseToken(batchToken); | 354 fPlotArray[index]->setLastUseToken(batchToken); |
368 } | 355 } |
369 | 356 |
370 void GrBatchAtlas::setLastUseTokenBulk(const BulkUseTokenUpdater& updater, | 357 void GrBatchAtlas::setLastUseTokenBulk(const BulkUseTokenUpdater& updater, |
371 GrBatchToken batchToken) { | 358 GrBatchToken batchToken) { |
372 int count = updater.fPlotsToUpdate.count(); | 359 int count = updater.fPlotsToUpdate.count(); |
373 for (int i = 0; i < count; i++) { | 360 for (int i = 0; i < count; i++) { |
374 BatchPlot* plot = fPlotArray[updater.fPlotsToUpdate[i]]; | 361 BatchPlot* plot = fPlotArray[updater.fPlotsToUpdate[i]]; |
375 this->makeMRU(plot); | 362 this->makeMRU(plot); |
376 plot->setLastUseToken(batchToken); | 363 plot->setLastUseToken(batchToken); |
377 } | 364 } |
378 } | 365 } |
OLD | NEW |