1/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include <memory>
9#include "SkColor.h"
10#include "SkLinearBitmapPipeline.h"
11#include "SkPM4f.h"
12#include "Benchmark.h"
13#include "SkShader.h"
14#include "SkImage.h"
15
16struct CommonBitmapFPBenchmark : public Benchmark {
17    CommonBitmapFPBenchmark(
18        SkISize srcSize,
19        SkColorProfileType colorProfile,
20        SkMatrix m,
21        bool useBilerp,
22        SkShader::TileMode xTile,
23        SkShader::TileMode yTile)
24        : fColorProfile(colorProfile)
25        , fM{m}
26        , fUseBilerp{useBilerp}
27        , fXTile{xTile}
28        , fYTile{yTile} {
29        fSrcSize = srcSize;
30    }
31
32    static SkString tileName(const char* pre, SkShader::TileMode mode) {
33        SkString name{pre};
34        switch (mode) {
35            case SkShader::kClamp_TileMode:
36                name.append("Clamp");
37                return name;
38            case SkShader::kRepeat_TileMode:
39                name.append("Repeat");
40                return name;
41            case SkShader::kMirror_TileMode:
42                name.append("Mirror");
43                return name;
44            default:
45                name.append("Unknown");
46                return name;
47        }
48    }
49
50    const char* onGetName() override {
51        fName.set("SkBitmapFP");
52        if (fM.getType() & SkMatrix::kPerspective_Mask) {
53            fName.append("Perspective");
54        } else if (fM.getType() & SkMatrix::kAffine_Mask) {
55            fName.append("Affine");
56        } else if (fM.getType() & SkMatrix::kScale_Mask) {
57            fName.append("Scale");
58        } else if (fM.getType() & SkMatrix::kTranslate_Mask) {
59            fName.append("Translate");
60        } else {
61            fName.append("Identity");
62        }
63
64        fName.append(tileName("X", fXTile));
65        fName.append(tileName("Y", fYTile));
66
67        if (fUseBilerp) {
68            fName.append("Filter");
69        } else {
70            fName.append("Nearest");
71        }
72
73        fName.appendf("%s", BaseName().c_str());
74
75        return fName.c_str();
76    }
77
78    void onPreDraw(SkCanvas*) override {
79        int width = fSrcSize.fWidth;
80        int height = fSrcSize.fHeight;
81        fBitmap.reset(new uint32_t[width * height]);
82        for (int y = 0; y < height; y++) {
83            for (int x = 0; x < width; x++) {
84                fBitmap[y * width + x] = (y << 8) + x + (128<<24);
85            }
86        }
87
88        bool trash = fM.invert(&fInvert);
89        sk_ignore_unused_variable(trash);
90
91        fInfo = SkImageInfo::MakeN32Premul(width, height, fColorProfile);
92    }
93
94    bool isSuitableFor(Backend backend) override {
95        return backend == kNonRendering_Backend;
96    }
97
98    virtual SkString BaseName() = 0;
99
100    SkString fName;
101    SkISize fSrcSize;
102    SkColorProfileType fColorProfile;
103    SkMatrix fM;
104    SkMatrix fInvert;
105    bool fUseBilerp;
106    SkShader::TileMode fXTile;
107    SkShader::TileMode fYTile;
108    SkImageInfo fInfo;
109    std::unique_ptr<uint32_t[]> fBitmap;
110};
111
112struct SkBitmapFPGeneral final : public CommonBitmapFPBenchmark {
113    SkBitmapFPGeneral(
114        SkISize srcSize,
115        SkColorProfileType colorProfile,
116        SkMatrix m,
117        bool useBilerp,
118        SkShader::TileMode xTile,
119        SkShader::TileMode yTile)
120            : CommonBitmapFPBenchmark(srcSize, colorProfile, m, useBilerp, xTile, yTile) { }
121
122    SkString BaseName() override {
123        SkString name;
124        if (fInfo.isSRGB()) {
125            name.set("sRGB");
126        } else {
127            name.set("Linr");
128        }
129        return name;
130    }
131
132    void onDraw(int loops, SkCanvas*) override {
133        int width = fSrcSize.fWidth;
134        int height = fSrcSize.fHeight;
135
136        SkAutoTMalloc<SkPM4f> FPbuffer(width*height);
137
138        SkFilterQuality filterQuality;
139        if (fUseBilerp) {
140            filterQuality = SkFilterQuality::kLow_SkFilterQuality;
141        } else {
142            filterQuality = SkFilterQuality::kNone_SkFilterQuality;
143        }
144
145        SkPixmap srcPixmap{fInfo, fBitmap.get(), static_cast<size_t>(4 * width)};
146
147        SkLinearBitmapPipeline pipeline{
148            fInvert, filterQuality, fXTile, fYTile, srcPixmap};
149
150        int count = 100;
151
152        for (int n = 0; n < 1000*loops; n++) {
153            pipeline.shadeSpan4f(3, 6, FPbuffer, count);
154        }
155    }
156};
157
158struct SkBitmapFPOrigShader : public CommonBitmapFPBenchmark {
159    SkBitmapFPOrigShader(
160        SkISize srcSize,
161        SkColorProfileType colorProfile,
162        SkMatrix m,
163        bool useBilerp,
164        SkShader::TileMode xTile,
165        SkShader::TileMode yTile)
166            : CommonBitmapFPBenchmark(srcSize, colorProfile, m, useBilerp, xTile, yTile) { }
167
168    SkString BaseName() override {
169        SkString name{"Orig"};
170        return name;
171    }
172
173    void onPreDraw(SkCanvas* c) override {
174        CommonBitmapFPBenchmark::onPreDraw(c);
175
176        SkImage* image = SkImage::NewRasterCopy(
177            fInfo, fBitmap.get(), sizeof(SkPMColor) * fSrcSize.fWidth);
178        fImage.reset(image);
179        SkShader* shader = fImage->newShader(fXTile, fYTile);
180        if (fUseBilerp) {
181            fPaint.setFilterQuality(SkFilterQuality::kLow_SkFilterQuality);
182        } else {
183            fPaint.setFilterQuality(SkFilterQuality::kNone_SkFilterQuality);
184        }
185        fPaint.setShader(shader)->unref();
186    }
187
188    void onPostDraw(SkCanvas*) override {
189
190    }
191
192    void onDraw(int loops, SkCanvas*) override {
193        int width = fSrcSize.fWidth;
194        int height = fSrcSize.fHeight;
195
196        SkAutoTMalloc<SkPMColor> buffer4b(width*height);
197
198        uint32_t storage[200];
199        const SkShader::ContextRec rec(fPaint, fM, nullptr,
200                                       SkShader::ContextRec::kPMColor_DstType);
201        SkASSERT(fPaint.getShader()->contextSize(rec) <= sizeof(storage));
202        SkShader::Context* ctx = fPaint.getShader()->createContext(rec, storage);
203
204        int count = 100;
205
206        for (int n = 0; n < 1000*loops; n++) {
207            ctx->shadeSpan(3, 6, buffer4b, count);
208        }
209
210        ctx->~Context();
211    }
212    SkPaint fPaint;
213    SkAutoTUnref<SkImage> fImage;
214};
215
216static SkISize srcSize = SkISize::Make(120, 100);
217static SkMatrix mI = SkMatrix::I();
218DEF_BENCH(return new SkBitmapFPGeneral(
219    srcSize, kSRGB_SkColorProfileType, mI, false,
220    SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);)
221
222DEF_BENCH(return new SkBitmapFPGeneral(
223    srcSize, kLinear_SkColorProfileType, mI, false,
224    SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);)
225
226DEF_BENCH(return new SkBitmapFPOrigShader(
227    srcSize, kLinear_SkColorProfileType, mI, false,
228    SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);)
229
230DEF_BENCH(return new SkBitmapFPGeneral(
231    srcSize, kSRGB_SkColorProfileType, mI, true,
232    SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);)
233
234DEF_BENCH(return new SkBitmapFPGeneral(
235    srcSize, kLinear_SkColorProfileType, mI, true,
236    SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);)
237
238DEF_BENCH(return new SkBitmapFPOrigShader(
239    srcSize, kLinear_SkColorProfileType, mI, true,
240    SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);)
241
242static SkMatrix mS = SkMatrix::MakeScale(2.7f, 2.7f);
243DEF_BENCH(return new SkBitmapFPGeneral(
244    srcSize, kSRGB_SkColorProfileType, mS, false,
245    SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);)
246
247DEF_BENCH(return new SkBitmapFPGeneral(
248    srcSize, kLinear_SkColorProfileType, mS, false,
249    SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);)
250
251DEF_BENCH(return new SkBitmapFPOrigShader(
252    srcSize, kLinear_SkColorProfileType, mS, false,
253    SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);)
254
255DEF_BENCH(return new SkBitmapFPGeneral(
256    srcSize, kSRGB_SkColorProfileType, mS, true,
257    SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);)
258
259DEF_BENCH(return new SkBitmapFPGeneral(
260    srcSize, kLinear_SkColorProfileType, mS, true,
261    SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);)
262
263DEF_BENCH(return new SkBitmapFPOrigShader(
264    srcSize, kLinear_SkColorProfileType, mS, true,
265    SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);)
266
267static SkMatrix rotate(SkScalar r) {
268    SkMatrix m;
269    m.setRotate(30);
270    return m;
271}
272
273static SkMatrix mR = rotate(30);
274DEF_BENCH(return new SkBitmapFPGeneral(
275    srcSize, kSRGB_SkColorProfileType, mR, false,
276    SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);)
277
278DEF_BENCH(return new SkBitmapFPGeneral(
279    srcSize, kLinear_SkColorProfileType, mR, false,
280    SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);)
281
282DEF_BENCH(return new SkBitmapFPOrigShader(
283    srcSize, kLinear_SkColorProfileType, mR, false,
284    SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);)
285
286DEF_BENCH(return new SkBitmapFPGeneral(
287    srcSize, kSRGB_SkColorProfileType, mR, true,
288    SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);)
289
290DEF_BENCH(return new SkBitmapFPGeneral(
291    srcSize, kLinear_SkColorProfileType, mR, true,
292    SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);)
293
294DEF_BENCH(return new SkBitmapFPOrigShader(
295    srcSize, kLinear_SkColorProfileType, mR, true,
296    SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);)
297
298