aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
7 files changed, 155 insertions, 57 deletions
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