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]); |
} |
} |
} |