| 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
|
|
|