Index: src/core/SkMultiPictureDraw.cpp |
diff --git a/src/core/SkMultiPictureDraw.cpp b/src/core/SkMultiPictureDraw.cpp |
index 19b26ca60775e1b03d89cfd34952a936254525d2..5fe3c0ea5210aa0a5969e7afb97143991bd7a37d 100644 |
--- a/src/core/SkMultiPictureDraw.cpp |
+++ b/src/core/SkMultiPictureDraw.cpp |
@@ -63,7 +63,10 @@ void SkMultiPictureDraw::draw() { |
#ifndef SK_IGNORE_GPU_LAYER_HOISTING |
GrContext* context = NULL; |
- SkTDArray<GrHoistedLayer> atlased, nonAtlased, recycled; |
+ // Start by collecting all the layers that are going to be atlased and render |
+ // them (if necessary). Hoisting the free floating layers is deferred until |
+ // drawing the canvas that requires them. |
+ SkTDArray<GrHoistedLayer> atlasedNeedRendering, atlasedRecycled; |
for (int i = 0; i < fDrawData.count(); ++i) { |
if (fDrawData[i].canvas->getGrContext() && |
@@ -80,28 +83,57 @@ void SkMultiPictureDraw::draw() { |
continue; |
} |
- GrLayerHoister::FindLayersToHoist(context, fDrawData[i].picture, |
- clipBounds, &atlased, &nonAtlased, &recycled); |
+ // TODO: sorting the cacheable layers from smallest to largest |
+ // would improve the packing and reduce the number of swaps |
+ // TODO: another optimization would be to make a first pass to |
+ // lock any required layer that is already in the atlas |
+ GrLayerHoister::FindLayersToAtlas(context, fDrawData[i].picture, |
+ clipBounds, |
+ &atlasedNeedRendering, &atlasedRecycled); |
} |
} |
- GrReplacements replacements; |
- |
if (NULL != context) { |
- GrLayerHoister::DrawLayers(atlased, nonAtlased, recycled, &replacements); |
+ GrLayerHoister::DrawLayersToAtlas(context, atlasedNeedRendering); |
} |
+ |
+ SkTDArray<GrHoistedLayer> needRendering, recycled; |
#endif |
for (int i = 0; i < fDrawData.count(); ++i) { |
#ifndef SK_IGNORE_GPU_LAYER_HOISTING |
if (fDrawData[i].canvas->getGrContext() && |
!fDrawData[i].paint && fDrawData[i].matrix.isIdentity()) { |
- // Render the entire picture using new layers |
+ |
+ SkRect clipBounds; |
+ if (!fDrawData[i].canvas->getClipBounds(&clipBounds)) { |
+ continue; |
+ } |
+ |
+ // Find the layers required by this canvas. It will return atlased |
+ // layers in the 'recycled' list since they have already been drawn. |
+ GrLayerHoister::FindLayersToHoist(context, fDrawData[i].picture, |
+ clipBounds, &needRendering, &recycled); |
+ |
+ GrLayerHoister::DrawLayers(context, needRendering); |
+ |
+ GrReplacements replacements; |
+ |
+ GrLayerHoister::ConvertLayersToReplacements(needRendering, &replacements); |
+ GrLayerHoister::ConvertLayersToReplacements(recycled, &replacements); |
+ |
const SkMatrix initialMatrix = fDrawData[i].canvas->getTotalMatrix(); |
+ // Render the entire picture using new layers |
GrRecordReplaceDraw(fDrawData[i].picture, fDrawData[i].canvas, |
&replacements, initialMatrix, NULL); |
- } else |
+ |
+ GrLayerHoister::UnlockLayers(context, needRendering); |
+ GrLayerHoister::UnlockLayers(context, recycled); |
+ |
+ needRendering.rewind(); |
+ recycled.rewind(); |
+ } else |
#endif |
{ |
fDrawData[i].canvas->drawPicture(fDrawData[i].picture, |
@@ -112,7 +144,8 @@ void SkMultiPictureDraw::draw() { |
#ifndef SK_IGNORE_GPU_LAYER_HOISTING |
if (NULL != context) { |
- GrLayerHoister::UnlockLayers(context, atlased, nonAtlased, recycled); |
+ GrLayerHoister::UnlockLayers(context, atlasedNeedRendering); |
+ GrLayerHoister::UnlockLayers(context, atlasedRecycled); |
} |
#endif |