Index: src/gpu/SkGpuDevice.cpp |
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp |
index f2bd025a0f6e5d9bc29777213420914d2549a783..693e16c0e320d13ad9889320f947c7b9f11ed8bf 100644 |
--- a/src/gpu/SkGpuDevice.cpp |
+++ b/src/gpu/SkGpuDevice.cpp |
@@ -1876,49 +1876,20 @@ static void wrap_texture(GrTexture* texture, int width, int height, SkBitmap* re |
result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref(); |
} |
-bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture* picture, |
- const SkMatrix* matrix, const SkPaint* paint) { |
- // todo: should handle these natively |
- if (matrix || paint) { |
- return false; |
- } |
- |
- fContext->getLayerCache()->processDeletedPictures(); |
- |
- SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey(); |
- |
- const SkPicture::AccelData* data = picture->EXPERIMENTAL_getAccelData(key); |
- if (NULL == data) { |
- return false; |
- } |
- |
- const GrAccelData *gpuData = static_cast<const GrAccelData*>(data); |
- |
- if (0 == gpuData->numSaveLayers()) { |
- return false; |
- } |
- |
- SkAutoTArray<bool> pullForward(gpuData->numSaveLayers()); |
- for (int i = 0; i < gpuData->numSaveLayers(); ++i) { |
- pullForward[i] = false; |
- } |
- |
- SkRect clipBounds; |
- if (!mainCanvas->getClipBounds(&clipBounds)) { |
- return true; |
- } |
- SkIRect query; |
- clipBounds.roundOut(&query); |
- |
- SkAutoTDelete<const SkPicture::OperationList> ops(picture->EXPERIMENTAL_getActiveOps(query)); |
- |
- // This code pre-renders the entire layer since it will be cached and potentially |
+// Return true if any layers are suitable for hoisting |
+bool SkGpuDevice::FindLayersToHoist(const GrAccelData *gpuData, |
+ const SkPicture::OperationList* ops, |
+ const SkIRect& query, |
+ bool* pullForward) { |
+ bool anyHoisted = false; |
+ |
+ // Layer hoisting pre-renders the entire layer since it will be cached and potentially |
// reused with different clips (e.g., in different tiles). Because of this the |
// clip will not be limiting the size of the pre-rendered layer. kSaveLayerMaxSize |
// is used to limit which clips are pre-rendered. |
static const int kSaveLayerMaxSize = 256; |
- if (NULL != ops.get()) { |
+ if (NULL != ops) { |
// In this case the picture has been generated with a BBH so we use |
// the BBH to limit the pre-rendering to just the layers needed to cover |
// the region being drawn |
@@ -1928,7 +1899,7 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture |
// For now we're saving all the layers in the GrAccelData so they |
// can be nested. Additionally, the nested layers appear before |
// their parent in the list. |
- for (int j = 0 ; j < gpuData->numSaveLayers(); ++j) { |
+ for (int j = 0; j < gpuData->numSaveLayers(); ++j) { |
const GrAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(j); |
if (pullForward[j]) { |
@@ -1949,6 +1920,7 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture |
} |
pullForward[j] = true; |
+ anyHoisted = true; |
} |
} |
} else { |
@@ -1976,9 +1948,53 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture |
} |
pullForward[j] = true; |
+ anyHoisted = true; |
} |
} |
+ return anyHoisted; |
+} |
+ |
+bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture* picture, |
+ const SkMatrix* matrix, const SkPaint* paint) { |
+ // todo: should handle these natively |
+ if (matrix || paint) { |
+ return false; |
+ } |
+ |
+ fContext->getLayerCache()->processDeletedPictures(); |
+ |
+ SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey(); |
+ |
+ const SkPicture::AccelData* data = picture->EXPERIMENTAL_getAccelData(key); |
+ if (NULL == data) { |
+ return false; |
+ } |
+ |
+ const GrAccelData *gpuData = static_cast<const GrAccelData*>(data); |
+ |
+ if (0 == gpuData->numSaveLayers()) { |
+ return false; |
+ } |
+ |
+ SkAutoTArray<bool> pullForward(gpuData->numSaveLayers()); |
+ for (int i = 0; i < gpuData->numSaveLayers(); ++i) { |
+ pullForward[i] = false; |
+ } |
+ |
+ SkRect clipBounds; |
+ if (!mainCanvas->getClipBounds(&clipBounds)) { |
+ return true; |
+ } |
+ SkIRect query; |
+ clipBounds.roundOut(&query); |
+ |
+ SkAutoTDelete<const SkPicture::OperationList> ops(picture->EXPERIMENTAL_getActiveOps(query)); |
+ |
+ if (!FindLayersToHoist(gpuData, ops.get(), query, pullForward.get())) { |
+ return false; |
+ } |
+ |
SkPictureReplacementPlayback::PlaybackReplacements replacements; |
SkTDArray<GrCachedLayer*> atlased, nonAtlased; |
@@ -2037,13 +2053,28 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture |
} |
} |
+ this->drawLayers(picture, atlased, nonAtlased); |
+ |
+ // Render the entire picture using new layers |
+ SkPictureReplacementPlayback playback(picture, &replacements, ops.get()); |
+ |
+ playback.draw(mainCanvas, NULL); |
+ |
+ this->unlockLayers(picture); |
+ |
+ return true; |
+} |
+ |
+void SkGpuDevice::drawLayers(const SkPicture* picture, |
+ const SkTDArray<GrCachedLayer*>& atlased, |
+ const SkTDArray<GrCachedLayer*>& nonAtlased) { |
// Render the atlased layers that require it |
if (atlased.count() > 0) { |
// All the atlased layers are rendered into the same GrTexture |
SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect( |
- atlased[0]->texture()->asRenderTarget(), |
- SkSurface::kStandard_TextRenderMode, |
- SkSurface::kDontClear_RenderTargetFlag)); |
+ atlased[0]->texture()->asRenderTarget(), |
+ SkSurface::kStandard_TextRenderMode, |
+ SkSurface::kDontClear_RenderTargetFlag)); |
SkCanvas* atlasCanvas = surface->getCanvas(); |
@@ -2091,9 +2122,9 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture |
// Each non-atlased layer has its own GrTexture |
SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect( |
- layer->texture()->asRenderTarget(), |
- SkSurface::kStandard_TextRenderMode, |
- SkSurface::kDontClear_RenderTargetFlag)); |
+ layer->texture()->asRenderTarget(), |
+ SkSurface::kStandard_TextRenderMode, |
+ SkSurface::kDontClear_RenderTargetFlag)); |
SkCanvas* layerCanvas = surface->getCanvas(); |
@@ -2117,17 +2148,22 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture |
layerCanvas->flush(); |
} |
+} |
- // Render the entire picture using new layers |
- SkPictureReplacementPlayback playback(picture, &replacements, ops.get()); |
+void SkGpuDevice::unlockLayers(const SkPicture* picture) { |
+ SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey(); |
- playback.draw(mainCanvas, NULL); |
+ const SkPicture::AccelData* data = picture->EXPERIMENTAL_getAccelData(key); |
+ SkASSERT(NULL != data); |
+ |
+ const GrAccelData *gpuData = static_cast<const GrAccelData*>(data); |
+ SkASSERT(0 != gpuData->numSaveLayers()); |
// unlock the layers |
for (int i = 0; i < gpuData->numSaveLayers(); ++i) { |
const GrAccelData::SaveLayerInfo& info = gpuData->saveLayerInfo(i); |
- GrCachedLayer* layer = fContext->getLayerCache()->findLayer(picture->uniqueID(), |
+ GrCachedLayer* layer = fContext->getLayerCache()->findLayer(picture->uniqueID(), |
info.fSaveLayerOpID, |
info.fRestoreOpID, |
info.fCTM); |
@@ -2142,8 +2178,6 @@ bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture |
fContext->getLayerCache()->purgeAll(); |
#endif |
- |
- return true; |
} |
SkImageFilter::Cache* SkGpuDevice::getImageFilterCache() { |