Add a transient image filter cache to SkImage::makeWithFilter & PDF

Added a bench for makeWithFilter (~23 ms -> ~6 ms median locally).

Also fixed indentation.

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2360663002

Review-Url: https://codereview.chromium.org/2360663002
This commit is contained in:
brianosman 2016-09-21 09:46:57 -07:00 committed by Commit bot
parent 3e8012e74f
commit 04a44d0fd4
6 changed files with 85 additions and 34 deletions

View File

@ -6,6 +6,7 @@
*/ */
#include "Benchmark.h" #include "Benchmark.h"
#include "Resources.h"
#include "SkBlurImageFilter.h" #include "SkBlurImageFilter.h"
#include "SkDisplacementMapEffect.h" #include "SkDisplacementMapEffect.h"
#include "SkCanvas.h" #include "SkCanvas.h"
@ -45,6 +46,45 @@ private:
typedef Benchmark INHERITED; typedef Benchmark INHERITED;
}; };
class ImageMakeWithFilterDAGBench : public Benchmark {
public:
ImageMakeWithFilterDAGBench() {}
protected:
const char* onGetName() override {
return "image_make_with_filter_dag";
}
void onDelayedSetup() override {
fImage = GetResourceAsImage("mandrill_512.png");
}
void onDraw(int loops, SkCanvas* canvas) override {
SkIRect subset = SkIRect::MakeSize(fImage->dimensions());
SkIPoint offset = SkIPoint::Make(0, 0);
SkIRect discardSubset;
sk_sp<SkImage> image = fImage;
for (int j = 0; j < loops; j++) {
sk_sp<SkImageFilter> blur(SkBlurImageFilter::Make(20.0f, 20.0f, nullptr));
sk_sp<SkImageFilter> inputs[kNumInputs];
for (int i = 0; i < kNumInputs; ++i) {
inputs[i] = blur;
}
sk_sp<SkImageFilter> mergeFilter = SkMergeImageFilter::Make(inputs, kNumInputs);
image = image->makeWithFilter(mergeFilter.get(), subset, subset, &discardSubset,
&offset);
SkASSERT(image && image->dimensions() == fImage->dimensions());
}
}
private:
static const int kNumInputs = 5;
sk_sp<SkImage> fImage;
typedef Benchmark INHERITED;
};
// Exercise a blur filter connected to both inputs of an SkDisplacementMapEffect. // Exercise a blur filter connected to both inputs of an SkDisplacementMapEffect.
class ImageFilterDisplacedBlur : public Benchmark { class ImageFilterDisplacedBlur : public Benchmark {
@ -77,4 +117,5 @@ private:
}; };
DEF_BENCH(return new ImageFilterDAGBench;) DEF_BENCH(return new ImageFilterDAGBench;)
DEF_BENCH(return new ImageMakeWithFilterDAGBench;)
DEF_BENCH(return new ImageFilterDisplacedBlur;) DEF_BENCH(return new ImageFilterDisplacedBlur;)

View File

@ -48,6 +48,8 @@ struct SkImageFilterCacheKey {
// (result, offset). // (result, offset).
class SkImageFilterCache : public SkRefCnt { class SkImageFilterCache : public SkRefCnt {
public: public:
enum { kDefaultTransientSize = 32 * 1024 * 1024 };
virtual ~SkImageFilterCache() {} virtual ~SkImageFilterCache() {}
static SkImageFilterCache* Create(size_t maxBytes); static SkImageFilterCache* Create(size_t maxBytes);
static SkImageFilterCache* Get(); static SkImageFilterCache* Get();

View File

@ -53,8 +53,6 @@
#define ASSERT_SINGLE_OWNER \ #define ASSERT_SINGLE_OWNER \
SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fContext->debugSingleOwner());) SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fContext->debugSingleOwner());)
enum { kDefaultImageFilterCacheSize = 32 * 1024 * 1024 };
#if 0 #if 0
extern bool (*gShouldDrawProc)(); extern bool (*gShouldDrawProc)();
#define CHECK_SHOULD_DRAW(draw) \ #define CHECK_SHOULD_DRAW(draw) \
@ -1818,7 +1816,7 @@ SkImageFilterCache* SkGpuDevice::getImageFilterCache() {
ASSERT_SINGLE_OWNER ASSERT_SINGLE_OWNER
// We always return a transient cache, so it is freed after each // We always return a transient cache, so it is freed after each
// filter traversal. // filter traversal.
return SkImageFilterCache::Create(kDefaultImageFilterCacheSize); return SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize);
} }
#endif #endif

View File

