showmiplevels.cpp revision 55713afb7a531bbb6a345a42b5a25ad709d8fd19
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
10#include "Resources.h"
11#include "SkBitmapScaler.h"
12#include "SkGradientShader.h"
13#include "SkTypeface.h"
14#include "SkStream.h"
15#include "SkPaint.h"
16#include "SkMipMap.h"
17#include "Resources.h"
18#include "sk_tool_utils.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        SkSourceGammaTreatment treatment = SkSourceGammaTreatment::kIgnore;
143        SkAutoTUnref<SkMipMap> mm(SkMipMap::Build(baseBM, treatment, 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, [basePM, 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
219/**
220 *  Show mip levels that were built, for all supported colortypes
221 */
222class ShowMipLevels2 : public skiagm::GM {
223    const int fW, fH;
224    SkBitmap  fBM[4];
225
226public:
227    ShowMipLevels2(int w, int h) : fW(w), fH(h) { }
228
229protected:
230
231    SkString onShortName() override {
232        SkString str;
233        str.printf("showmiplevels2_%dx%d", fW, fH);
234        return str;
235    }
236
237    SkISize onISize() override {
238        return { 824, 862 };
239    }
240
241    static void DrawAndFrame(SkCanvas* canvas, const SkBitmap& bm, SkScalar x, SkScalar y) {
242        canvas->drawBitmap(bm, x, y, nullptr);
243        SkPaint paint;
244        paint.setStyle(SkPaint::kStroke_Style);
245        paint.setColor(0xFFFFCCCC);
246        canvas->drawRect(SkRect::MakeIWH(bm.width(), bm.height()).makeOffset(x, y).makeOutset(0.5f, 0.5f), paint);
247    }
248
249    void drawLevels(SkCanvas* canvas, const SkBitmap& baseBM) {
250        SkScalar x = 4;
251        SkScalar y = 4;
252
253        SkSourceGammaTreatment treatment = SkSourceGammaTreatment::kIgnore;
254        SkAutoTUnref<SkMipMap> mm(SkMipMap::Build(baseBM, treatment, nullptr));
255
256        int index = 0;
257        SkMipMap::Level level;
258        SkScalar scale = 0.5f;
259        while (mm->extractLevel(SkSize::Make(scale, scale), &level)) {
260            SkBitmap bm;
261            bm.installPixels(level.fPixmap);
262            DrawAndFrame(canvas, bm, x, y);
263
264            if (level.fPixmap.width() <= 2 || level.fPixmap.height() <= 2) {
265                break;
266            }
267            if (index & 1) {
268                x += level.fPixmap.width() + 4;
269            } else {
270                y += level.fPixmap.height() + 4;
271            }
272            scale /= 2;
273            index += 1;
274        }
275    }
276
277    void drawSet(SkCanvas* canvas, const SkBitmap& orig) {
278        const SkColorType ctypes[] = {
279            kN32_SkColorType, kRGB_565_SkColorType, kARGB_4444_SkColorType, kGray_8_SkColorType
280        };
281
282        SkAutoCanvasRestore acr(canvas, true);
283
284        for (auto ctype : ctypes) {
285            SkBitmap bm;
286            orig.copyTo(&bm, ctype);
287            drawLevels(canvas, bm);
288            canvas->translate(orig.width()/2 + 8.0f, 0);
289        }
290    }
291
292    void onOnceBeforeDraw() override {
293        fBM[0] = sk_tool_utils::create_checkerboard_bitmap(fW, fH,
294                                                           SHOW_MIP_COLOR, SK_ColorWHITE, 2);
295        fBM[1] = make_bitmap(fW, fH);
296        fBM[2] = make_bitmap2(fW, fH);
297        fBM[3] = make_bitmap3(fW, fH);
298    }
299
300    void onDraw(SkCanvas* canvas) override {
301        canvas->translate(4, 4);
302        for (const auto& bm : fBM) {
303            this->drawSet(canvas, bm);
304            // round so we always produce an integral translate, so the GOLD tool won't show
305            // unimportant diffs if this is drawn on a GPU with different rounding rules
306            // since we draw the bitmaps using nearest-neighbor
307            canvas->translate(0, SkScalarRoundToScalar(bm.height() * 0.85f));
308        }
309    }
310
311private:
312    typedef skiagm::GM INHERITED;
313};
314DEF_GM( return new ShowMipLevels2(255, 255); )
315DEF_GM( return new ShowMipLevels2(256, 255); )
316DEF_GM( return new ShowMipLevels2(255, 256); )
317DEF_GM( return new ShowMipLevels2(256, 256); )
318