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 "gm.h"
9#include "sk_tool_utils.h"
10
11#include "Resources.h"
12#include "SkBitmapScaler.h"
13#include "SkGradientShader.h"
14#include "SkTypeface.h"
15#include "SkStream.h"
16#include "SkPaint.h"
17#include "SkMipMap.h"
18#include "Resources.h"
19
20#define SHOW_MIP_COLOR  0xFF000000
21
22static SkBitmap make_bitmap(int w, int h) {
23    SkBitmap bm;
24    bm.allocN32Pixels(w, h);
25    SkCanvas canvas(bm);
26    canvas.clear(0xFFFFFFFF);
27    SkPaint paint;
28    paint.setStyle(SkPaint::kStroke_Style);
29    paint.setStrokeWidth(w / 16.0f);
30    paint.setColor(SHOW_MIP_COLOR);
31    canvas.drawCircle(w/2.0f, h/2.0f, w/3.0f, paint);
32    return bm;
33}
34
35static SkBitmap make_bitmap2(int w, int h) {
36    SkBitmap bm;
37    bm.allocN32Pixels(w, h);
38    SkCanvas canvas(bm);
39    canvas.clear(0xFFFFFFFF);
40    SkPaint paint;
41    paint.setColor(SHOW_MIP_COLOR);
42    paint.setStyle(SkPaint::kStroke_Style);
43
44    SkScalar inset = 2;
45    SkRect r = SkRect::MakeIWH(w, h).makeInset(0.5f, 0.5f);
46    while (r.width() > 4) {
47        canvas.drawRect(r, paint);
48        r.inset(inset, inset);
49        inset += 1;
50    }
51    return bm;
52}
53
54#include "SkNx.h"
55static SkBitmap make_bitmap3(int w, int h) {
56    SkBitmap bm;
57    bm.allocN32Pixels(w, h);
58    SkCanvas canvas(bm);
59    canvas.clear(0xFFFFFFFF);
60    SkPaint paint;
61    paint.setStyle(SkPaint::kStroke_Style);
62    paint.setStrokeWidth(2.1f);
63    paint.setColor(SHOW_MIP_COLOR);
64
65    SkScalar s = SkIntToScalar(w);
66    Sk4f p(s, -s, -s, s);
67    Sk4f d(5);
68    while (p[1] < s) {
69        canvas.drawLine(p[0],p[1], p[2], p[3], paint);
70        p = p + d;
71    }
72    return bm;
73}
74
75class ShowMipLevels : public skiagm::GM {
76    const int fN;
77    SkBitmap  fBM[4];
78
79public:
80    static unsigned gamma(unsigned n) {
81        float x = n / 255.0f;
82#if 0
83        x = sqrtf(x);
84#else
85        if (x > 0.0031308f) {
86            x = 1.055f * (powf(x, (1.0f / 2.4f))) - 0.055f;
87        } else {
88            x = 12.92f * x;
89        }
90#endif
91        return (int)(x * 255);
92    }
93
94    static void apply_gamma(const SkBitmap& bm) {
95        return; // below is our experiment for sRGB correction
96        bm.lockPixels();
97        for (int y = 0; y < bm.height(); ++y) {
98            for (int x = 0; x < bm.width(); ++x) {
99                SkPMColor c = *bm.getAddr32(x, y);
100                unsigned r = gamma(SkGetPackedR32(c));
101                unsigned g = gamma(SkGetPackedG32(c));
102                unsigned b = gamma(SkGetPackedB32(c));
103                *bm.getAddr32(x, y) = SkPackARGB32(0xFF, r, g, b);
104            }
105        }
106    }
107
108    ShowMipLevels(int N) : fN(N) { }
109
110protected:
111
112    SkString onShortName() override {
113        SkString str;
114        str.printf("showmiplevels_%d", fN);
115        return str;
116    }
117
118    SkISize onISize() override {
119        return { 824, 862 };
120    }
121
122    static void DrawAndFrame(SkCanvas* canvas, const SkBitmap& orig, SkScalar x, SkScalar y) {
123        SkBitmap bm;
124        orig.copyTo(&bm);
125        apply_gamma(bm);
126
127        canvas->drawBitmap(bm, x, y, nullptr);
128        SkPaint paint;
129        paint.setStyle(SkPaint::kStroke_Style);
130        paint.setColor(0xFFFFCCCC);
131        canvas->drawRect(SkRect::MakeIWH(bm.width(), bm.height()).makeOffset(x, y).makeOutset(0.5f, 0.5f), paint);
132    }
133
134    template <typename F> void drawLevels(SkCanvas* canvas, const SkBitmap& baseBM, F func) {
135        SkScalar x = 4;
136        SkScalar y = 4;
137
138        SkPixmap prevPM;
139        baseBM.lockPixels();
140        baseBM.peekPixels(&prevPM);
141
142        SkDestinationSurfaceColorMode colorMode = SkDestinationSurfaceColorMode::kLegacy;
143        sk_sp<SkMipMap> mm(SkMipMap::Build(baseBM, colorMode, nullptr));
144
145        int index = 0;
146        SkMipMap::Level level;
147        SkScalar scale = 0.5f;
148        while (mm->extractLevel(SkSize::Make(scale, scale), &level)) {
149            SkBitmap bm = func(prevPM, level.fPixmap);
150            DrawAndFrame(canvas, bm, x, y);
151
152            if (level.fPixmap.width() <= 2 || level.fPixmap.height() <= 2) {
153                break;
154            }
155            if (index & 1) {
156                x += level.fPixmap.width() + 4;
157            } else {
158                y += level.fPixmap.height() + 4;
159            }
160            scale /= 2;
161            prevPM = level.fPixmap;
162            index += 1;
163        }
164    }
165
166    void drawSet(SkCanvas* canvas, const SkBitmap& orig) {
167        SkAutoCanvasRestore acr(canvas, true);
168
169        drawLevels(canvas, orig, [](const SkPixmap& prev, const SkPixmap& curr) {
170            SkBitmap bm;
171            bm.installPixels(curr);
172            return bm;
173        });
174
175        const SkBitmapScaler::ResizeMethod methods[] = {
176            SkBitmapScaler::RESIZE_BOX,
177            SkBitmapScaler::RESIZE_TRIANGLE,
178            SkBitmapScaler::RESIZE_LANCZOS3,
179            SkBitmapScaler::RESIZE_HAMMING,
180            SkBitmapScaler::RESIZE_MITCHELL,
181        };
182
183        SkPixmap basePM;
184        orig.lockPixels();
185        orig.peekPixels(&basePM);
186        for (auto method : methods) {
187            canvas->translate(orig.width()/2 + 8.0f, 0);
188            drawLevels(canvas, orig, [method](const SkPixmap& prev, const SkPixmap& curr) {
189                SkBitmap bm;
190                SkBitmapScaler::Resize(&bm, prev, method, curr.width(), curr.height());
191                return bm;
192            });
193        }
194    }
195
196    void onOnceBeforeDraw() override {
197        fBM[0] = sk_tool_utils::create_checkerboard_bitmap(fN, fN, SK_ColorBLACK, SK_ColorWHITE, 2);
198        fBM[1] = make_bitmap(fN, fN);
199        fBM[2] = make_bitmap2(fN, fN);
200        fBM[3] = make_bitmap3(fN, fN);
201    }
202
203    void onDraw(SkCanvas* canvas) override {
204        canvas->translate(4, 4);
205        for (const auto& bm : fBM) {
206            this->drawSet(canvas, bm);
207            canvas->translate(0, bm.height() * 0.85f);
208        }
209    }
210
211private:
212    typedef skiagm::GM INHERITED;
213};
214DEF_GM( return new ShowMipLevels(255); )
215DEF_GM( return new ShowMipLevels(256); )
216
217///////////////////////////////////////////////////////////////////////////////////////////////////
218
219void copy_to(SkBitmap* dst, SkColorType dstColorType, const SkBitmap& src) {
220    if (kGray_8_SkColorType == dstColorType) {
221        return sk_tool_utils::copy_to_g8(dst, src);
222    }
223
224    src.copyTo(dst, dstColorType);
225}
226
227/**
228 *  Show mip levels that were built, for all supported colortypes
229 */
230class ShowMipLevels2 : public skiagm::GM {
231    const int fW, fH;
232    SkBitmap  fBM[4];
233
234public:
235    ShowMipLevels2(int w, int h) : fW(w), fH(h) { }
236
237protected:
238
239    SkString onShortName() override {
240        SkString str;
241        str.printf("showmiplevels2_%dx%d", fW, fH);
242        return str;
243    }
244
245    SkISize onISize() override {
246        return { 824, 862 };
247    }
248
249    static void DrawAndFrame(SkCanvas* canvas, const SkBitmap& bm, SkScalar x, SkScalar y) {
250        canvas->drawBitmap(bm, x, y, nullptr);
251        SkPaint paint;
252        paint.setStyle(SkPaint::kStroke_Style);
253        paint.setColor(0xFFFFCCCC);
254        canvas->drawRect(SkRect::MakeIWH(bm.width(), bm.height()).makeOffset(x, y).makeOutset(0.5f, 0.5f), paint);
255    }
256
257    void drawLevels(SkCanvas* canvas, const SkBitmap& baseBM) {
258        SkScalar x = 4;
259        SkScalar y = 4;
260
261        SkDestinationSurfaceColorMode colorMode = SkDestinationSurfaceColorMode::kLegacy;
262        sk_sp<SkMipMap> mm(SkMipMap::Build(baseBM, colorMode, nullptr));
263
264        int index = 0;
265        SkMipMap::Level level;
266        SkScalar scale = 0.5f;
267        while (mm->extractLevel(SkSize::Make(scale, scale), &level)) {
268            SkBitmap bm;
269            bm.installPixels(level.fPixmap);
270            DrawAndFrame(canvas, bm, x, y);
271
272            if (level.fPixmap.width() <= 2 || level.fPixmap.height() <= 2) {
273                break;
274            }
275            if (index & 1) {
276                x += level.fPixmap.width() + 4;
277            } else {
278                y += level.fPixmap.height() + 4;
279            }
280            scale /= 2;
281            index += 1;
282        }
283    }
284
285    void drawSet(SkCanvas* canvas, const SkBitmap& orig) {
286        const SkColorType ctypes[] = {
287            kN32_SkColorType, kRGB_565_SkColorType, kARGB_4444_SkColorType, kGray_8_SkColorType
288        };
289
290        SkAutoCanvasRestore acr(canvas, true);
291
292        for (auto ctype : ctypes) {
293            SkBitmap bm;
294            copy_to(&bm, ctype, orig);
295            drawLevels(canvas, bm);
296            canvas->translate(orig.width()/2 + 8.0f, 0);
297        }
298    }
299
300    void onOnceBeforeDraw() override {
301        fBM[0] = sk_tool_utils::create_checkerboard_bitmap(fW, fH,
302                                                           SHOW_MIP_COLOR, SK_ColorWHITE, 2);
303        fBM[1] = make_bitmap(fW, fH);
304        fBM[2] = make_bitmap2(fW, fH);
305        fBM[3] = make_bitmap3(fW, fH);
306    }
307
308    void onDraw(SkCanvas* canvas) override {
309        canvas->translate(4, 4);
310        for (const auto& bm : fBM) {
311            this->drawSet(canvas, bm);
312            // round so we always produce an integral translate, so the GOLD tool won't show
313            // unimportant diffs if this is drawn on a GPU with different rounding rules
314            // since we draw the bitmaps using nearest-neighbor
315            canvas->translate(0, SkScalarRoundToScalar(bm.height() * 0.85f));
316        }
317    }
318
319private:
320    typedef skiagm::GM INHERITED;
321};
322DEF_GM( return new ShowMipLevels2(255, 255); )
323DEF_GM( return new ShowMipLevels2(256, 255); )
324DEF_GM( return new ShowMipLevels2(255, 256); )
325DEF_GM( return new ShowMipLevels2(256, 256); )
326