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