Index: src/gpu/GrLayerHoister.cpp |
diff --git a/src/gpu/GrLayerHoister.cpp b/src/gpu/GrLayerHoister.cpp |
index 3ae0e2d45fcbc311f4aa8f546406c80c3aedb421..272f0446b8c65dbe7145e8ff2f1185db7949e474 100644 |
--- a/src/gpu/GrLayerHoister.cpp |
+++ b/src/gpu/GrLayerHoister.cpp |
@@ -20,9 +20,9 @@ static void prepare_for_hoisting(GrLayerCache* layerCache, |
const SkPicture* topLevelPicture, |
const GrAccelData::SaveLayerInfo& info, |
const SkIRect& layerRect, |
- SkTDArray<GrHoistedLayer>* atlased, |
- SkTDArray<GrHoistedLayer>* nonAtlased, |
- SkTDArray<GrHoistedLayer>* recycled) { |
+ SkTDArray<GrHoistedLayer>* needRendering, |
+ SkTDArray<GrHoistedLayer>* recycled, |
+ bool attemptToAtlas) { |
const SkPicture* pict = info.fPicture ? info.fPicture : topLevelPicture; |
SkMatrix combined = SkMatrix::Concat(info.fPreMat, info.fLocalMat); |
@@ -40,24 +40,28 @@ static void prepare_for_hoisting(GrLayerCache* layerCache, |
desc.fConfig = kSkia8888_GrPixelConfig; |
// TODO: need to deal with sample count |
- |
- bool disallowAtlasing = info.fHasNestedLayers || info.fIsNested || |
- (layer->paint() && layer->paint()->getImageFilter()); |
- |
- bool needsRendering = layerCache->lock(layer, desc, disallowAtlasing); |
- if (NULL == layer->texture()) { |
+ bool locked, needsRendering; |
+ if (attemptToAtlas) { |
+ locked = layerCache->tryToAtlas(layer, desc, &needsRendering); |
+ } else { |
+ locked = layerCache->lock(layer, desc, &needsRendering); |
+ } |
+ if (!locked) { |
// GPU resources could not be secured for the hoisting of this layer |
return; |
} |
+ if (attemptToAtlas) { |
+ SkASSERT(layer->isAtlased()); |
+ } |
+ |
GrHoistedLayer* hl; |
if (needsRendering) { |
- if (layer->isAtlased()) { |
- hl = atlased->append(); |
- } else { |
- hl = nonAtlased->append(); |
+ if (!attemptToAtlas) { |
+ SkASSERT(!layer->isAtlased()); |
} |
+ hl = needRendering->append(); |
} else { |
hl = recycled->append(); |
} |
@@ -70,12 +74,13 @@ static void prepare_for_hoisting(GrLayerCache* layerCache, |
hl->fPreMat = info.fPreMat; |
} |
-// Return true if any layers are suitable for hoisting |
-bool GrLayerHoister::FindLayersToHoist(GrContext* context, |
+// Atlased layers must be small enough to fit in the atlas, not have a |
+// paint with an image filter and be neither nested nor nesting. |
+// TODO: allow leaf nested layers to appear in the atlas. |
+void GrLayerHoister::FindLayersToAtlas(GrContext* context, |
const SkPicture* topLevelPicture, |
const SkRect& query, |
SkTDArray<GrHoistedLayer>* atlased, |
- SkTDArray<GrHoistedLayer>* nonAtlased, |
SkTDArray<GrHoistedLayer>* recycled) { |
GrLayerCache* layerCache = context->getLayerCache(); |
@@ -85,31 +90,27 @@ bool GrLayerHoister::FindLayersToHoist(GrContext* context, |
const SkPicture::AccelData* topLevelData = topLevelPicture->EXPERIMENTAL_getAccelData(key); |
if (!topLevelData) { |
- return false; |
+ return; |
} |
const GrAccelData *topLevelGPUData = static_cast<const GrAccelData*>(topLevelData); |
if (0 == topLevelGPUData->numSaveLayers()) { |
- return false; |
+ return; |
} |
- bool anyHoisted = false; |
- |
- // The layer hoisting code will pre-render and cache an entire layer if most |
- // of it is being used (~70%) and it will fit in a texture. This is to allow |
- // such layers to be re-used for different clips/tiles. |
- // Small layers will additionally be atlased. |
- // The only limitation right now is that nested layers are currently not hoisted. |
- // Parent layers are hoisted but are never atlased (so that we never swap |
- // away from the atlas rendertarget when generating the hoisted layers). |
- |
atlased->setReserve(atlased->count() + topLevelGPUData->numSaveLayers()); |
- // Find and prepare for hoisting all the layers that intersect the query rect |
for (int i = 0; i < topLevelGPUData->numSaveLayers(); ++i) { |
- |
const GrAccelData::SaveLayerInfo& info = topLevelGPUData->saveLayerInfo(i); |
+ // TODO: ignore perspective projected layers here? |
+ bool disallowAtlasing = info.fHasNestedLayers || info.fIsNested || |
+ (info.fPaint && info.fPaint->getImageFilter()); |
+ |
+ if (disallowAtlasing) { |
+ continue; |
+ } |
+ |
SkRect layerRect = SkRect::Make(info.fBounds); |
if (!layerRect.intersect(query)) { |
continue; |
@@ -118,18 +119,55 @@ bool GrLayerHoister::FindLayersToHoist(GrContext* context, |
SkIRect ir; |
layerRect.roundOut(&ir); |
- // TODO: ignore perspective projected layers here! |
- // TODO: once this code is more stable unsuitable layers can |
- // just be omitted during the optimization stage |
- if (info.fIsNested) { |
+ if (!GrLayerCache::PlausiblyAtlasable(ir.width(), ir.height())) { |
continue; |
} |
- prepare_for_hoisting(layerCache, topLevelPicture, info, ir, atlased, nonAtlased, recycled); |
- anyHoisted = true; |
+ prepare_for_hoisting(layerCache, topLevelPicture, info, ir, atlased, recycled, true); |
+ } |
+ |
+} |
+ |
+void GrLayerHoister::FindLayersToHoist(GrContext* context, |
+ const SkPicture* topLevelPicture, |
+ const SkRect& query, |
+ SkTDArray<GrHoistedLayer>* needRendering, |
+ SkTDArray<GrHoistedLayer>* recycled) { |
+ GrLayerCache* layerCache = context->getLayerCache(); |
+ |
+ layerCache->processDeletedPictures(); |
+ |
+ SkPicture::AccelData::Key key = GrAccelData::ComputeAccelDataKey(); |
+ |
+ const SkPicture::AccelData* topLevelData = topLevelPicture->EXPERIMENTAL_getAccelData(key); |
+ if (!topLevelData) { |
+ return; |
+ } |
+ |
+ const GrAccelData *topLevelGPUData = static_cast<const GrAccelData*>(topLevelData); |
+ if (0 == topLevelGPUData->numSaveLayers()) { |
+ return; |
} |
- return anyHoisted; |
+ // Find and prepare for hoisting all the layers that intersect the query rect |
+ for (int i = 0; i < topLevelGPUData->numSaveLayers(); ++i) { |
+ const GrAccelData::SaveLayerInfo& info = topLevelGPUData->saveLayerInfo(i); |
+ if (info.fIsNested) { |
+ // Parent layers are currently hoisted while nested layers are not. |
+ continue; |
+ } |
+ |
+ SkRect layerRect = SkRect::Make(info.fBounds); |
+ if (!layerRect.intersect(query)) { |
+ continue; |
+ } |
+ |
+ SkIRect ir; |
+ layerRect.roundOut(&ir); |
+ |
+ prepare_for_hoisting(layerCache, topLevelPicture, info, ir, |
+ needRendering, recycled, false); |
+ } |
} |
static void wrap_texture(GrTexture* texture, int width, int height, SkBitmap* result) { |
@@ -138,8 +176,8 @@ static void wrap_texture(GrTexture* texture, int width, int height, SkBitmap* re |
result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref(); |
} |
-static void convert_layers_to_replacements(const SkTDArray<GrHoistedLayer>& layers, |
- GrReplacements* replacements) { |
+void GrLayerHoister::ConvertLayersToReplacements(const SkTDArray<GrHoistedLayer>& layers, |
+ GrReplacements* replacements) { |
// TODO: just replace GrReplacements::ReplacementInfo with GrCachedLayer? |
for (int i = 0; i < layers.count(); ++i) { |
GrCachedLayer* layer = layers[i].fLayer; |
@@ -174,12 +212,8 @@ static void convert_layers_to_replacements(const SkTDArray<GrHoistedLayer>& laye |
} |
} |
-void GrLayerHoister::DrawLayers(GrContext* context, |
- const SkTDArray<GrHoistedLayer>& atlased, |
- const SkTDArray<GrHoistedLayer>& nonAtlased, |
- const SkTDArray<GrHoistedLayer>& recycled, |
- GrReplacements* replacements) { |
- // Render the atlased layers that require it |
+void GrLayerHoister::DrawLayersToAtlas(GrContext* context, |
+ const SkTDArray<GrHoistedLayer>& atlased) { |
if (atlased.count() > 0) { |
// All the atlased layers are rendered into the same GrTexture |
SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect( |
@@ -210,38 +244,34 @@ void GrLayerHoister::DrawLayers(GrContext* context, |
atlasCanvas->clipRect(bound); |
// Since 'clear' doesn't respect the clip we need to draw a rect |
- // TODO: ensure none of the atlased layers contain a clear call! |
atlasCanvas->drawRect(bound, clearPaint); |
- // info.fCTM maps the layer's top/left to the origin. |
+ // '-offset' maps the layer's top/left to the origin. |
// Since this layer is atlased, the top/left corner needs |
// to be offset to the correct location in the backing texture. |
SkMatrix initialCTM; |
- initialCTM.setTranslate(SkIntToScalar(-offset.fX), |
- SkIntToScalar(-offset.fY)); |
- initialCTM.postTranslate(bound.fLeft, bound.fTop); |
- initialCTM.postConcat(atlased[i].fPreMat); |
- |
- atlasCanvas->translate(SkIntToScalar(-offset.fX), |
- SkIntToScalar(-offset.fY)); |
- atlasCanvas->translate(bound.fLeft, bound.fTop); |
- atlasCanvas->concat(atlased[i].fPreMat); |
+ initialCTM.setTranslate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset.fY)); |
+ initialCTM.preTranslate(bound.fLeft, bound.fTop); |
+ initialCTM.preConcat(atlased[i].fPreMat); |
+ |
+ atlasCanvas->setMatrix(initialCTM); |
atlasCanvas->concat(atlased[i].fLocalMat); |
SkRecordPartialDraw(*pict->fRecord.get(), atlasCanvas, bound, |
- layer->start()+1, layer->stop(), initialCTM); |
+ layer->start() + 1, layer->stop(), initialCTM); |
atlasCanvas->restore(); |
} |
atlasCanvas->flush(); |
} |
+} |
- // Render the non-atlased layers that require it |
- for (int i = 0; i < nonAtlased.count(); ++i) { |
- GrCachedLayer* layer = nonAtlased[i].fLayer; |
- const SkPicture* pict = nonAtlased[i].fPicture; |
- const SkIPoint& offset = nonAtlased[i].fOffset; |
+void GrLayerHoister::DrawLayers(GrContext* context, const SkTDArray<GrHoistedLayer>& layers) { |
+ for (int i = 0; i < layers.count(); ++i) { |
+ GrCachedLayer* layer = layers[i].fLayer; |
+ const SkPicture* pict = layers[i].fPicture; |
+ const SkIPoint& offset = layers[i].fOffset; |
// Each non-atlased layer has its own GrTexture |
SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect( |
@@ -252,51 +282,36 @@ void GrLayerHoister::DrawLayers(GrContext* context, |
SkASSERT(0 == layer->rect().fLeft && 0 == layer->rect().fTop); |
// Add a rect clip to make sure the rendering doesn't |
- // extend beyond the boundaries of the atlased sub-rect |
+ // extend beyond the boundaries of the layer |
SkRect bound = SkRect::MakeXYWH(SkIntToScalar(layer->rect().fLeft), |
SkIntToScalar(layer->rect().fTop), |
SkIntToScalar(layer->rect().width()), |
SkIntToScalar(layer->rect().height())); |
- layerCanvas->clipRect(bound); // TODO: still useful? |
+ layerCanvas->clipRect(bound); |
layerCanvas->clear(SK_ColorTRANSPARENT); |
SkMatrix initialCTM; |
initialCTM.setTranslate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset.fY)); |
- initialCTM.postConcat(nonAtlased[i].fPreMat); |
+ initialCTM.preConcat(layers[i].fPreMat); |
- layerCanvas->translate(SkIntToScalar(-offset.fX), SkIntToScalar(-offset.fY)); |
- layerCanvas->concat(nonAtlased[i].fPreMat); |
- layerCanvas->concat(nonAtlased[i].fLocalMat); |
+ layerCanvas->setMatrix(initialCTM); |
+ layerCanvas->concat(layers[i].fLocalMat); |
SkRecordPartialDraw(*pict->fRecord.get(), layerCanvas, bound, |
layer->start()+1, layer->stop(), initialCTM); |
layerCanvas->flush(); |
} |
- |
- convert_layers_to_replacements(atlased, replacements); |
- convert_layers_to_replacements(nonAtlased, replacements); |
- convert_layers_to_replacements(recycled, replacements); |
} |
void GrLayerHoister::UnlockLayers(GrContext* context, |
- const SkTDArray<GrHoistedLayer>& atlased, |
- const SkTDArray<GrHoistedLayer>& nonAtlased, |
- const SkTDArray<GrHoistedLayer>& recycled) { |
+ const SkTDArray<GrHoistedLayer>& layers) { |
GrLayerCache* layerCache = context->getLayerCache(); |
- for (int i = 0; i < atlased.count(); ++i) { |
- layerCache->removeUse(atlased[i].fLayer); |
- } |
- |
- for (int i = 0; i < nonAtlased.count(); ++i) { |
- layerCache->removeUse(nonAtlased[i].fLayer); |
- } |
- |
- for (int i = 0; i < recycled.count(); ++i) { |
- layerCache->removeUse(recycled[i].fLayer); |
+ for (int i = 0; i < layers.count(); ++i) { |
+ layerCache->removeUse(layers[i].fLayer); |
} |
#if DISABLE_CACHING |