| Index: src/gpu/GrLayerHoister.cpp
|
| diff --git a/src/gpu/GrLayerHoister.cpp b/src/gpu/GrLayerHoister.cpp
|
| index c63fb5476c5b0c7fb8dd77034b316d17e1696883..0a86e419b635f4c176cb5b50c809045f9d17bd3c 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]);
|
| }
|
| }
|
| }
|
|
|