Index: src/gpu/GrAtlas.cpp |
diff --git a/src/gpu/GrAtlas.cpp b/src/gpu/GrAtlas.cpp |
index 008bae2f00eaf3812bb7121d6f52941338cd86fb..6809a087e794923c2fde4bc80b38cf8eeda08be9 100644 |
--- a/src/gpu/GrAtlas.cpp |
+++ b/src/gpu/GrAtlas.cpp |
@@ -29,6 +29,8 @@ GrPlot::GrPlot() : fDrawToken(NULL, 0) |
} |
GrPlot::~GrPlot() { |
+ SkDELETE_ARRAY(fPlotData); |
+ fPlotData = NULL; |
delete fRects; |
} |
@@ -37,6 +39,9 @@ void GrPlot::init(GrAtlasMgr* mgr, int offX, int offY, int width, int height, si |
fAtlasMgr = mgr; |
fOffset.set(offX * width, offY * height); |
fBytesPerPixel = bpp; |
+ fPlotData = NULL; |
+ fDirtyRect.setEmpty(); |
+ fDirty = false; |
} |
static inline void adjust_for_offset(GrIPoint16* loc, const GrIPoint16& offset) { |
@@ -46,20 +51,45 @@ 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); |
+ // create backing memory on first use |
robertphillips
2014/05/12 19:45:52
// Once the plot is nearly full we will revert to
jvanverth1
2014/05/12 20:44:04
Done.
|
+ int plotWidth = fRects->width(); |
+ int plotHeight = fRects->height(); |
+ if (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) { |
robertphillips
2014/05/12 19:45:52
const unsigned char* ?
jvanverth1
2014/05/12 20:44:04
Done.
|
+ unsigned char* imagePtr = (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 +98,33 @@ bool GrPlot::addSubImage(int width, int height, const void* image, |
return true; |
} |
+void GrPlot::uploadToTexture() { |
+ if (fDirty && 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(); |
robertphillips
2014/05/12 19:45:52
const unsigned char* ?
jvanverth1
2014/05/12 20:44:04
Done.
|
+ 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(); |
+ // 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 upload any new images directly. |
robertphillips
2014/05/12 19:45:52
static const int kNearlyFullTolerance = 0.85f; ?
jvanverth1
2014/05/12 20:44:04
Done.
|
+ if (fRects->percentFull() > 0.85f) { |
+ SkDELETE_ARRAY(fPlotData); |
+ fPlotData = NULL; |
+ } |
+ } |
robertphillips
2014/05/12 19:45:52
It seems like if we're going to clear fDirty out h
jvanverth1
2014/05/12 20:44:04
Cleaned up. We shouldn't hit the 'if' block unless
|
+ fDirty = false; |
+} |
+ |
void GrPlot::resetRects() { |
SkASSERT(NULL != fRects); |
fRects->reset(); |
@@ -85,11 +142,14 @@ GrAtlasMgr::GrAtlasMgr(GrGpu* gpu, GrPixelConfig config, |
fNumPlotsY = numPlotsY; |
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); |
@@ -201,3 +261,13 @@ GrPlot* GrAtlasMgr::getUnusedPlot() { |
return NULL; |
} |
+ |
+void GrAtlasMgr::uploadPlotsToTexture() { |
+ GrPlotList::Iter plotIter; |
+ plotIter.init(fPlotList, GrPlotList::Iter::kHead_IterStart); |
+ GrPlot* plot; |
+ while (NULL != (plot = plotIter.get())) { |
+ plot->uploadToTexture(); |
+ plotIter.next(); |
+ } |
+} |