aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar robertphillips <robertphillips@google.com>2014-12-16 07:27:30 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2014-12-16 07:27:30 -0800
commit702eb9622102599d94ab6798e6227cf29f48c2d3 (patch)
tree4f89d2bd00efba8a11df210765efa3ea3303a6ff
parent9a5380dd358a9c559a41beef7cb368cd7f0ca51f (diff)
Fix layer hoisting image filter corner cases
This CL fixes 5 bugs related to hoisting image filters: For image filters the src layer (the one prior to filtering) often needs to be smaller then the final layer. This requires the saveLayer's optional bounds to be stored (in SkLayerInfo.h and SkRecordDraw.cpp) and then used in compute_source_rect and carried around in GrCachedLayer. The image filters can add an extra offset to the final draw operation. This is now computed in GrLayerHoister::FilterLayer and carried around in GrCachedLayer. Filtered layers must use exact matches. This is now done in GrLayerCache::lock. The filter cache requires a valid matrix so it can compute the correct offset. This is now done in GrLayerHoister::FilterLayer. Filtered layers need to be drawn with drawSprite while unfiltered (and therefore hopefully atlased) layers can be drawn with drawBitmap. This is now done in draw_replacement_bitmap. Review URL: https://codereview.chromium.org/803183003
-rw-r--r--gm/gmmain.cpp32
-rw-r--r--src/core/SkLayerInfo.h3
-rw-r--r--src/core/SkRecordDraw.cpp15
-rw-r--r--src/gpu/GrLayerCache.cpp21
-rw-r--r--src/gpu/GrLayerCache.h33
-rw-r--r--src/gpu/GrLayerHoister.cpp114
-rw-r--r--src/gpu/GrLayerHoister.h4
-rw-r--r--src/gpu/GrRecordReplaceDraw.cpp22
-rw-r--r--tests/GpuLayerCacheTest.cpp1
-rw-r--r--tests/RecordReplaceDrawTest.cpp1
10 files changed, 176 insertions, 70 deletions
diff --git a/gm/gmmain.cpp b/gm/gmmain.cpp
index da4184db67..9b2f9a13c2 100644
--- a/gm/gmmain.cpp
+++ b/gm/gmmain.cpp
@@ -655,18 +655,21 @@ public:
}
}
- static void generate_image_from_picture(GM* gm, const ConfigData& gRec,
+ static void generate_image_from_picture(GM* gm, const ConfigData& config,
+ GrSurface* gpuTarget,
SkPicture* pict, SkBitmap* bitmap,
SkScalar scale = SK_Scalar1,
bool tile = false) {
- SkISize size = gm->getISize();
- setup_bitmap(gRec, size, bitmap);
+ const SkISize size = gm->getISize();
- SkAutoTUnref<SkSurface> surf(SkSurface::NewRasterDirect(bitmap->info(),
- bitmap->getPixels(),
- bitmap->rowBytes()));
+ SkAutoTUnref<SkSurface> surf(CreateSurface(config, size, gpuTarget));
DrawPictureToSurface(surf, pict, scale, tile, false);
+
+ setup_bitmap(config, size, bitmap);
+
+ surf->readPixels(bitmap->info(), bitmap->getPixels(), bitmap->rowBytes(), 0, 0);
+
complete_bitmap(bitmap);
}
@@ -1630,10 +1633,12 @@ template <typename T> void appendUnique(SkTDArray<T>* array, const T& value) {
*
* Returns all errors encountered while doing so.
*/
-ErrorCombination run_multiple_modes(GMMain &gmmain, GM *gm, const ConfigData &compareConfig,
+ErrorCombination run_multiple_modes(GMMain &gmmain, GM *gm,
+ const ConfigData &compareConfig, GrSurface* gpuTarget,
const SkBitmap &comparisonBitmap,
const SkTDArray<SkScalar> &tileGridReplayScales);
-ErrorCombination run_multiple_modes(GMMain &gmmain, GM *gm, const ConfigData &compareConfig,
+ErrorCombination run_multiple_modes(GMMain &gmmain, GM *gm,
+ const ConfigData &compareConfig, GrSurface* gpuTarget,
const SkBitmap &comparisonBitmap,
const SkTDArray<SkScalar> &tileGridReplayScales) {
ErrorCombination errorsForAllModes;
@@ -1651,7 +1656,8 @@ ErrorCombination run_multiple_modes(GMMain &gmmain, GM *gm, const ConfigData &co
errorsForAllModes.add(kIntentionallySkipped_ErrorType);
} else {
SkBitmap bitmap;
- gmmain.generate_image_from_picture(gm, compareConfig, pict, &bitmap);
+ gmmain.generate_image_from_picture(gm, compareConfig, gpuTarget, pict, &bitmap);
+
errorsForAllModes.add(gmmain.compare_test_results_to_reference_bitmap(
gm->getName(), compareConfig.fName, renderModeDescriptor, bitmap,
&comparisonBitmap));
@@ -1668,7 +1674,7 @@ ErrorCombination run_multiple_modes(GMMain &gmmain, GM *gm, const ConfigData &co
SkPicture* repict = gmmain.stream_to_new_picture(*pict);
SkAutoTUnref<SkPicture> aurr(repict);
SkBitmap bitmap;
- gmmain.generate_image_from_picture(gm, compareConfig, repict, &bitmap);
+ gmmain.generate_image_from_picture(gm, compareConfig, gpuTarget, repict, &bitmap);
errorsForAllModes.add(gmmain.compare_test_results_to_reference_bitmap(
gm->getName(), compareConfig.fName, renderModeDescriptor, bitmap,
&comparisonBitmap));
@@ -1701,7 +1707,7 @@ ErrorCombination run_multiple_modes(GMMain &gmmain, GM *gm, const ConfigData &co
SkPicture* pict = gmmain.generate_new_picture(gm, kRTree_BbhType, 0);
SkAutoTUnref<SkPicture> aur(pict);
SkBitmap bitmap;
- gmmain.generate_image_from_picture(gm, compareConfig, pict, &bitmap);
+ gmmain.generate_image_from_picture(gm, compareConfig, gpuTarget, pict, &bitmap);
errorsForAllModes.add(gmmain.compare_test_results_to_reference_bitmap(
gm->getName(), compareConfig.fName, renderModeDescriptor, bitmap,
&comparisonBitmap));
@@ -1734,7 +1740,7 @@ ErrorCombination run_multiple_modes(GMMain &gmmain, GM *gm, const ConfigData &co
// We cannot yet pass 'true' to generate_image_from_picture to
// perform actual tiled rendering (see Issue 1198 -
// https://code.google.com/p/skia/issues/detail?id=1198)
- gmmain.generate_image_from_picture(gm, compareConfig, pict, &bitmap,
+ gmmain.generate_image_from_picture(gm, compareConfig, gpuTarget, pict, &bitmap,
replayScale /*, true */);
errorsForAllModes.add(gmmain.compare_test_results_to_reference_bitmap(
gm->getName(), compareConfig.fName, renderModeDescriptor.c_str(), bitmap,
@@ -1875,7 +1881,7 @@ ErrorCombination run_multiple_configs(GMMain &gmmain, GM *gm,
// TODO: run only if gmmain.test_drawing succeeded.
if (kRaster_Backend == config.fBackend) {
- run_multiple_modes(gmmain, gm, config, comparisonBitmap, tileGridReplayScales);
+ run_multiple_modes(gmmain, gm, config, gpuTarget, comparisonBitmap, tileGridReplayScales);
}
if (FLAGS_deferred && errorsForThisConfig.isEmpty() &&
diff --git a/src/core/SkLayerInfo.h b/src/core/SkLayerInfo.h
index add57d780c..a47c3f1199 100644
--- a/src/core/SkLayerInfo.h
+++ b/src/core/SkLayerInfo.h
@@ -28,6 +28,9 @@ public:
const SkPicture* fPicture;
// The device space bounds of this layer.
SkRect fBounds;
+ // If not-empty, the optional bounds parameter passed in to the saveLayer
+ // call.
+ SkRect fSrcBounds;
// The pre-matrix begins as the identity and accumulates the transforms
// of the containing SkPictures (if any). This matrix state has to be
// part of the initial matrix during replay so that it will be
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
index 86621f2170..6a2a5e3677 100644
--- a/src/core/SkRecordDraw.cpp
+++ b/src/core/SkRecordDraw.cpp
@@ -608,24 +608,26 @@ public:
private:
struct SaveLayerInfo {
SaveLayerInfo() { }
- SaveLayerInfo(int opIndex, bool isSaveLayer, const SkPaint* paint)
+ SaveLayerInfo(int opIndex, bool isSaveLayer, const SkRect* bounds, const SkPaint* paint)
: fStartIndex(opIndex)
, fIsSaveLayer(isSaveLayer)
, fHasNestedSaveLayer(false)
+ , fBounds(bounds ? *bounds : SkRect::MakeEmpty())
, fPaint(paint) {
}
int fStartIndex;
bool fIsSaveLayer;
bool fHasNestedSaveLayer;
+ SkRect fBounds;
const SkPaint* fPaint;
};
template <typename T> void trackSaveLayers(const T& op) {
/* most ops aren't involved in saveLayers */
}
- void trackSaveLayers(const Save& s) { this->pushSaveLayerInfo(false, NULL); }
- void trackSaveLayers(const SaveLayer& sl) { this->pushSaveLayerInfo(true, sl.paint); }
+ void trackSaveLayers(const Save& s) { this->pushSaveLayerInfo(false, NULL, NULL); }
+ void trackSaveLayers(const SaveLayer& sl) { this->pushSaveLayerInfo(true, sl.bounds, sl.paint); }
void trackSaveLayers(const Restore& r) { this->popSaveLayerInfo(); }
void trackSaveLayersForPicture(const SkPicture* picture, const SkPaint* paint) {
@@ -662,6 +664,7 @@ private:
dst.fPicture = src.fPicture ? src.fPicture : picture;
dst.fPicture->ref();
dst.fBounds = newBound;
+ dst.fSrcBounds = src.fSrcBounds;
dst.fLocalMat = src.fLocalMat;
dst.fPreMat = src.fPreMat;
dst.fPreMat.postConcat(fFillBounds.ctm());
@@ -707,14 +710,14 @@ private:
}
}
- void pushSaveLayerInfo(bool isSaveLayer, const SkPaint* paint) {
+ void pushSaveLayerInfo(bool isSaveLayer, const SkRect* bounds, const SkPaint* paint) {
if (isSaveLayer) {
this->updateStackForSaveLayer();
++fSaveLayersInStack;
fSaveLayerOpStack.push(fFillBounds.currentOp());
}
- fSaveLayerStack.push(SaveLayerInfo(fFillBounds.currentOp(), isSaveLayer, paint));
+ fSaveLayerStack.push(SaveLayerInfo(fFillBounds.currentOp(), isSaveLayer, bounds, paint));
}
void popSaveLayerInfo() {
@@ -744,6 +747,8 @@ private:
if (sli.fPaint) {
block.fPaint = SkNEW_ARGS(SkPaint, (*sli.fPaint));
}
+
+ block.fSrcBounds = sli.fBounds;
block.fSaveLayerOpID = sli.fStartIndex;
block.fRestoreOpID = fFillBounds.currentOp();
block.fHasNestedLayers = sli.fHasNestedSaveLayer;
diff --git a/src/gpu/GrLayerCache.cpp b/src/gpu/GrLayerCache.cpp
index fc5be5fd05..e521b3e323 100644
--- a/src/gpu/GrLayerCache.cpp
+++ b/src/gpu/GrLayerCache.cpp
@@ -123,14 +123,16 @@ void GrLayerCache::freeAll() {
GrCachedLayer* GrLayerCache::createLayer(uint32_t pictureID,
int start, int stop,
- const SkIRect& bounds,
+ const SkIRect& srcIR,
+ const SkIRect& dstIR,
const SkMatrix& initialMat,
const unsigned* key,
int keySize,
const SkPaint* paint) {
SkASSERT(pictureID != SK_InvalidGenID && start >= 0 && stop > 0);
- GrCachedLayer* layer = SkNEW_ARGS(GrCachedLayer, (pictureID, start, stop, bounds, initialMat,
+ GrCachedLayer* layer = SkNEW_ARGS(GrCachedLayer, (pictureID, start, stop,
+ srcIR, dstIR, initialMat,
key, keySize, paint));
fLayerHash.add(layer);
return layer;
@@ -144,7 +146,8 @@ GrCachedLayer* GrLayerCache::findLayer(uint32_t pictureID, const SkMatrix& initi
GrCachedLayer* GrLayerCache::findLayerOrCreate(uint32_t pictureID,
int start, int stop,
- const SkIRect& bounds,
+ const SkIRect& srcIR,
+ const SkIRect& dstIR,
const SkMatrix& initialMat,
const unsigned* key,
int keySize,
@@ -152,7 +155,9 @@ GrCachedLayer* GrLayerCache::findLayerOrCreate(uint32_t pictureID,
SkASSERT(pictureID != SK_InvalidGenID && start >= 0 && stop > 0);
GrCachedLayer* layer = fLayerHash.find(GrCachedLayer::Key(pictureID, initialMat, key, keySize));
if (NULL == layer) {
- layer = this->createLayer(pictureID, start, stop, bounds, initialMat, key, keySize, paint);
+ layer = this->createLayer(pictureID, start, stop,
+ srcIR, dstIR, initialMat,
+ key, keySize, paint);
}
return layer;
@@ -242,8 +247,14 @@ bool GrLayerCache::lock(GrCachedLayer* layer, const GrSurfaceDesc& desc, bool* n
return true;
}
+ // TODO: make the test for exact match depend on the image filters themselves
+ GrContext::ScratchTexMatch usage = GrContext::kApprox_ScratchTexMatch;
+ if (layer->fFilter) {
+ usage = GrContext::kExact_ScratchTexMatch;
+ }
+
SkAutoTUnref<GrTexture> tex(
- fContext->refScratchTexture(desc, GrContext::kApprox_ScratchTexMatch));
+ fContext->refScratchTexture(desc, usage));
if (!tex) {
return false;
diff --git a/src/gpu/GrLayerCache.h b/src/gpu/GrLayerCache.h
index 0ea23b3fc7..cdbd0806cc 100644
--- a/src/gpu/GrLayerCache.h
+++ b/src/gpu/GrLayerCache.h
@@ -144,13 +144,16 @@ public:
// GrCachedLayer proper
GrCachedLayer(uint32_t pictureID, unsigned start, unsigned stop,
- const SkIRect& bounds, const SkMatrix& ctm,
+ const SkIRect& srcIR, const SkIRect& dstIR,
+ const SkMatrix& ctm,
const unsigned* key, int keySize,
const SkPaint* paint)
: fKey(pictureID, ctm, key, keySize, true)
, fStart(start)
, fStop(stop)
- , fBounds(bounds)
+ , fSrcIR(srcIR)
+ , fDstIR(dstIR)
+ , fOffset(SkIPoint::Make(0, 0))
, fPaint(paint ? SkNEW_ARGS(SkPaint, (*paint)) : NULL)
, fFilter(NULL)
, fTexture(NULL)
@@ -161,8 +164,10 @@ public:
SkASSERT(SK_InvalidGenID != pictureID);
if (fPaint) {
- fFilter = SkSafeRef(fPaint->getImageFilter());
- fPaint->setImageFilter(NULL);
+ if (fPaint->getImageFilter() && fPaint->getImageFilter()->canFilterImageGPU()) {
+ fFilter = SkSafeRef(fPaint->getImageFilter());
+ fPaint->setImageFilter(NULL);
+ }
}
}
@@ -179,7 +184,8 @@ public:
unsigned start() const { return fStart; }
// TODO: make bound debug only
- const SkIRect& bound() const { return fBounds; }
+ const SkIRect& srcIR() const { return fSrcIR; }
+ const SkIRect& dstIR() const { return fDstIR; }
unsigned stop() const { return fStop; }
void setTexture(GrTexture* texture, const SkIRect& rect) {
SkRefCnt_SafeAssign(fTexture, texture);
@@ -190,6 +196,9 @@ public:
const SkImageFilter* filter() const { return fFilter; }
const SkIRect& rect() const { return fRect; }
+ void setOffset(const SkIPoint& offset) { fOffset = offset; }
+ const SkIPoint& offset() const { return fOffset; }
+
void setPlot(GrPlot* plot) {
SkASSERT(NULL == plot || NULL == fPlot);
fPlot = plot;
@@ -212,7 +221,13 @@ private:
// The final "restore" operation index of the cached layer
const unsigned fStop;
- const SkIRect fBounds;
+ // The layer's src rect (i.e., the portion of the source scene required
+ // for filtering).
+ const SkIRect fSrcIR;
+ // The layer's dest rect (i.e., where it will land in device space)
+ const SkIRect fDstIR;
+ // Offset sometimes required by image filters
+ SkIPoint fOffset;
// The paint used when dropping the layer down into the owning canvas.
// Can be NULL. This class makes a copy for itself.
@@ -276,7 +291,8 @@ public:
const unsigned* key, int keySize);
GrCachedLayer* findLayerOrCreate(uint32_t pictureID,
int start, int stop,
- const SkIRect& bounds,
+ const SkIRect& srcIR,
+ const SkIRect& dstIR,
const SkMatrix& initialMat,
const unsigned* key, int keySize,
const SkPaint* paint);
@@ -360,7 +376,8 @@ private:
void initAtlas();
GrCachedLayer* createLayer(uint32_t pictureID, int start, int stop,
- const SkIRect& bounds, const SkMatrix& initialMat,
+ const SkIRect& srcIR, const SkIRect& dstIR,
+ const SkMatrix& initialMat,
const unsigned* key, int keySize,
const SkPaint* paint);
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]);
}
}
}
diff --git a/src/gpu/GrLayerHoister.h b/src/gpu/GrLayerHoister.h
index 9668ba60d5..f30c53c038 100644
--- a/src/gpu/GrLayerHoister.h
+++ b/src/gpu/GrLayerHoister.h
@@ -108,9 +108,9 @@ private:
/** Update the GrTexture in 'layer' with its filtered version
@param context Owner of the layer cache (and thus the layers)
@param device Required by the filtering code
- @param layer A layer needing filtering prior to being composited
+ @param info Layer info for a layer needing filtering prior to being composited
*/
- static void FilterLayer(GrContext* context, SkGpuDevice* device, GrCachedLayer* layer);
+ static void FilterLayer(GrContext* context, SkGpuDevice* device, const GrHoistedLayer& info);
};
diff --git a/src/gpu/GrRecordReplaceDraw.cpp b/src/gpu/GrRecordReplaceDraw.cpp
index 852c51f418..0ceea3721f 100644
--- a/src/gpu/GrRecordReplaceDraw.cpp
+++ b/src/gpu/GrRecordReplaceDraw.cpp
@@ -21,8 +21,6 @@ static inline void wrap_texture(GrTexture* texture, int width, int height, SkBit
}
static inline void draw_replacement_bitmap(GrCachedLayer* layer, SkCanvas* canvas) {
- const SkRect src = SkRect::Make(layer->rect());
- const SkRect dst = SkRect::Make(layer->bound());
SkBitmap bm;
wrap_texture(layer->texture(),
@@ -30,10 +28,22 @@ static inline void draw_replacement_bitmap(GrCachedLayer* layer, SkCanvas* canva
!layer->isAtlased() ? layer->rect().height() : layer->texture()->height(),
&bm);
- canvas->save();
- canvas->setMatrix(SkMatrix::I());
- canvas->drawBitmapRectToRect(bm, &src, dst, layer->paint());
- canvas->restore();
+ if (layer->isAtlased()) {
+ const SkRect src = SkRect::Make(layer->rect());
+ const SkRect dst = SkRect::Make(layer->srcIR());
+
+ SkASSERT(layer->offset().isZero());
+
+ canvas->save();
+ canvas->setMatrix(SkMatrix::I());
+ canvas->drawBitmapRectToRect(bm, &src, dst, layer->paint());
+ canvas->restore();
+ } else {
+ canvas->drawSprite(bm,
+ layer->srcIR().fLeft + layer->offset().fX,
+ layer->srcIR().fTop + layer->offset().fY,
+ layer->paint());
+ }
}
// Used by GrRecordReplaceDraw. It intercepts nested drawPicture calls and
diff --git a/tests/GpuLayerCacheTest.cpp b/tests/GpuLayerCacheTest.cpp
index a149c367a0..6b3084b641 100644
--- a/tests/GpuLayerCacheTest.cpp
+++ b/tests/GpuLayerCacheTest.cpp
@@ -43,6 +43,7 @@ static void create_layers(skiatest::Reporter* reporter,
GrCachedLayer* layer = cache->findLayerOrCreate(picture.uniqueID(),
idOffset+i+1, idOffset+i+2,
SkIRect::MakeEmpty(),
+ SkIRect::MakeEmpty(),
SkMatrix::I(),
indices, 1,
NULL);
diff --git a/tests/RecordReplaceDrawTest.cpp b/tests/RecordReplaceDrawTest.cpp
index fd518fa177..bc63594fef 100644
--- a/tests/RecordReplaceDrawTest.cpp
+++ b/tests/RecordReplaceDrawTest.cpp
@@ -114,6 +114,7 @@ void test_replacements(skiatest::Reporter* r, GrContext* context, bool useBBH) {
GrLayerCache* layerCache = context->getLayerCache();
GrCachedLayer* layer = layerCache->findLayerOrCreate(pic->uniqueID(), 0, 2,
SkIRect::MakeWH(kWidth, kHeight),
+ SkIRect::MakeWH(kWidth, kHeight),
SkMatrix::I(), key, 1, &paint);
GrSurfaceDesc desc;