aboutsummaryrefslogtreecommitdiffhomepage
path: root/bench/ImageBench.cpp
blob: 0263758da50eea53e49a52b011fe3b06451e5587 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "Benchmark.h"
#include "SkCanvas.h"
#include "SkImage.h"
#include "SkSurface.h"

class Image2RasterBench : public Benchmark {
public:
    Image2RasterBench() {
        fName.set("native_image_to_raster_surface");
    }

    bool isSuitableFor(Backend backend) override {
        return kGPU_Backend == backend || kRaster_Backend == backend;
    }

protected:
    const char* onGetName() override {
        return fName.c_str();
    }

    // We explicitly want to bench drawing a Image [cpu or gpu backed] into a raster target,
    // to ensure that we can cache the read-back in the case of gpu -> raster
    //
    void onPerCanvasPreDraw(SkCanvas* canvas) override {
        // create an Image reflecting the canvas (gpu or cpu)
        SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
        SkAutoTUnref<SkSurface> surface(canvas->newSurface(info));
        canvas->drawColor(SK_ColorRED);
        fImage.reset(surface->newImageSnapshot());

        // create a cpu-backed Surface
        fRasterSurface.reset(SkSurface::NewRaster(info));
    }

    void onPerCanvasPostDraw(SkCanvas*) override {
        // Release the image and raster surface here to prevent out of order destruction
        // between these and the gpu interface.
        fRasterSurface.reset(nullptr);
        fImage.reset(nullptr);
    }

    void onDraw(int loops, SkCanvas*) override {
        for (int i = 0; i < loops; i++) {
            for (int inner = 0; inner < 10; ++inner) {
                fRasterSurface->getCanvas()->drawImage(fImage, 0, 0);
            }
        }
    }

private:
    SkString                fName;
    SkAutoTUnref<SkImage>   fImage;
    SkAutoTUnref<SkSurface> fRasterSurface;

    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"); )