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 "GrBatchTarget.h" | 9 #include "GrBatchTarget.h" |
10 #include "GrGpu.h" | 10 #include "GrGpu.h" |
11 #include "GrRectanizer.h" | 11 #include "GrRectanizer.h" |
12 #include "GrTracing.h" | 12 #include "GrTracing.h" |
13 | 13 |
| 14 // for testing |
| 15 #define ATLAS_STATS 0 |
| 16 #if ATLAS_STATS |
| 17 static int g_UploadCount = 0; |
| 18 #endif |
| 19 |
14 static inline void adjust_for_offset(SkIPoint16* loc, const SkIPoint16& offset)
{ | 20 static inline void adjust_for_offset(SkIPoint16* loc, const SkIPoint16& offset)
{ |
15 loc->fX += offset.fX; | 21 loc->fX += offset.fX; |
16 loc->fY += offset.fY; | 22 loc->fY += offset.fY; |
17 } | 23 } |
18 | 24 |
19 static GrBatchAtlas::AtlasID create_id(int index, int generation) { | 25 static GrBatchAtlas::AtlasID create_id(int index, int generation) { |
20 // Generation ID can roll over because we only check for equality | 26 // Generation ID can roll over because we only check for equality |
21 SkASSERT(index < (1 << 16)); | 27 SkASSERT(index < (1 << 16)); |
22 return generation << 16 | index; | 28 return generation << 16 | index; |
23 } | 29 } |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
60 for (int i = 0; i < height; ++i) { | 66 for (int i = 0; i < height; ++i) { |
61 memcpy(dataPtr, imagePtr, rowBytes); | 67 memcpy(dataPtr, imagePtr, rowBytes); |
62 dataPtr += fBytesPerPixel * fWidth; | 68 dataPtr += fBytesPerPixel * fWidth; |
63 imagePtr += rowBytes; | 69 imagePtr += rowBytes; |
64 } | 70 } |
65 | 71 |
66 fDirtyRect.join(loc->fX, loc->fY, loc->fX + width, loc->fY + height); | 72 fDirtyRect.join(loc->fX, loc->fY, loc->fX + width, loc->fY + height); |
67 adjust_for_offset(loc, fOffset); | 73 adjust_for_offset(loc, fOffset); |
68 SkDEBUGCODE(fDirty = true;) | 74 SkDEBUGCODE(fDirty = true;) |
69 | 75 |
| 76 #if ATLAS_STATS |
| 77 ++g_UploadCount; |
| 78 #endif |
| 79 |
70 return true; | 80 return true; |
71 } | 81 } |
72 | 82 |
73 // to manage the lifetime of a plot, we use two tokens. We use last upload
token to know when | 83 // to manage the lifetime of a plot, we use two tokens. We use last upload
token to know when |
74 // we can 'piggy back' uploads, ie if the last upload hasn't been flushed to
gpu, we don't need | 84 // we can 'piggy back' uploads, ie if the last upload hasn't been flushed to
gpu, we don't need |
75 // to issue a new upload even if we update the cpu backing store. We use la
stref to determine | 85 // to issue a new upload even if we update the cpu backing store. We use la
stref to determine |
76 // when we can evict a plot from the cache, ie if the last ref has already f
lushed through | 86 // when we can evict a plot from the cache, ie if the last ref has already f
lushed through |
77 // the gpu then we can reuse the plot | 87 // the gpu then we can reuse the plot |
78 BatchToken lastUploadToken() const { return fLastUpload; } | 88 BatchToken lastUploadToken() const { return fLastUpload; } |
79 BatchToken lastUseToken() const { return fLastUse; } | 89 BatchToken lastRefToken() const { return fLastRef; } |
80 void setLastUploadToken(BatchToken batchToken) { | 90 void setLastUploadToken(BatchToken batchToken) { fLastUpload = batchToken; } |
81 SkASSERT(batchToken >= fLastUpload); | 91 void setLastRefToken(BatchToken batchToken) { fLastRef = batchToken; } |
82 fLastUpload = batchToken; | |
83 } | |
84 void setLastUseToken(BatchToken batchToken) { | |
85 SkASSERT(batchToken >= fLastUse); | |
86 fLastUse = batchToken; | |
87 } | |
88 | 92 |
89 void uploadToTexture(GrBatchTarget::TextureUploader uploader) { | 93 void uploadToTexture(GrBatchTarget::TextureUploader uploader) { |
90 // We should only be issuing uploads if we are in fact dirty | 94 // We should only be issuing uploads if we are in fact dirty |
91 SkASSERT(fDirty); | 95 SkASSERT(fDirty); |
92 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), "GrBatchPlot::upload
ToTexture"); | 96 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), "GrBatchPlot::upload
ToTexture"); |
93 SkASSERT(fTexture); | 97 SkASSERT(fTexture); |
94 size_t rowBytes = fBytesPerPixel * fRects->width(); | 98 size_t rowBytes = fBytesPerPixel * fRects->width(); |
95 const unsigned char* dataPtr = fData; | 99 const unsigned char* dataPtr = fData; |
96 dataPtr += rowBytes * fDirtyRect.fTop; | 100 dataPtr += rowBytes * fDirtyRect.fTop; |
97 dataPtr += fBytesPerPixel * fDirtyRect.fLeft; | 101 dataPtr += fBytesPerPixel * fDirtyRect.fLeft; |
(...skipping 18 matching lines...) Expand all Loading... |
116 fDirtyRect.setEmpty(); | 120 fDirtyRect.setEmpty(); |
117 SkDEBUGCODE(fDirty = false;) | 121 SkDEBUGCODE(fDirty = false;) |
118 } | 122 } |
119 | 123 |
120 int x() const { return fX; } | 124 int x() const { return fX; } |
121 int y() const { return fY; } | 125 int y() const { return fY; } |
122 | 126 |
123 private: | 127 private: |
124 BatchPlot() | 128 BatchPlot() |
125 : fLastUpload(0) | 129 : fLastUpload(0) |
126 , fLastUse(0) | 130 , fLastRef(0) |
127 , fIndex(-1) | 131 , fIndex(-1) |
128 , fGenID(-1) | 132 , fGenID(-1) |
129 , fID(0) | 133 , fID(0) |
130 , fData(NULL) | 134 , fData(NULL) |
131 , fWidth(0) | 135 , fWidth(0) |
132 , fHeight(0) | 136 , fHeight(0) |
133 , fX(0) | 137 , fX(0) |
134 , fY(0) | 138 , fY(0) |
135 , fTexture(NULL) | 139 , fTexture(NULL) |
136 , fRects(NULL) | 140 , fRects(NULL) |
(...skipping 29 matching lines...) Expand all Loading... |
166 fDirtyRect.setEmpty(); | 170 fDirtyRect.setEmpty(); |
167 SkDEBUGCODE(fDirty = false;) | 171 SkDEBUGCODE(fDirty = false;) |
168 fTexture = texture; | 172 fTexture = texture; |
169 | 173 |
170 // allocate backing store | 174 // allocate backing store |
171 fData = SkNEW_ARRAY(unsigned char, fBytesPerPixel * width * height); | 175 fData = SkNEW_ARRAY(unsigned char, fBytesPerPixel * width * height); |
172 memset(fData, 0, fBytesPerPixel * width * height); | 176 memset(fData, 0, fBytesPerPixel * width * height); |
173 } | 177 } |
174 | 178 |
175 BatchToken fLastUpload; | 179 BatchToken fLastUpload; |
176 BatchToken fLastUse; | 180 BatchToken fLastRef; |
177 | 181 |
178 uint32_t fIndex; | 182 uint32_t fIndex; |
179 uint32_t fGenID; | 183 uint32_t fGenID; |
180 GrBatchAtlas::AtlasID fID; | 184 GrBatchAtlas::AtlasID fID; |
181 unsigned char* fData; | 185 unsigned char* fData; |
182 int fWidth; | 186 int fWidth; |
183 int fHeight; | 187 int fHeight; |
184 int fX; | 188 int fX; |
185 int fY; | 189 int fY; |
186 GrTexture* fTexture; | 190 GrTexture* fTexture; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
218 | 222 |
219 /////////////////////////////////////////////////////////////////////////////// | 223 /////////////////////////////////////////////////////////////////////////////// |
220 | 224 |
221 GrBatchAtlas::GrBatchAtlas(GrTexture* texture, int numPlotsX, int numPlotsY) | 225 GrBatchAtlas::GrBatchAtlas(GrTexture* texture, int numPlotsX, int numPlotsY) |
222 : fTexture(texture) | 226 : fTexture(texture) |
223 , fNumPlotsX(numPlotsX) | 227 , fNumPlotsX(numPlotsX) |
224 , fNumPlotsY(numPlotsY) | 228 , fNumPlotsY(numPlotsY) |
225 , fPlotWidth(texture->width() / numPlotsX) | 229 , fPlotWidth(texture->width() / numPlotsX) |
226 , fPlotHeight(texture->height() / numPlotsY) | 230 , fPlotHeight(texture->height() / numPlotsY) |
227 , fAtlasGeneration(kInvalidAtlasGeneration + 1) { | 231 , fAtlasGeneration(kInvalidAtlasGeneration + 1) { |
228 SkASSERT(fNumPlotsX * fNumPlotsY <= BulkUseTokenUpdater::kMaxPlots); | |
229 SkASSERT(fPlotWidth * fNumPlotsX == texture->width()); | 232 SkASSERT(fPlotWidth * fNumPlotsX == texture->width()); |
230 SkASSERT(fPlotHeight * fNumPlotsY == texture->height()); | 233 SkASSERT(fPlotHeight * fNumPlotsY == texture->height()); |
231 | 234 |
232 // We currently do not support compressed atlases... | 235 // We currently do not support compressed atlases... |
233 SkASSERT(!GrPixelConfigIsCompressed(texture->desc().fConfig)); | 236 SkASSERT(!GrPixelConfigIsCompressed(texture->desc().fConfig)); |
234 | 237 |
235 // set up allocated plots | 238 // set up allocated plots |
236 fBPP = GrBytesPerPixel(texture->desc().fConfig); | 239 fBPP = GrBytesPerPixel(texture->desc().fConfig); |
237 fPlotArray = SkNEW_ARRAY(SkAutoTUnref<BatchPlot>, (fNumPlotsX * fNumPlotsY))
; | 240 fPlotArray = SkNEW_ARRAY(SkAutoTUnref<BatchPlot>, (fNumPlotsX * fNumPlotsY))
; |
238 | 241 |
239 SkAutoTUnref<BatchPlot>* currPlot = fPlotArray; | 242 SkAutoTUnref<BatchPlot>* currPlot = fPlotArray; |
240 for (int y = fNumPlotsY - 1, r = 0; y >= 0; --y, ++r) { | 243 for (int y = fNumPlotsY - 1, r = 0; y >= 0; --y, ++r) { |
241 for (int x = fNumPlotsX - 1, c = 0; x >= 0; --x, ++c) { | 244 for (int x = fNumPlotsX - 1, c = 0; x >= 0; --x, ++c) { |
242 int id = r * fNumPlotsX + c; | 245 int id = r * fNumPlotsX + c; |
243 currPlot->reset(SkNEW(BatchPlot)); | 246 currPlot->reset(SkNEW(BatchPlot)); |
244 (*currPlot)->init(this, texture, id, 1, x, y, fPlotWidth, fPlotHeigh
t, fBPP); | 247 (*currPlot)->init(this, texture, id, 1, x, y, fPlotWidth, fPlotHeigh
t, fBPP); |
245 | 248 |
246 // build LRU list | 249 // build LRU list |
247 fPlotList.addToHead(currPlot->get()); | 250 fPlotList.addToHead(currPlot->get()); |
248 ++currPlot; | 251 ++currPlot; |
249 } | 252 } |
250 } | 253 } |
251 } | 254 } |
252 | 255 |
253 GrBatchAtlas::~GrBatchAtlas() { | 256 GrBatchAtlas::~GrBatchAtlas() { |
254 SkSafeUnref(fTexture); | 257 SkSafeUnref(fTexture); |
255 SkDELETE_ARRAY(fPlotArray); | 258 SkDELETE_ARRAY(fPlotArray); |
| 259 |
| 260 #if ATLAS_STATS |
| 261 SkDebugf("Num uploads: %d\n", g_UploadCount); |
| 262 #endif |
256 } | 263 } |
257 | 264 |
258 void GrBatchAtlas::processEviction(AtlasID id) { | 265 void GrBatchAtlas::processEviction(AtlasID id) { |
259 for (int i = 0; i < fEvictionCallbacks.count(); i++) { | 266 for (int i = 0; i < fEvictionCallbacks.count(); i++) { |
260 (*fEvictionCallbacks[i].fFunc)(id, fEvictionCallbacks[i].fData); | 267 (*fEvictionCallbacks[i].fFunc)(id, fEvictionCallbacks[i].fData); |
261 } | 268 } |
262 } | 269 } |
263 | 270 |
264 void GrBatchAtlas::makeMRU(BatchPlot* plot) { | 271 void GrBatchAtlas::makeMRU(BatchPlot* plot) { |
265 if (fPlotList.head() == plot) { | 272 if (fPlotList.head() == plot) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
299 return true; | 306 return true; |
300 } | 307 } |
301 plotIter.next(); | 308 plotIter.next(); |
302 } | 309 } |
303 | 310 |
304 // If the above fails, then see if the least recently refed plot has already
been flushed to the | 311 // If the above fails, then see if the least recently refed plot has already
been flushed to the |
305 // gpu | 312 // gpu |
306 plotIter.init(fPlotList, GrBatchPlotList::Iter::kTail_IterStart); | 313 plotIter.init(fPlotList, GrBatchPlotList::Iter::kTail_IterStart); |
307 plot = plotIter.get(); | 314 plot = plotIter.get(); |
308 SkASSERT(plot); | 315 SkASSERT(plot); |
309 if (batchTarget->isIssued(plot->lastUseToken())) { | 316 if (batchTarget->isIssued(plot->lastRefToken())) { |
310 this->processEviction(plot->id()); | 317 this->processEviction(plot->id()); |
311 plot->resetRects(); | 318 plot->resetRects(); |
312 SkDEBUGCODE(bool verify = )plot->addSubImage(width, height, image, loc,
fBPP * width); | 319 SkDEBUGCODE(bool verify = )plot->addSubImage(width, height, image, loc,
fBPP * width); |
313 SkASSERT(verify); | 320 SkASSERT(verify); |
314 this->updatePlot(batchTarget, id, plot); | 321 this->updatePlot(batchTarget, id, plot); |
315 fAtlasGeneration++; | 322 fAtlasGeneration++; |
316 return true; | 323 return true; |
317 } | 324 } |
318 | 325 |
319 // The least recently refed plot hasn't been flushed to the gpu yet, however
, if we have flushed | 326 // The least recently refed plot hasn't been flushed to the gpu yet, however
, if we have flushed |
320 // it to the batch target than we can reuse it. Our last ref token is guara
nteed to be less | 327 // it to the batch target than we can reuse it. Our last ref token is guara
nteed to be less |
321 // than or equal to the current token. If its 'less than' the current token
, than we can spin | 328 // than or equal to the current token. If its 'less than' the current token
, than we can spin |
322 // off the plot(ie let the batch target manage it) and create a new plot in
its place in our | 329 // off the plot(ie let the batch target manage it) and create a new plot in
its place in our |
323 // array. If it is equal to the currentToken, then the caller has to flush
draws to the batch | 330 // array. If it is equal to the currentToken, then the caller has to flush
draws to the batch |
324 // target so we can spin off the plot | 331 // target so we can spin off the plot |
325 if (plot->lastUseToken() == batchTarget->currentToken()) { | 332 if (plot->lastRefToken() == batchTarget->currentToken()) { |
326 return false; | 333 return false; |
327 } | 334 } |
328 | 335 |
329 // We take an extra ref here so our plot isn't deleted when we reset its ind
ex in the array. | 336 // We take an extra ref here so our plot isn't deleted when we reset its ind
ex in the array. |
330 plot->ref(); | 337 plot->ref(); |
331 int index = plot->index(); | 338 int index = plot->index(); |
332 int x = plot->x(); | 339 int x = plot->x(); |
333 int y = plot->y(); | 340 int y = plot->y(); |
334 int generation = plot->genID(); | 341 int generation = plot->genID(); |
335 | 342 |
336 this->processEviction(plot->id()); | 343 this->processEviction(plot->id()); |
337 fPlotList.remove(plot); | 344 fPlotList.remove(plot); |
338 SkAutoTUnref<BatchPlot>& newPlot = fPlotArray[plot->index()]; | 345 SkAutoTUnref<BatchPlot>& newPlot = fPlotArray[plot->index()]; |
339 newPlot.reset(SkNEW(BatchPlot)); | 346 newPlot.reset(SkNEW(BatchPlot)); |
340 newPlot->init(this, fTexture, index, ++generation, x, y, fPlotWidth, fPlotHe
ight, fBPP); | 347 newPlot->init(this, fTexture, index, ++generation, x, y, fPlotWidth, fPlotHe
ight, fBPP); |
341 | 348 |
342 fPlotList.addToHead(newPlot.get()); | 349 fPlotList.addToHead(newPlot.get()); |
343 SkDEBUGCODE(bool verify = )newPlot->addSubImage(width, height, image, loc, f
BPP * width); | 350 SkDEBUGCODE(bool verify = )newPlot->addSubImage(width, height, image, loc, f
BPP * width); |
344 SkASSERT(verify); | 351 SkASSERT(verify); |
345 newPlot->setLastUploadToken(batchTarget->currentToken()); | 352 newPlot->setLastUploadToken(batchTarget->currentToken()); |
346 SkAutoTUnref<GrPlotUploader> uploader(SkNEW_ARGS(GrPlotUploader, (newPlot)))
; | 353 SkAutoTUnref<GrPlotUploader> uploader(SkNEW_ARGS(GrPlotUploader, (newPlot)))
; |
347 batchTarget->upload(uploader); | 354 batchTarget->upload(uploader); |
348 *id = newPlot->id(); | 355 *id = newPlot->id(); |
349 plot->unref(); | 356 plot->unref(); |
350 fAtlasGeneration++; | 357 fAtlasGeneration++; |
351 return true; | 358 return true; |
352 } | 359 } |
353 | 360 |
354 bool GrBatchAtlas::hasID(AtlasID id) { | 361 bool GrBatchAtlas::hasID(AtlasID id) { |
355 int index = GetIndexFromID(id); | 362 int index = this->getIndexFromID(id); |
356 SkASSERT(index < fNumPlotsX * fNumPlotsY); | 363 SkASSERT(index < fNumPlotsX * fNumPlotsY); |
357 return fPlotArray[index]->genID() == GetGenerationFromID(id); | 364 return fPlotArray[index]->genID() == this->getGenerationFromID(id); |
358 } | 365 } |
359 | 366 |
360 void GrBatchAtlas::setLastUseToken(AtlasID id, BatchToken batchToken) { | 367 void GrBatchAtlas::setLastRefToken(AtlasID id, BatchToken batchToken) { |
361 SkASSERT(this->hasID(id)); | 368 SkASSERT(this->hasID(id)); |
362 int index = GetIndexFromID(id); | 369 int index = this->getIndexFromID(id); |
363 SkASSERT(index < fNumPlotsX * fNumPlotsY); | |
364 this->makeMRU(fPlotArray[index]); | 370 this->makeMRU(fPlotArray[index]); |
365 fPlotArray[index]->setLastUseToken(batchToken); | 371 fPlotArray[index]->setLastRefToken(batchToken); |
366 } | 372 } |
367 | |
368 void GrBatchAtlas::setLastUseTokenBulk(const BulkUseTokenUpdater& updater, Batch
Token batchToken) { | |
369 int plotsToUpdateCount = updater.fPlotsToUpdate.count(); | |
370 for (int i = 0; i < plotsToUpdateCount; i++) { | |
371 BatchPlot* plot = fPlotArray[updater.fPlotsToUpdate[i]]; | |
372 this->makeMRU(plot); | |
373 plot->setLastUseToken(batchToken); | |
374 } | |
375 } | |
OLD | NEW |