@ -11,6 +11,7 @@
#include "SkData.h" #include "SkData.h"
#include "SkImageEncoder.h" #include "SkImageEncoder.h"
#include "SkImageFilter.h" #include "SkImageFilter.h"
#include "SkImageFilterCache.h"
#include "SkImageGenerator.h" #include "SkImageGenerator.h"
#include "SkImagePriv.h" #include "SkImagePriv.h"
#include "SkImageShader.h" #include "SkImageShader.h"
@ -334,40 +335,41 @@ sk_sp<SkImage> SkImage::MakeFromPicture(sk_sp<SkPicture> picture, const SkISize&
sk_sp<SkImage> SkImage::makeWithFilter(const SkImageFilter* filter, const SkIRect& subset, sk_sp<SkImage> SkImage::makeWithFilter(const SkImageFilter* filter, const SkIRect& subset,
const SkIRect& clipBounds, SkIRect* outSubset, const SkIRect& clipBounds, SkIRect* outSubset,
SkIPoint* offset) const { SkIPoint* offset) const {
if (!filter || !outSubset || !offset || !this->bounds().contains(subset)) { if (!filter || !outSubset || !offset || !this->bounds().contains(subset)) {
return nullptr; return nullptr;
} }
sk_sp<SkSpecialImage> srcSpecialImage = SkSpecialImage::MakeFromImage( sk_sp<SkSpecialImage> srcSpecialImage = SkSpecialImage::MakeFromImage(
subset, sk_ref_sp(const_cast<SkImage*>(this))); subset, sk_ref_sp(const_cast<SkImage*>(this)));
if (!srcSpecialImage) { if (!srcSpecialImage) {
return nullptr; return nullptr;
} }
// FIXME: build a cache here. SkAutoTUnref<SkImageFilterCache> cache(
SkImageFilter::Context context(SkMatrix::I(), clipBounds, nullptr); SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize));
sk_sp<SkSpecialImage> result = SkImageFilter::Context context(SkMatrix::I(), clipBounds, cache.get());
filter->filterImage(srcSpecialImage.get(), context, offset); sk_sp<SkSpecialImage> result =
filter->filterImage(srcSpecialImage.get(), context, offset);
if (!result) { if (!result) {
return nullptr; return nullptr;
} }
SkIRect fullSize = SkIRect::MakeWH(result->width(), result->height()); SkIRect fullSize = SkIRect::MakeWH(result->width(), result->height());
#if SK_SUPPORT_GPU #if SK_SUPPORT_GPU
if (result->isTextureBacked()) { if (result->isTextureBacked()) {
GrContext* context = result->getContext(); GrContext* context = result->getContext();
sk_sp<GrTexture> texture = result->asTextureRef(context); sk_sp<GrTexture> texture = result->asTextureRef(context);
fullSize = SkIRect::MakeWH(texture->width(), texture->height()); fullSize = SkIRect::MakeWH(texture->width(), texture->height());
} }
#endif #endif
*outSubset = SkIRect::MakeWH(result->width(), result->height()); *outSubset = SkIRect::MakeWH(result->width(), result->height());
if (!outSubset->intersect(clipBounds.makeOffset(-offset->x(), -offset->y()))) { if (!outSubset->intersect(clipBounds.makeOffset(-offset->x(), -offset->y()))) {
return nullptr; return nullptr;
} }
offset->fX += outSubset->x(); offset->fX += outSubset->x();
offset->fY += outSubset->y(); offset->fY += outSubset->y();
// This isn't really a "tight" subset, but includes any texture padding. // This isn't really a "tight" subset, but includes any texture padding.
return result->makeTightSubset(fullSize); return result->makeTightSubset(fullSize);
} }
bool SkImage::isLazyGenerated() const { bool SkImage::isLazyGenerated() const {

View File

@ -16,6 +16,7 @@
#include "SkDraw.h" #include "SkDraw.h"
#include "SkDrawFilter.h" #include "SkDrawFilter.h"
#include "SkGlyphCache.h" #include "SkGlyphCache.h"
#include "SkImageFilterCache.h"
#include "SkMakeUnique.h" #include "SkMakeUnique.h"
#include "SkPath.h" #include "SkPath.h"
#include "SkPathEffect.h" #include "SkPathEffect.h"
@ -2286,8 +2287,8 @@ void SkPDFDevice::drawSpecial(const SkDraw& draw, SkSpecialImage* srcImg, int x,
SkMatrix matrix = *draw.fMatrix; SkMatrix matrix = *draw.fMatrix;
matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y)); matrix.postTranslate(SkIntToScalar(-x), SkIntToScalar(-y));
const SkIRect clipBounds = draw.fRC->getBounds().makeOffset(-x, -y); const SkIRect clipBounds = draw.fRC->getBounds().makeOffset(-x, -y);
// SkAutoTUnref<SkImageFilterCache> cache(this->getImageFilterCache()); SkAutoTUnref<SkImageFilterCache> cache(this->getImageFilterCache());
SkImageFilter::Context ctx(matrix, clipBounds, nullptr /*cache.get()*/); SkImageFilter::Context ctx(matrix, clipBounds, cache.get());
sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg, ctx, &offset)); sk_sp<SkSpecialImage> resultImg(filter->filterImage(srcImg, ctx, &offset));
if (resultImg) { if (resultImg) {
@ -2316,3 +2317,9 @@ sk_sp<SkSpecialImage> SkPDFDevice::makeSpecial(const SkImage* image) {
sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() { sk_sp<SkSpecialImage> SkPDFDevice::snapSpecial() {
return nullptr; return nullptr;
} }
SkImageFilterCache* SkPDFDevice::getImageFilterCache() {
// We always return a transient cache, so it is freed after each
// filter traversal.
return SkImageFilterCache::Create(SkImageFilterCache::kDefaultTransientSize);
}

View File

@ -181,6 +181,7 @@ protected:
sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&) override; sk_sp<SkSpecialImage> makeSpecial(const SkBitmap&) override;
sk_sp<SkSpecialImage> makeSpecial(const SkImage*) override; sk_sp<SkSpecialImage> makeSpecial(const SkImage*) override;
sk_sp<SkSpecialImage> snapSpecial() override; sk_sp<SkSpecialImage> snapSpecial() override;
SkImageFilterCache* getImageFilterCache() override;
private: private:
struct RectWithData { struct RectWithData {