Chromium Code Reviews| Index: src/gpu/GrAtlas.cpp |
| diff --git a/src/gpu/GrAtlas.cpp b/src/gpu/GrAtlas.cpp |
| index 646c213b8675a738aa190daeece4ebc2088f49ab..775bd1285a626e0c702681f11827135e5205fb5d 100644 |
| --- a/src/gpu/GrAtlas.cpp |
| +++ b/src/gpu/GrAtlas.cpp |
| @@ -46,6 +46,7 @@ static int g_UploadCount = 0; |
| #endif |
| GrPlot::GrPlot() : fDrawToken(NULL, 0) |
| + , fPrev(NULL) |
| , fNext(NULL) |
| , fTexture(NULL) |
| , fAtlasMgr(NULL) |
| @@ -94,6 +95,11 @@ bool GrPlot::addSubImage(int width, int height, const void* image, |
| return true; |
| } |
| +void GrPlot::resetRects() { |
| + SkASSERT(NULL != fRects); |
| + fRects->reset(); |
| +} |
| + |
| /////////////////////////////////////////////////////////////////////////////// |
| GrAtlasMgr::GrAtlasMgr(GrGpu* gpu, GrPixelConfig config) { |
| @@ -105,7 +111,9 @@ GrAtlasMgr::GrAtlasMgr(GrGpu* gpu, GrPixelConfig config) { |
| // set up allocated plots |
| size_t bpp = GrBytesPerPixel(fPixelConfig); |
| fPlots = SkNEW_ARRAY(GrPlot, (GR_PLOT_WIDTH*GR_PLOT_HEIGHT)); |
| - fFreePlots = NULL; |
| + fHead = NULL; |
| + fTail = NULL; |
| + |
| GrPlot* currPlot = fPlots; |
| for (int y = GR_PLOT_HEIGHT-1; y >= 0; --y) { |
| for (int x = GR_PLOT_WIDTH-1; x >= 0; --x) { |
| @@ -113,10 +121,16 @@ GrAtlasMgr::GrAtlasMgr(GrGpu* gpu, GrPixelConfig config) { |
| currPlot->fOffset.set(x, y); |
| currPlot->fBytesPerPixel = bpp; |
| - // add to free list |
| - currPlot->fNext = fFreePlots; |
| - fFreePlots = currPlot; |
| - |
| + // build LRU list |
| + if (fHead == NULL) { |
| + currPlot->fPrev = NULL; |
| + currPlot->fNext = NULL; |
| + fHead = fTail = currPlot; |
| + } else { |
| + currPlot->fNext = fHead; |
| + fHead->fPrev = currPlot; |
| + fHead = currPlot; |
| + } |
| ++currPlot; |
| } |
| } |
| @@ -132,25 +146,42 @@ GrAtlasMgr::~GrAtlasMgr() { |
| #endif |
| } |
| +void GrAtlasMgr::moveToHead(GrPlot* plot) { |
| + if (NULL == plot || NULL == plot->fPrev) { |
|
bsalomon
2014/02/28 16:28:53
I wonder if we should be using SkTInternalLList
jvanverth1
2014/02/28 19:55:27
Done.
|
| + SkASSERT(plot == fHead); |
| + return; |
| + } |
| + |
| + if (plot == fTail) { |
| + fTail = plot->fPrev; |
| + } else { |
| + plot->fNext->fPrev = plot->fPrev; |
| + } |
| + |
| + plot->fPrev->fNext = plot->fNext; |
| + plot->fNext = fHead; |
| + fHead->fPrev = plot; |
| + fHead = plot; |
| + plot->fPrev = NULL; |
| + SkASSERT(plot == fHead); |
| + SkASSERT(plot->fPrev == NULL); |
| + SkASSERT(plot->fNext->fPrev == plot); |
| +} |
| + |
| GrPlot* GrAtlasMgr::addToAtlas(GrAtlas* atlas, |
| int width, int height, const void* image, |
| GrIPoint16* loc) { |
| - // iterate through entire plot list, see if we can find a hole |
| - GrPlot* plotIter = atlas->fPlots; |
| - while (plotIter) { |
| - if (plotIter->addSubImage(width, height, image, loc)) { |
| - return plotIter; |
| + // iterate through entire plot list for this atlas, see if we can find a hole |
| + // last one was most recently added and probably most empty |
| + for (int i = atlas->fPlots.count()-1; i >= 0; --i) { |
| + GrPlot* plot = atlas->fPlots[i]; |
| + if (plot->addSubImage(width, height, image, loc)) { |
| + moveToHead(plot); |
|
bsalomon
2014/02/28 16:28:53
this->
jvanverth1
2014/02/28 19:55:27
Done.
|
| + return plot; |
| } |
| - plotIter = plotIter->fNext; |
| - } |
| - |
| - // If the above fails, then either we have no starting plot, or the current |
| - // plot list is full. Either way we need to allocate a new plot |
| - GrPlot* newPlot = this->allocPlot(); |
| - if (NULL == newPlot) { |
| - return NULL; |
| } |
| + // before we get a new plot, make sure we have a backing texture |
| if (NULL == fTexture) { |
| // TODO: Update this to use the cache rather than directly creating a texture. |
| GrTextureDesc desc; |
| @@ -164,77 +195,49 @@ GrPlot* GrAtlasMgr::addToAtlas(GrAtlas* atlas, |
| return NULL; |
| } |
| } |
| - // be sure to set texture for fast lookup |
| - newPlot->fTexture = fTexture; |
| - if (!newPlot->addSubImage(width, height, image, loc)) { |
| - this->freePlot(newPlot); |
| - return NULL; |
| + // now look through all allocated plots for one we can share, in MRU order |
| + GrPlot* plotIter = fHead; |
| + while (plotIter) { |
| + // make sure texture is set for quick lookup |
| + plotIter->fTexture = fTexture; |
| + if (plotIter->addSubImage(width, height, image, loc)) { |
| + moveToHead(plotIter); |
| + // new plot for atlas, put at end of array |
| + *(atlas->fPlots.append()) = plotIter; |
| + return plotIter; |
| + } |
| + plotIter = plotIter->fNext; |
| } |
| - // new plot, put at head |
| - newPlot->fNext = atlas->fPlots; |
| - atlas->fPlots = newPlot; |
| - |
| - return newPlot; |
| + // If the above fails, then the current plot list has no room |
| + return NULL; |
| } |
| -bool GrAtlasMgr::removeUnusedPlots(GrAtlas* atlas) { |
| - |
| - // GrPlot** is used so that the head element can be easily |
| - // modified when the first element is deleted |
| - GrPlot** plotRef = &atlas->fPlots; |
| - GrPlot* plot = atlas->fPlots; |
| - bool removed = false; |
| - while (NULL != plot) { |
| - if (plot->drawToken().isIssued()) { |
| - *plotRef = plot->fNext; |
| - this->freePlot(plot); |
| - plot = *plotRef; |
| - removed = true; |
| - } else { |
| - plotRef = &plot->fNext; |
| - plot = plot->fNext; |
| +bool GrAtlasMgr::removePlot(GrAtlas* atlas, const GrPlot* plot) { |
| + // iterate through plot list for this atlas |
| + int count = atlas->fPlots.count(); |
| + for (int i = 0; i < count; ++i) { |
| + if (plot == atlas->fPlots[i]) { |
| + atlas->fPlots.remove(i); |
| + return true; |
| } |
| } |
| - return removed; |
| -} |
| - |
| -void GrAtlasMgr::deletePlotList(GrPlot* plot) { |
| - while (NULL != plot) { |
| - GrPlot* next = plot->fNext; |
| - this->freePlot(plot); |
| - plot = next; |
| - } |
| + return false; |
| } |
| -GrPlot* GrAtlasMgr::allocPlot() { |
| - if (NULL == fFreePlots) { |
| - return NULL; |
| - } else { |
| - GrPlot* alloc = fFreePlots; |
| - fFreePlots = alloc->fNext; |
| -#ifdef SK_DEBUG |
| -// GrPrintf(" GrPlot %p [%d %d] %d\n", this, alloc->fOffset.fX, alloc->fOffset.fY, gCounter); |
| - gCounter += 1; |
| -#endif |
| - return alloc; |
| +// get a plot that only contains drawn content |
| +GrPlot* GrAtlasMgr::getUnusedPlot() { |
| + GrPlot* plotIter = fTail; |
| + while (plotIter) { |
| + if (plotIter->drawToken().isIssued()) { |
| + return plotIter; |
| + } |
| + plotIter = plotIter->fPrev; |
| } |
| -} |
| - |
| -void GrAtlasMgr::freePlot(GrPlot* plot) { |
| - SkASSERT(this == plot->fAtlasMgr); |
| - |
| - plot->fRects->reset(); |
| - plot->fNext = fFreePlots; |
| - fFreePlots = plot; |
| - |
| -#ifdef SK_DEBUG |
| - --gCounter; |
| -// GrPrintf("~GrPlot %p [%d %d] %d\n", this, plot->fOffset.fX, plot->fOffset.fY, gCounter); |
| -#endif |
| + return NULL; |
| } |
| SkISize GrAtlas::getSize() const { |