| Index: bench/ImageBench.cpp | 
| diff --git a/bench/ImageBench.cpp b/bench/ImageBench.cpp | 
| index b81c57c6dcb09b8402a7b7bd394ae8f91e1976ee..0263758da50eea53e49a52b011fe3b06451e5587 100644 | 
| --- a/bench/ImageBench.cpp | 
| +++ b/bench/ImageBench.cpp | 
| @@ -61,6 +61,118 @@ private: | 
|  | 
| typedef Benchmark INHERITED; | 
| }; | 
| +DEF_BENCH( return new Image2RasterBench; ) | 
|  | 
| +/////////////////////////////////////////////////////////////////////////////////////////////////// | 
| + | 
| +#include "SkOffsetImageFilter.h" | 
| + | 
| +#if SK_SUPPORT_GPU | 
| +#include "SkGrPixelRef.h" | 
| +#endif | 
| + | 
| +enum MyDrawType { | 
| +    kSprite_Type, | 
| +    kBitmap_Type, | 
| +    kImage_Type, | 
| +}; | 
| + | 
| +/* | 
| + *  Want to time drawing images/bitmaps via drawSprite, and via drawBitmap/drawImage but with | 
| + *  a non-scaling matrix and a clip that is tight to the image bounds. In this scenario, we | 
| + *  should be able to match the speed of drawSprite. | 
| + * | 
| + *  An optimal result should be that all three types: sprite/bitmap/image draw at the same speed. | 
| + */ | 
| +class ImageFilterSpriteBench : public Benchmark { | 
| +    SkAutoTUnref<SkImage>       fImage; | 
| +    SkBitmap                    fBitmap; | 
| +    SkString                    fName; | 
| +    MyDrawType                  fType; | 
| + | 
| +public: | 
| +    ImageFilterSpriteBench(MyDrawType dt, const char suffix[]) : fType(dt) { | 
| +        fName.printf("image-filter-sprite-draw-%s", suffix); | 
| +    } | 
| + | 
| +    bool isSuitableFor(Backend backend) override { | 
| +        return kGPU_Backend == backend || kRaster_Backend == backend; | 
| +    } | 
| + | 
| +protected: | 
| +    bool isVisual() override { | 
| +        return true; | 
| +    } | 
| + | 
| +    const char* onGetName() override { | 
| +        return fName.c_str(); | 
| +    } | 
| + | 
| +    void onPerCanvasPreDraw(SkCanvas* canvas) override { | 
| +        const SkImageInfo info = SkImageInfo::MakeN32Premul(500, 500); | 
| +        SkAutoTUnref<SkSurface> surface(canvas->newSurface(info)); | 
| + | 
| +        surface->getCanvas()->drawColor(SK_ColorRED); | 
| +        fImage.reset(surface->newImageSnapshot()); | 
| + | 
| +        fBitmap.setInfo(info); | 
| +        if (fImage->getTexture()) { | 
| +#if SK_SUPPORT_GPU | 
| +            fBitmap.setPixelRef(new SkGrPixelRef(info, fImage->getTexture()))->unref(); | 
| +#endif | 
| +        } else { | 
| +            SkPixmap pmap; | 
| +            if (!fImage->peekPixels(&pmap)) { | 
| +                sk_throw(); | 
| +            } | 
| +            fBitmap.installPixels(pmap.info(), pmap.writable_addr(), pmap.rowBytes()); | 
| +        } | 
| +    } | 
| + | 
| +    void onPerCanvasPostDraw(SkCanvas*) override { | 
| +        // Release the image and raster surface here to prevent out of order destruction | 
| +        // between these and the gpu interface. | 
| +        fImage.reset(nullptr); | 
| +        fBitmap.reset(); | 
| +    } | 
| + | 
| +    void onDraw(int loops, SkCanvas* canvas) override { | 
| +        // This clip is important; it allows the drawImage/drawBitmap code to fall into the | 
| +        // fast (sprite) case, since the imagefilter's output should match. | 
| +        // | 
| +        // When we address skbug.com/4526 we should be able to remove the need for this clip. | 
| +        // | 
| +        canvas->clipRect(SkRect::MakeIWH(fImage->width(), fImage->height())); | 
| + | 
| +        const SkScalar kDelta = 10; | 
| +        SkPaint paint; | 
| +        for (int i = 0; i < loops; i++) { | 
| +            for (int inner = 0; inner < 10; ++inner) { | 
| +                // build the filter everytime, so we don't accidentally draw a cached version, | 
| +                // since the point of this bench is to time the actual imagefilter | 
| +                // handling/overhead. | 
| +                SkAutoTUnref<SkImageFilter> filter(SkOffsetImageFilter::Create(kDelta, kDelta)); | 
| +                paint.setImageFilter(filter); | 
| + | 
| +                switch (fType) { | 
| +                    case kSprite_Type: | 
| +                        canvas->drawSprite(fBitmap, 0, 0, &paint); | 
| +                        break; | 
| +                    case kBitmap_Type: | 
| +                        canvas->drawBitmap(fBitmap, 0, 0, &paint); | 
| +                        break; | 
| +                    case kImage_Type: | 
| +                        canvas->drawImage(fImage, 0, 0, &paint); | 
| +                        break; | 
| +                } | 
| +            } | 
| +        } | 
| +    } | 
| + | 
| +private: | 
| +    typedef Benchmark INHERITED; | 
| +}; | 
| +DEF_BENCH( return new ImageFilterSpriteBench(kSprite_Type, "sprite"); ) | 
| +DEF_BENCH( return new ImageFilterSpriteBench(kBitmap_Type, "bitmap"); ) | 
| +DEF_BENCH( return new ImageFilterSpriteBench(kImage_Type,  "image"); ) | 
|  | 
| -DEF_BENCH( return new Image2RasterBench; ) | 
|  |