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 { |