diff options
Diffstat (limited to 'src/gpu/GrLayerHoister.cpp')
-rw-r--r-- | src/gpu/GrLayerHoister.cpp | 114 |
1 files changed, 83 insertions, 31 deletions
diff --git a/src/gpu/GrLayerHoister.cpp b/src/gpu/GrLayerHoister.cpp index c63fb5476c..0a86e419b6 100644 --- a/src/gpu/GrLayerHoister.cpp +++ b/src/gpu/GrLayerHoister.cpp @@ -23,7 +23,8 @@ static void prepare_for_hoisting(GrLayerCache* layerCache, const SkPicture* topLevelPicture, const SkMatrix& initialMat, const SkLayerInfo::BlockInfo& info, - const SkIRect& layerRect, + const SkIRect& srcIR, + const SkIRect& dstIR, SkTDArray<GrHoistedLayer>* needRendering, SkTDArray<GrHoistedLayer>* recycled, bool attemptToAtlas, @@ -33,15 +34,16 @@ static void prepare_for_hoisting(GrLayerCache* layerCache, GrCachedLayer* layer = layerCache->findLayerOrCreate(topLevelPicture->uniqueID(), SkToInt(info.fSaveLayerOpID), SkToInt(info.fRestoreOpID), - layerRect, + srcIR, + dstIR, initialMat, info.fKey, info.fKeySize, info.fPaint); GrSurfaceDesc desc; desc.fFlags = kRenderTarget_GrSurfaceFlag; - desc.fWidth = layerRect.width(); - desc.fHeight = layerRect.height(); + desc.fWidth = srcIR.width(); + desc.fHeight = srcIR.height(); desc.fConfig = kSkia8888_GrPixelConfig; desc.fSampleCnt = numSamples; @@ -80,6 +82,40 @@ static void prepare_for_hoisting(GrLayerCache* layerCache, hl->fPreMat.preConcat(info.fPreMat); } +// Compute the source rect if possible and return false if further processing +// on the layer should be abandoned based on its source rect. +static bool compute_source_rect(const SkLayerInfo::BlockInfo& info, const SkMatrix& initialMat, + const SkIRect& dstIR, SkIRect* srcIR) { + SkIRect clipBounds = dstIR; + + SkMatrix totMat = initialMat; + totMat.preConcat(info.fPreMat); + totMat.preConcat(info.fLocalMat); + + if (info.fPaint && info.fPaint->getImageFilter()) { + info.fPaint->getImageFilter()->filterBounds(clipBounds, totMat, &clipBounds); + } + + if (!info.fSrcBounds.isEmpty()) { + SkRect r; + + totMat.mapRect(&r, info.fSrcBounds); + r.roundOut(srcIR); + + if (!srcIR->intersect(clipBounds)) { + return false; + } + } else { + *srcIR = clipBounds; + } + + if (!GrLayerCache::PlausiblyAtlasable(srcIR->width(), srcIR->height())) { + return false; + } + + return true; +} + // 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. @@ -130,14 +166,16 @@ void GrLayerHoister::FindLayersToAtlas(GrContext* context, continue; } - const SkIRect ir = layerRect.roundOut(); + const SkIRect dstIR = layerRect.roundOut(); + + SkIRect srcIR; - if (!GrLayerCache::PlausiblyAtlasable(ir.width(), ir.height())) { + if (!compute_source_rect(info, initialMat, dstIR, &srcIR)) { continue; } prepare_for_hoisting(layerCache, topLevelPicture, initialMat, - info, ir, atlased, recycled, true, 0); + info, srcIR, dstIR, atlased, recycled, true, 0); } } @@ -179,9 +217,14 @@ void GrLayerHoister::FindLayersToHoist(GrContext* context, continue; } - const SkIRect ir = layerRect.roundOut(); + const SkIRect dstIR = layerRect.roundOut(); + + SkIRect srcIR; + if (!compute_source_rect(info, initialMat, dstIR, &srcIR)) { + continue; + } - prepare_for_hoisting(layerCache, topLevelPicture, initialMat, info, ir, + prepare_for_hoisting(layerCache, topLevelPicture, initialMat, info, srcIR, dstIR, needRendering, recycled, false, numSamples); } } @@ -198,7 +241,7 @@ void GrLayerHoister::DrawLayersToAtlas(GrContext* context, for (int i = 0; i < atlased.count(); ++i) { const GrCachedLayer* layer = atlased[i].fLayer; const SkPicture* pict = atlased[i].fPicture; - const SkIPoint offset = SkIPoint::Make(layer->bound().fLeft, layer->bound().fTop); + const SkIPoint offset = SkIPoint::Make(layer->srcIR().fLeft, layer->srcIR().fTop); SkDEBUGCODE(const SkPaint* layerPaint = layer->paint();) SkASSERT(!layerPaint || !layerPaint->getImageFilter()); @@ -234,42 +277,51 @@ void GrLayerHoister::DrawLayersToAtlas(GrContext* context, } } -void GrLayerHoister::FilterLayer(GrContext* context, SkGpuDevice* device, GrCachedLayer* layer) { +void GrLayerHoister::FilterLayer(GrContext* context, + SkGpuDevice* device, + const GrHoistedLayer& info) { + GrCachedLayer* layer = info.fLayer; + SkASSERT(layer->filter()); + SkASSERT(layer->filter()->canFilterImageGPU()); static const int kDefaultCacheSize = 32 * 1024 * 1024; - if (layer->filter()->canFilterImageGPU()) { - SkBitmap filteredBitmap; - SkIPoint offset = SkIPoint::Make(0, 0); + SkBitmap filteredBitmap; + SkIPoint offset = SkIPoint::Make(0, 0); - SkASSERT(0 == layer->rect().fLeft && 0 == layer->rect().fTop); - SkIRect clipBounds = layer->rect(); + const SkIPoint filterOffset = SkIPoint::Make(layer->srcIR().fLeft, layer->srcIR().fTop); - // This cache is transient, and is freed (along with all its contained - // textures) when it goes out of scope. - SkAutoTUnref<SkImageFilter::Cache> cache(SkImageFilter::Cache::Create(kDefaultCacheSize)); - SkImageFilter::Context filterContext(SkMatrix::I(), clipBounds, cache); + SkMatrix totMat = SkMatrix::I(); + totMat.preConcat(info.fPreMat); + totMat.preConcat(info.fLocalMat); + totMat.postTranslate(-SkIntToScalar(filterOffset.fX), -SkIntToScalar(filterOffset.fY)); - if (!device->filterTexture(context, layer->texture(), layer->filter(), - filterContext, &filteredBitmap, &offset)) { - // Filtering failed. Press on with the unfiltered version - return; - } - // TODO: need to fix up offset - SkASSERT(0 == offset.fX && 0 == offset.fY); + SkASSERT(0 == layer->rect().fLeft && 0 == layer->rect().fTop); + SkIRect clipBounds = layer->rect(); - SkIRect newRect = SkIRect::MakeWH(filteredBitmap.width(), filteredBitmap.height()); - layer->setTexture(filteredBitmap.getTexture(), newRect); + // This cache is transient, and is freed (along with all its contained + // textures) when it goes out of scope. + SkAutoTUnref<SkImageFilter::Cache> cache(SkImageFilter::Cache::Create(kDefaultCacheSize)); + SkImageFilter::Context filterContext(totMat, clipBounds, cache); + + if (!device->filterTexture(context, layer->texture(), layer->filter(), + filterContext, &filteredBitmap, &offset)) { + // Filtering failed. Press on with the unfiltered version + return; } + + SkIRect newRect = SkIRect::MakeWH(filteredBitmap.width(), filteredBitmap.height()); + layer->setTexture(filteredBitmap.getTexture(), newRect); + layer->setOffset(offset); } 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 = SkIPoint::Make(layer->bound().fLeft, layer->bound().fTop); + const SkIPoint offset = SkIPoint::Make(layer->srcIR().fLeft, layer->srcIR().fTop); // Each non-atlased layer has its own GrTexture SkAutoTUnref<SkSurface> surface(SkSurface::NewRenderTargetDirect( @@ -301,7 +353,7 @@ void GrLayerHoister::DrawLayers(GrContext* context, const SkTDArray<GrHoistedLay if (layer->filter()) { SkSurface_Gpu* gpuSurf = static_cast<SkSurface_Gpu*>(surface.get()); - FilterLayer(context, gpuSurf->getDevice(), layer); + FilterLayer(context, gpuSurf->getDevice(), layers[i]); } } } |