| 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 #include "GrVertexBuffer.h" | 13 #include "GrVertexBuffer.h" |
| 14 | 14 |
| 15 static inline void adjust_for_offset(SkIPoint16* loc, const SkIPoint16& offset)
{ | 15 static inline void adjust_for_offset(SkIPoint16* loc, const SkIPoint16& offset)
{ |
| 16 loc->fX += offset.fX; | 16 loc->fX += offset.fX; |
| 17 loc->fY += offset.fY; | 17 loc->fY += offset.fY; |
| 18 } | 18 } |
| 19 | 19 |
| 20 static GrBatchAtlas::AtlasID create_id(int index, int generation) { | 20 static GrBatchAtlas::AtlasID create_id(uint32_t index, uint64_t generation) { |
| 21 // Generation ID can roll over because we only check for equality | |
| 22 SkASSERT(index < (1 << 16)); | 21 SkASSERT(index < (1 << 16)); |
| 22 SkASSERT(generation < ((uint64_t)1 << 48)); |
| 23 return generation << 16 | index; | 23 return generation << 16 | index; |
| 24 } | 24 } |
| 25 | 25 |
| 26 // The backing GrTexture for a GrBatchAtlas is broken into a spatial grid of GrB
atchPlots. | 26 // The backing GrTexture for a GrBatchAtlas is broken into a spatial grid of GrB
atchPlots. |
| 27 // The GrBatchPlots keep track of subimage placement via their GrRectanizer. In
turn, a GrBatchPlot | 27 // The GrBatchPlots keep track of subimage placement via their GrRectanizer. In
turn, a GrBatchPlot |
| 28 // manages the lifetime of its data using two tokens, a last ref toke and a last
upload token. | 28 // manages the lifetime of its data using two tokens, a last ref toke and a last
upload token. |
| 29 // Once a GrBatchPlot is "full" (i.e. there is no room for the new subimage acco
rding to the | 29 // Once a GrBatchPlot is "full" (i.e. there is no room for the new subimage acco
rding to the |
| 30 // GrRectanizer), it can no longer be used unless the last ref on the GrPlot has
already been | 30 // GrRectanizer), it can no longer be used unless the last ref on the GrPlot has
already been |
| 31 // flushed through to the gpu. | 31 // flushed through to the gpu. |
| 32 | 32 |
| 33 class BatchPlot : public SkRefCnt { | 33 class BatchPlot : public SkRefCnt { |
| 34 public: | 34 public: |
| 35 typedef GrBatchAtlas::BatchToken BatchToken; | 35 typedef GrBatchAtlas::BatchToken BatchToken; |
| 36 | 36 |
| 37 SK_DECLARE_INTERNAL_LLIST_INTERFACE(BatchPlot); | 37 SK_DECLARE_INTERNAL_LLIST_INTERFACE(BatchPlot); |
| 38 | 38 |
| 39 // index() refers to the index of the plot in the owning GrAtlas's plot arra
y. genID() is a | 39 // index() refers to the index of the plot in the owning GrAtlas's plot arra
y. genID() is a |
| 40 // monotonically incrementing number which is bumped every time the cpu back
ing store is | 40 // monotonically incrementing number which is bumped every time the cpu back
ing store is |
| 41 // wiped, or when the plot itself is evicted from the atlas(ie, there is con
tinuity in genID() | 41 // wiped, or when the plot itself is evicted from the atlas(ie, there is con
tinuity in genID() |
| 42 // across atlas spills) | 42 // across atlas spills) |
| 43 int index() const { return fIndex; } | 43 uint32_t index() const { return fIndex; } |
| 44 int genID() const { return fGenID; } | 44 uint64_t genID() const { return fGenID; } |
| 45 GrBatchAtlas::AtlasID id() { return fID; } | 45 GrBatchAtlas::AtlasID id() { return fID; } |
| 46 | 46 |
| 47 GrTexture* texture() const { return fTexture; } | 47 GrTexture* texture() const { return fTexture; } |
| 48 | 48 |
| 49 bool addSubImage(int width, int height, const void* image, SkIPoint16* loc,
size_t rowBytes) { | 49 bool addSubImage(int width, int height, const void* image, SkIPoint16* loc,
size_t rowBytes) { |
| 50 if (!fRects->addRect(width, height, loc)) { | 50 if (!fRects->addRect(width, height, loc)) { |
| 51 return false; | 51 return false; |
| 52 } | 52 } |
| 53 | 53 |
| 54 if (!fData) { | 54 if (!fData) { |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 114 | 114 |
| 115 // zero out the plot | 115 // zero out the plot |
| 116 if (fData) { | 116 if (fData) { |
| 117 sk_bzero(fData, fBytesPerPixel * fWidth * fHeight); | 117 sk_bzero(fData, fBytesPerPixel * fWidth * fHeight); |
| 118 } | 118 } |
| 119 | 119 |
| 120 fDirtyRect.setEmpty(); | 120 fDirtyRect.setEmpty(); |
| 121 SkDEBUGCODE(fDirty = false;) | 121 SkDEBUGCODE(fDirty = false;) |
| 122 } | 122 } |
| 123 | 123 |
| 124 int x() const { return fX; } | 124 uint32_t x() const { return fX; } |
| 125 int y() const { return fY; } | 125 uint32_t y() const { return fY; } |
| 126 | 126 |
| 127 private: | 127 private: |
| 128 BatchPlot() | 128 BatchPlot() |
| 129 : fLastUpload(0) | 129 : fLastUpload(0) |
| 130 , fLastUse(0) | 130 , fLastUse(0) |
| 131 , fIndex(-1) | 131 , fIndex(-1) |
| 132 , fGenID(-1) | 132 , fGenID(-1) |
| 133 , fID(0) | 133 , fID(0) |
| 134 , fData(NULL) | 134 , fData(NULL) |
| 135 , fWidth(0) | 135 , fWidth(0) |
| (...skipping 10 matching lines...) Expand all Loading... |
| 146 { | 146 { |
| 147 fOffset.set(0, 0); | 147 fOffset.set(0, 0); |
| 148 } | 148 } |
| 149 | 149 |
| 150 ~BatchPlot() { | 150 ~BatchPlot() { |
| 151 sk_free(fData); | 151 sk_free(fData); |
| 152 fData = NULL; | 152 fData = NULL; |
| 153 delete fRects; | 153 delete fRects; |
| 154 } | 154 } |
| 155 | 155 |
| 156 void init(GrBatchAtlas* atlas, GrTexture* texture, int index, uint32_t gener
ation, | 156 void init(GrBatchAtlas* atlas, GrTexture* texture, int index, uint64_t gener
ation, |
| 157 int offX, int offY, int width, int height, size_t bpp) { | 157 int offX, int offY, int width, int height, size_t bpp) { |
| 158 fIndex = index; | 158 fIndex = index; |
| 159 fGenID = generation; | 159 fGenID = generation; |
| 160 fID = create_id(index, generation); | 160 fID = create_id(index, generation); |
| 161 fWidth = width; | 161 fWidth = width; |
| 162 fHeight = height; | 162 fHeight = height; |
| 163 fX = offX; | 163 fX = offX; |
| 164 fY = offY; | 164 fY = offY; |
| 165 fRects = GrRectanizer::Factory(width, height); | 165 fRects = GrRectanizer::Factory(width, height); |
| 166 fAtlas = atlas; | 166 fAtlas = atlas; |
| 167 fOffset.set(offX * width, offY * height); | 167 fOffset.set(offX * width, offY * height); |
| 168 fBytesPerPixel = bpp; | 168 fBytesPerPixel = bpp; |
| 169 fData = NULL; | 169 fData = NULL; |
| 170 fDirtyRect.setEmpty(); | 170 fDirtyRect.setEmpty(); |
| 171 SkDEBUGCODE(fDirty = false;) | 171 SkDEBUGCODE(fDirty = false;) |
| 172 fTexture = texture; | 172 fTexture = texture; |
| 173 } | 173 } |
| 174 | 174 |
| 175 BatchToken fLastUpload; | 175 BatchToken fLastUpload; |
| 176 BatchToken fLastUse; | 176 BatchToken fLastUse; |
| 177 | 177 |
| 178 uint32_t fIndex; | 178 uint32_t fIndex; |
| 179 uint32_t fGenID; | 179 uint64_t fGenID; |
| 180 GrBatchAtlas::AtlasID fID; | 180 GrBatchAtlas::AtlasID fID; |
| 181 unsigned char* fData; | 181 unsigned char* fData; |
| 182 int fWidth; | 182 uint32_t fWidth; |
| 183 int fHeight; | 183 uint32_t fHeight; |
| 184 int fX; | 184 uint32_t fX; |
| 185 int fY; | 185 uint32_t fY; |
| 186 GrTexture* fTexture; | 186 GrTexture* fTexture; |
| 187 GrRectanizer* fRects; | 187 GrRectanizer* fRects; |
| 188 GrBatchAtlas* fAtlas; | 188 GrBatchAtlas* fAtlas; |
| 189 SkIPoint16 fOffset; // the offset of the plot in the backing texture | 189 SkIPoint16 fOffset; // the offset of the plot in the backing texture |
| 190 size_t fBytesPerPixel; | 190 size_t fBytesPerPixel; |
| 191 SkIRect fDirtyRect; | 191 SkIRect fDirtyRect; |
| 192 SkDEBUGCODE(bool fDirty;) | 192 SkDEBUGCODE(bool fDirty;) |
| 193 | 193 |
| 194 friend class GrBatchAtlas; | 194 friend class GrBatchAtlas; |
| 195 | 195 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 219 /////////////////////////////////////////////////////////////////////////////// | 219 /////////////////////////////////////////////////////////////////////////////// |
| 220 | 220 |
| 221 GrBatchAtlas::GrBatchAtlas(GrTexture* texture, int numPlotsX, int numPlotsY) | 221 GrBatchAtlas::GrBatchAtlas(GrTexture* texture, int numPlotsX, int numPlotsY) |
| 222 : fTexture(texture) | 222 : fTexture(texture) |
| 223 , fNumPlotsX(numPlotsX) | 223 , fNumPlotsX(numPlotsX) |
| 224 , fNumPlotsY(numPlotsY) | 224 , fNumPlotsY(numPlotsY) |
| 225 , fPlotWidth(texture->width() / numPlotsX) | 225 , fPlotWidth(texture->width() / numPlotsX) |
| 226 , fPlotHeight(texture->height() / numPlotsY) | 226 , fPlotHeight(texture->height() / numPlotsY) |
| 227 , fAtlasGeneration(kInvalidAtlasGeneration + 1) { | 227 , fAtlasGeneration(kInvalidAtlasGeneration + 1) { |
| 228 SkASSERT(fNumPlotsX * fNumPlotsY <= BulkUseTokenUpdater::kMaxPlots); | 228 SkASSERT(fNumPlotsX * fNumPlotsY <= BulkUseTokenUpdater::kMaxPlots); |
| 229 SkASSERT(fPlotWidth * fNumPlotsX == texture->width()); | 229 SkASSERT(fPlotWidth * fNumPlotsX == static_cast<uint32_t>(texture->width()))
; |
| 230 SkASSERT(fPlotHeight * fNumPlotsY == texture->height()); | 230 SkASSERT(fPlotHeight * fNumPlotsY == static_cast<uint32_t>(texture->height()
)); |
| 231 | 231 |
| 232 // We currently do not support compressed atlases... | 232 // We currently do not support compressed atlases... |
| 233 SkASSERT(!GrPixelConfigIsCompressed(texture->desc().fConfig)); | 233 SkASSERT(!GrPixelConfigIsCompressed(texture->desc().fConfig)); |
| 234 | 234 |
| 235 // set up allocated plots | 235 // set up allocated plots |
| 236 fBPP = GrBytesPerPixel(texture->desc().fConfig); | 236 fBPP = GrBytesPerPixel(texture->desc().fConfig); |
| 237 fPlotArray = SkNEW_ARRAY(SkAutoTUnref<BatchPlot>, (fNumPlotsX * fNumPlotsY))
; | 237 fPlotArray = SkNEW_ARRAY(SkAutoTUnref<BatchPlot>, (fNumPlotsX * fNumPlotsY))
; |
| 238 | 238 |
| 239 SkAutoTUnref<BatchPlot>* currPlot = fPlotArray; | 239 SkAutoTUnref<BatchPlot>* currPlot = fPlotArray; |
| 240 for (int y = fNumPlotsY - 1, r = 0; y >= 0; --y, ++r) { | 240 for (int y = fNumPlotsY - 1, r = 0; y >= 0; --y, ++r) { |
| 241 for (int x = fNumPlotsX - 1, c = 0; x >= 0; --x, ++c) { | 241 for (int x = fNumPlotsX - 1, c = 0; x >= 0; --x, ++c) { |
| 242 int id = r * fNumPlotsX + c; | 242 uint32_t id = r * fNumPlotsX + c; |
| 243 currPlot->reset(SkNEW(BatchPlot)); | 243 currPlot->reset(SkNEW(BatchPlot)); |
| 244 (*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); |
| 245 | 245 |
| 246 // build LRU list | 246 // build LRU list |
| 247 fPlotList.addToHead(currPlot->get()); | 247 fPlotList.addToHead(currPlot->get()); |
| 248 ++currPlot; | 248 ++currPlot; |
| 249 } | 249 } |
| 250 } | 250 } |
| 251 } | 251 } |
| 252 | 252 |
| (...skipping 27 matching lines...) Expand all Loading... |
| 280 plot->setLastUploadToken(batchTarget->asapToken()); | 280 plot->setLastUploadToken(batchTarget->asapToken()); |
| 281 SkAutoTUnref<GrPlotUploader> uploader(SkNEW_ARGS(GrPlotUploader, (plot))
); | 281 SkAutoTUnref<GrPlotUploader> uploader(SkNEW_ARGS(GrPlotUploader, (plot))
); |
| 282 batchTarget->upload(uploader); | 282 batchTarget->upload(uploader); |
| 283 } | 283 } |
| 284 *id = plot->id(); | 284 *id = plot->id(); |
| 285 } | 285 } |
| 286 | 286 |
| 287 bool GrBatchAtlas::addToAtlas(AtlasID* id, GrBatchTarget* batchTarget, | 287 bool GrBatchAtlas::addToAtlas(AtlasID* id, GrBatchTarget* batchTarget, |
| 288 int width, int height, const void* image, SkIPoint
16* loc) { | 288 int width, int height, const void* image, SkIPoint
16* loc) { |
| 289 // We should already have a texture, TODO clean this up | 289 // We should already have a texture, TODO clean this up |
| 290 SkASSERT(fTexture && width <= fPlotWidth && height <= fPlotHeight); | 290 SkASSERT(fTexture && |
| 291 static_cast<uint32_t>(width) <= fPlotWidth && |
| 292 static_cast<uint32_t>(height) <= fPlotHeight); |
| 291 | 293 |
| 292 // now look through all allocated plots for one we can share, in Most Recent
ly Refed order | 294 // now look through all allocated plots for one we can share, in Most Recent
ly Refed order |
| 293 GrBatchPlotList::Iter plotIter; | 295 GrBatchPlotList::Iter plotIter; |
| 294 plotIter.init(fPlotList, GrBatchPlotList::Iter::kHead_IterStart); | 296 plotIter.init(fPlotList, GrBatchPlotList::Iter::kHead_IterStart); |
| 295 BatchPlot* plot; | 297 BatchPlot* plot; |
| 296 while ((plot = plotIter.get())) { | 298 while ((plot = plotIter.get())) { |
| 297 if (plot->addSubImage(width, height, image, loc, fBPP * width)) { | 299 if (plot->addSubImage(width, height, image, loc, fBPP * width)) { |
| 298 this->updatePlot(batchTarget, id, plot); | 300 this->updatePlot(batchTarget, id, plot); |
| 299 return true; | 301 return true; |
| 300 } | 302 } |
| (...skipping 23 matching lines...) Expand all Loading... |
| 324 // target so we can spin off the plot | 326 // target so we can spin off the plot |
| 325 if (plot->lastUseToken() == batchTarget->currentToken()) { | 327 if (plot->lastUseToken() == batchTarget->currentToken()) { |
| 326 return false; | 328 return false; |
| 327 } | 329 } |
| 328 | 330 |
| 329 // We take an extra ref here so our plot isn't deleted when we reset its ind
ex in the array. | 331 // We take an extra ref here so our plot isn't deleted when we reset its ind
ex in the array. |
| 330 plot->ref(); | 332 plot->ref(); |
| 331 int index = plot->index(); | 333 int index = plot->index(); |
| 332 int x = plot->x(); | 334 int x = plot->x(); |
| 333 int y = plot->y(); | 335 int y = plot->y(); |
| 334 int generation = plot->genID(); | 336 uint64_t generation = plot->genID(); |
| 335 | 337 |
| 336 this->processEviction(plot->id()); | 338 this->processEviction(plot->id()); |
| 337 fPlotList.remove(plot); | 339 fPlotList.remove(plot); |
| 338 SkAutoTUnref<BatchPlot>& newPlot = fPlotArray[plot->index()]; | 340 SkAutoTUnref<BatchPlot>& newPlot = fPlotArray[plot->index()]; |
| 339 newPlot.reset(SkNEW(BatchPlot)); | 341 newPlot.reset(SkNEW(BatchPlot)); |
| 340 newPlot->init(this, fTexture, index, ++generation, x, y, fPlotWidth, fPlotHe
ight, fBPP); | 342 newPlot->init(this, fTexture, index, ++generation, x, y, fPlotWidth, fPlotHe
ight, fBPP); |
| 341 | 343 |
| 342 fPlotList.addToHead(newPlot.get()); | 344 fPlotList.addToHead(newPlot.get()); |
| 343 SkDEBUGCODE(bool verify = )newPlot->addSubImage(width, height, image, loc, f
BPP * width); | 345 SkDEBUGCODE(bool verify = )newPlot->addSubImage(width, height, image, loc, f
BPP * width); |
| 344 SkASSERT(verify); | 346 SkASSERT(verify); |
| 345 newPlot->setLastUploadToken(batchTarget->currentToken()); | 347 newPlot->setLastUploadToken(batchTarget->currentToken()); |
| 346 SkAutoTUnref<GrPlotUploader> uploader(SkNEW_ARGS(GrPlotUploader, (newPlot)))
; | 348 SkAutoTUnref<GrPlotUploader> uploader(SkNEW_ARGS(GrPlotUploader, (newPlot)))
; |
| 347 batchTarget->upload(uploader); | 349 batchTarget->upload(uploader); |
| 348 *id = newPlot->id(); | 350 *id = newPlot->id(); |
| 349 plot->unref(); | 351 plot->unref(); |
| 350 fAtlasGeneration++; | 352 fAtlasGeneration++; |
| 351 return true; | 353 return true; |
| 352 } | 354 } |
| 353 | 355 |
| 354 bool GrBatchAtlas::hasID(AtlasID id) { | 356 bool GrBatchAtlas::hasID(AtlasID id) { |
| 355 int index = GetIndexFromID(id); | 357 uint32_t index = GetIndexFromID(id); |
| 356 SkASSERT(index < fNumPlotsX * fNumPlotsY); | 358 SkASSERT(index < fNumPlotsX * fNumPlotsY); |
| 357 return fPlotArray[index]->genID() == GetGenerationFromID(id); | 359 return fPlotArray[index]->genID() == GetGenerationFromID(id); |
| 358 } | 360 } |
| 359 | 361 |
| 360 void GrBatchAtlas::setLastUseToken(AtlasID id, BatchToken batchToken) { | 362 void GrBatchAtlas::setLastUseToken(AtlasID id, BatchToken batchToken) { |
| 361 SkASSERT(this->hasID(id)); | 363 SkASSERT(this->hasID(id)); |
| 362 int index = GetIndexFromID(id); | 364 uint32_t index = GetIndexFromID(id); |
| 363 SkASSERT(index < fNumPlotsX * fNumPlotsY); | 365 SkASSERT(index < fNumPlotsX * fNumPlotsY); |
| 364 this->makeMRU(fPlotArray[index]); | 366 this->makeMRU(fPlotArray[index]); |
| 365 fPlotArray[index]->setLastUseToken(batchToken); | 367 fPlotArray[index]->setLastUseToken(batchToken); |
| 366 } | 368 } |
| 367 | 369 |
| 368 void GrBatchAtlas::setLastUseTokenBulk(const BulkUseTokenUpdater& updater, Batch
Token batchToken) { | 370 void GrBatchAtlas::setLastUseTokenBulk(const BulkUseTokenUpdater& updater, Batch
Token batchToken) { |
| 369 int count = updater.fPlotsToUpdate.count(); | 371 int count = updater.fPlotsToUpdate.count(); |
| 370 for (int i = 0; i < count; i++) { | 372 for (int i = 0; i < count; i++) { |
| 371 BatchPlot* plot = fPlotArray[updater.fPlotsToUpdate[i]]; | 373 BatchPlot* plot = fPlotArray[updater.fPlotsToUpdate[i]]; |
| 372 this->makeMRU(plot); | 374 this->makeMRU(plot); |
| 373 plot->setLastUseToken(batchToken); | 375 plot->setLastUseToken(batchToken); |
| 374 } | 376 } |
| 375 } | 377 } |
| OLD | NEW |