Index: src/gpu/GrAtlas.cpp |
diff --git a/src/gpu/GrAtlas.cpp b/src/gpu/GrAtlas.cpp |
index 008bae2f00eaf3812bb7121d6f52941338cd86fb..c4e1a3b61849070b713c9dfcaa0551a537e0487f 100644 |
--- a/src/gpu/GrAtlas.cpp |
+++ b/src/gpu/GrAtlas.cpp |
@@ -24,19 +24,28 @@ GrPlot::GrPlot() : fDrawToken(NULL, 0) |
, fRects(NULL) |
, fAtlasMgr(NULL) |
, fBytesPerPixel(1) |
+ , fDirty(false) |
+ , fBatchUploads(false) |
{ |
fOffset.set(0, 0); |
} |
GrPlot::~GrPlot() { |
+ SkDELETE_ARRAY(fPlotData); |
+ fPlotData = NULL; |
delete fRects; |
} |
-void GrPlot::init(GrAtlasMgr* mgr, int offX, int offY, int width, int height, size_t bpp) { |
+void GrPlot::init(GrAtlasMgr* mgr, int offX, int offY, int width, int height, size_t bpp, |
+ bool batchUploads) { |
fRects = GrRectanizer::Factory(width, height); |
fAtlasMgr = mgr; |
fOffset.set(offX * width, offY * height); |
fBytesPerPixel = bpp; |
+ fPlotData = NULL; |
+ fDirtyRect.setEmpty(); |
+ fDirty = false; |
+ fBatchUploads = batchUploads; |
} |
static inline void adjust_for_offset(GrIPoint16* loc, const GrIPoint16& offset) { |
@@ -46,20 +55,46 @@ static inline void adjust_for_offset(GrIPoint16* loc, const GrIPoint16& offset) |
bool GrPlot::addSubImage(int width, int height, const void* image, |
GrIPoint16* loc) { |
+ float percentFull = fRects->percentFull(); |
if (!fRects->addRect(width, height, loc)) { |
return false; |
} |
- SkAutoSMalloc<1024> storage; |
- adjust_for_offset(loc, fOffset); |
- GrContext* context = fTexture->getContext(); |
- // We pass the flag that does not force a flush. We assume our caller is |
- // smart and hasn't referenced the part of the texture we're about to update |
- // since the last flush. |
- context->writeTexturePixels(fTexture, |
- loc->fX, loc->fY, width, height, |
- fTexture->config(), image, 0, |
- GrContext::kDontFlush_PixelOpsFlag); |
+ // if batching uploads, create backing memory on first use |
+ // once the plot is nearly full we will revert to uploading each subimage individually |
+ int plotWidth = fRects->width(); |
+ int plotHeight = fRects->height(); |
+ if (fBatchUploads && NULL == fPlotData && 0.0f == percentFull) { |
+ fPlotData = SkNEW_ARRAY(unsigned char, fBytesPerPixel*plotWidth*plotHeight); |
+ memset(fPlotData, 0, fBytesPerPixel*plotWidth*plotHeight); |
+ } |
+ |
+ // if we have backing memory, copy to the memory and set for future upload |
+ if (NULL != fPlotData) { |
+ const unsigned char* imagePtr = (const unsigned char*) image; |
+ // point ourselves at the right starting spot |
+ unsigned char* dataPtr = fPlotData; |
+ dataPtr += fBytesPerPixel*plotWidth*loc->fY; |
+ dataPtr += fBytesPerPixel*loc->fX; |
+ // copy into the data buffer |
+ for (int i = 0; i < height; ++i) { |
+ memcpy(dataPtr, imagePtr, fBytesPerPixel*width); |
+ dataPtr += fBytesPerPixel*plotWidth; |
+ imagePtr += fBytesPerPixel*width; |
+ } |
+ |
+ fDirtyRect.join(loc->fX, loc->fY, loc->fX + width, loc->fY + height); |
+ adjust_for_offset(loc, fOffset); |
+ fDirty = true; |
+ // otherwise, just upload the image directly |
+ } else { |
+ adjust_for_offset(loc, fOffset); |
+ GrContext* context = fTexture->getContext(); |
+ context->writeTexturePixels(fTexture, |
+ loc->fX, loc->fY, width, height, |
+ fTexture->config(), image, 0, |
+ GrContext::kDontFlush_PixelOpsFlag); |
+ } |
#if FONT_CACHE_STATS |
++g_UploadCount; |
@@ -68,6 +103,39 @@ bool GrPlot::addSubImage(int width, int height, const void* image, |
return true; |
} |
+void GrPlot::uploadToTexture() { |
+ static const float kNearlyFullTolerance = 0.85f; |
+ |
+ // should only do this if batching is enabled |
+ SkASSERT(fBatchUploads); |
+ |
+ if (fDirty) { |
+ SkASSERT(NULL != fTexture); |
+ GrContext* context = fTexture->getContext(); |
+ // We pass the flag that does not force a flush. We assume our caller is |
+ // smart and hasn't referenced the part of the texture we're about to update |
+ // since the last flush. |
+ int rowBytes = fBytesPerPixel*fRects->width(); |
+ const unsigned char* dataPtr = fPlotData; |
+ dataPtr += rowBytes*fDirtyRect.fTop; |
+ dataPtr += fBytesPerPixel*fDirtyRect.fLeft; |
+ context->writeTexturePixels(fTexture, |
+ fOffset.fX + fDirtyRect.fLeft, fOffset.fY + fDirtyRect.fTop, |
+ fDirtyRect.width(), fDirtyRect.height(), |
+ fTexture->config(), dataPtr, |
+ rowBytes, |
+ GrContext::kDontFlush_PixelOpsFlag); |
+ fDirtyRect.setEmpty(); |
+ fDirty = false; |
+ // If the Plot is nearly full, anything else we add will probably be small and one |
+ // at a time, so free up the memory and after this upload any new images directly. |
+ if (fRects->percentFull() > kNearlyFullTolerance) { |
+ SkDELETE_ARRAY(fPlotData); |
+ fPlotData = NULL; |
+ } |
+ } |
+} |
+ |
void GrPlot::resetRects() { |
SkASSERT(NULL != fRects); |
fRects->reset(); |
@@ -77,19 +145,23 @@ void GrPlot::resetRects() { |
GrAtlasMgr::GrAtlasMgr(GrGpu* gpu, GrPixelConfig config, |
const SkISize& backingTextureSize, |
- int numPlotsX, int numPlotsY) { |
+ int numPlotsX, int numPlotsY, bool batchUploads) { |
fGpu = SkRef(gpu); |
fPixelConfig = config; |
fBackingTextureSize = backingTextureSize; |
fNumPlotsX = numPlotsX; |
fNumPlotsY = numPlotsY; |
+ fBatchUploads = batchUploads; |
fTexture = NULL; |
- int plotWidth = fBackingTextureSize.width() / fNumPlotsX; |
- int plotHeight = fBackingTextureSize.height() / fNumPlotsY; |
+ int textureWidth = fBackingTextureSize.width(); |
+ int textureHeight = fBackingTextureSize.height(); |
- SkASSERT(plotWidth * fNumPlotsX == fBackingTextureSize.width()); |
- SkASSERT(plotHeight * fNumPlotsY == fBackingTextureSize.height()); |
+ int plotWidth = textureWidth / fNumPlotsX; |
+ int plotHeight = textureHeight / fNumPlotsY; |
+ |
+ SkASSERT(plotWidth * fNumPlotsX == textureWidth); |
+ SkASSERT(plotHeight * fNumPlotsY == textureHeight); |
// set up allocated plots |
size_t bpp = GrBytesPerPixel(fPixelConfig); |
@@ -98,7 +170,7 @@ GrAtlasMgr::GrAtlasMgr(GrGpu* gpu, GrPixelConfig config, |
GrPlot* currPlot = fPlotArray; |
for (int y = numPlotsY-1; y >= 0; --y) { |
for (int x = numPlotsX-1; x >= 0; --x) { |
- currPlot->init(this, x, y, plotWidth, plotHeight, bpp); |
+ currPlot->init(this, x, y, plotWidth, plotHeight, bpp, batchUploads); |
// build LRU list |
fPlotList.addToHead(currPlot); |
@@ -201,3 +273,15 @@ GrPlot* GrAtlasMgr::getUnusedPlot() { |
return NULL; |
} |
+ |
+void GrAtlasMgr::uploadPlotsToTexture() { |
+ if (fBatchUploads) { |
+ GrPlotList::Iter plotIter; |
+ plotIter.init(fPlotList, GrPlotList::Iter::kHead_IterStart); |
+ GrPlot* plot; |
+ while (NULL != (plot = plotIter.get())) { |
+ plot->uploadToTexture(); |
+ plotIter.next(); |
+ } |
+ } |
+} |