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/gm.h"
9 #include "include/core/SkBitmap.h"
10 #include "include/core/SkCanvas.h"
11 #include "include/core/SkColor.h"
12 #include "include/core/SkColorPriv.h"
13 #include "include/core/SkImageInfo.h"
14 #include "include/core/SkPaint.h"
15 #include "include/core/SkPixmap.h"
16 #include "include/core/SkRect.h"
17 #include "include/core/SkRefCnt.h"
18 #include "include/core/SkScalar.h"
19 #include "include/core/SkSize.h"
20 #include "include/core/SkString.h"
21 #include "include/private/SkNx.h"
22 #include "src/core/SkMipmap.h"
23 #include "tools/ToolUtils.h"
24 
25 #include <math.h>
26 
27 #define SHOW_MIP_COLOR  0xFF000000
28 
make_bitmap(int w,int h)29 static SkBitmap make_bitmap(int w, int h) {
30     SkBitmap bm;
31     bm.allocN32Pixels(w, h);
32     SkCanvas canvas(bm);
33     canvas.clear(0xFFFFFFFF);
34     SkPaint paint;
35     paint.setStyle(SkPaint::kStroke_Style);
36     paint.setStrokeWidth(w / 16.0f);
37     paint.setColor(SHOW_MIP_COLOR);
38     canvas.drawCircle(w/2.0f, h/2.0f, w/3.0f, paint);
39     return bm;
40 }
41 
make_bitmap2(int w,int h)42 static SkBitmap make_bitmap2(int w, int h) {
43     SkBitmap bm;
44     bm.allocN32Pixels(w, h);
45     SkCanvas canvas(bm);
46     canvas.clear(0xFFFFFFFF);
47     SkPaint paint;
48     paint.setColor(SHOW_MIP_COLOR);
49     paint.setStyle(SkPaint::kStroke_Style);
50 
51     SkScalar inset = 2;
52     SkRect r = SkRect::MakeIWH(w, h).makeInset(0.5f, 0.5f);
53     while (r.width() > 4) {
54         canvas.drawRect(r, paint);
55         r.inset(inset, inset);
56         inset += 1;
57     }
58     return bm;
59 }
60 
make_bitmap3(int w,int h)61 static SkBitmap make_bitmap3(int w, int h) {
62     SkBitmap bm;
63     bm.allocN32Pixels(w, h);
64     SkCanvas canvas(bm);
65     canvas.clear(0xFFFFFFFF);
66     SkPaint paint;
67     paint.setStyle(SkPaint::kStroke_Style);
68     paint.setStrokeWidth(2.1f);
69     paint.setColor(SHOW_MIP_COLOR);
70 
71     SkScalar s = SkIntToScalar(w);
72     Sk4f p(s, -s, -s, s);
73     Sk4f d(5);
74     while (p[1] < s) {
75         canvas.drawLine(p[0],p[1], p[2], p[3], paint);
76         p = p + d;
77     }
78     return bm;
79 }
80 
81 class ShowMipLevels : public skiagm::GM {
82     const int fN;
83     SkBitmap  fBM[4];
84 
85 public:
gamma(unsigned n)86     static unsigned gamma(unsigned n) {
87         float x = n / 255.0f;
88 #if 0
89         x = sqrtf(x);
90 #else
91         if (x > 0.0031308f) {
92             x = 1.055f * (powf(x, (1.0f / 2.4f))) - 0.055f;
93         } else {
94             x = 12.92f * x;
95         }
96 #endif
97         return (int)(x * 255);
98     }
99 
apply_gamma(const SkBitmap & bm)100     static void apply_gamma(const SkBitmap& bm) {
101         return; // below is our experiment for sRGB correction
102         for (int y = 0; y < bm.height(); ++y) {
103             for (int x = 0; x < bm.width(); ++x) {
104                 SkPMColor c = *bm.getAddr32(x, y);
105                 unsigned r = gamma(SkGetPackedR32(c));
106                 unsigned g = gamma(SkGetPackedG32(c));
107                 unsigned b = gamma(SkGetPackedB32(c));
108                 *bm.getAddr32(x, y) = SkPackARGB32(0xFF, r, g, b);
109             }
110         }
111     }
112 
ShowMipLevels(int N)113     ShowMipLevels(int N) : fN(N) { }
114 
115 protected:
116 
onShortName()117     SkString onShortName() override {
118         SkString str;
119         str.printf("showmiplevels_%d", fN);
120         return str;
121     }
122 
onISize()123     SkISize onISize() override { return { 150, 862 }; }
124 
DrawAndFrame(SkCanvas * canvas,const SkBitmap & orig,SkScalar x,SkScalar y)125     static void DrawAndFrame(SkCanvas* canvas, const SkBitmap& orig, SkScalar x, SkScalar y) {
126         SkBitmap bm;
127         ToolUtils::copy_to(&bm, orig.colorType(), orig);
128         apply_gamma(bm);
129 
130         canvas->drawBitmap(bm, x, y, nullptr);
131         SkPaint paint;
132         paint.setStyle(SkPaint::kStroke_Style);
133         paint.setColor(0xFFFFCCCC);
134         canvas->drawRect(SkRect::MakeIWH(bm.width(), bm.height()).makeOffset(x, y).makeOutset(0.5f, 0.5f), paint);
135     }
136 
drawLevels(SkCanvas * canvas,const SkBitmap & baseBM,F func)137     template <typename F> void drawLevels(SkCanvas* canvas, const SkBitmap& baseBM, F func) {
138         SkScalar x = 4;
139         SkScalar y = 4;
140 
141         SkPixmap prevPM;
142         baseBM.peekPixels(&prevPM);
143 
144         sk_sp<SkMipmap> mm(SkMipmap::Build(baseBM, nullptr));
145 
146         int index = 0;
147         SkMipmap::Level level;
148         SkScalar scale = 0.5f;
149         while (mm->extractLevel(SkSize::Make(scale, scale), &level)) {
150             SkBitmap bm = func(prevPM, level.fPixmap);
151             DrawAndFrame(canvas, bm, x, y);
152 
153             if (level.fPixmap.width() <= 2 || level.fPixmap.height() <= 2) {
154                 break;
155             }
156             if (index & 1) {
157                 x += level.fPixmap.width() + 4;
158             } else {
159                 y += level.fPixmap.height() + 4;
160             }
161             scale /= 2;
162             prevPM = level.fPixmap;
163             index += 1;
164         }
165     }
166 
drawSet(SkCanvas * canvas,const SkBitmap & orig)167     void drawSet(SkCanvas* canvas, const SkBitmap& orig) {
168         SkAutoCanvasRestore acr(canvas, true);
169 
170         drawLevels(canvas, orig, [](const SkPixmap& prev, const SkPixmap& curr) {
171             SkBitmap bm;
172             bm.installPixels(curr);
173             return bm;
174         });
175     }
176 
onOnceBeforeDraw()177     void onOnceBeforeDraw() override {
178         fBM[0] = ToolUtils::create_checkerboard_bitmap(fN, fN, SK_ColorBLACK, SK_ColorWHITE, 2);
179         fBM[1] = make_bitmap(fN, fN);
180         fBM[2] = make_bitmap2(fN, fN);
181         fBM[3] = make_bitmap3(fN, fN);
182     }
183 
onDraw(SkCanvas * canvas)184     void onDraw(SkCanvas* canvas) override {
185         canvas->translate(4, 4);
186         for (const auto& bm : fBM) {
187             this->drawSet(canvas, bm);
188             // round so we always produce an integral translate, so the GOLD tool won't show
189             // unimportant diffs if this is drawn on a GPU with different rounding rules
190             // since we draw the bitmaps using nearest-neighbor
191             canvas->translate(0, SkScalarRoundToScalar(bm.height() * 0.85f));
192         }
193     }
194 
195 private:
196     using INHERITED = skiagm::GM;
197 };
198 DEF_GM( return new ShowMipLevels(255); )
199 DEF_GM( return new ShowMipLevels(256); )
200 
201 ///////////////////////////////////////////////////////////////////////////////////////////////////
202 
copy_to(SkBitmap * dst,SkColorType dstColorType,const SkBitmap & src)203 void copy_to(SkBitmap* dst, SkColorType dstColorType, const SkBitmap& src) {
204     if (kGray_8_SkColorType == dstColorType) {
205         return ToolUtils::copy_to_g8(dst, src);
206     }
207 
208     const SkBitmap* srcPtr = &src;
209     SkBitmap tmp(src);
210     if (kRGB_565_SkColorType == dstColorType) {
211         tmp.setAlphaType(kOpaque_SkAlphaType);
212         srcPtr = &tmp;
213     }
214 
215     ToolUtils::copy_to(dst, dstColorType, *srcPtr);
216 }
217 
218 /**
219  *  Show mip levels that were built, for all supported colortypes
220  */
221 class ShowMipLevels2 : public skiagm::GM {
222     const int fW, fH;
223     SkBitmap  fBM[4];
224 
225 public:
ShowMipLevels2(int w,int h)226     ShowMipLevels2(int w, int h) : fW(w), fH(h) { }
227 
228 protected:
229 
onShortName()230     SkString onShortName() override {
231         SkString str;
232         str.printf("showmiplevels2_%dx%d", fW, fH);
233         return str;
234     }
235 
onISize()236     SkISize onISize() override {
237         return { 824, 862 };
238     }
239 
DrawAndFrame(SkCanvas * canvas,const SkBitmap & bm,SkScalar x,SkScalar y)240     static void DrawAndFrame(SkCanvas* canvas, const SkBitmap& bm, SkScalar x, SkScalar y) {
241         canvas->drawBitmap(bm, x, y, nullptr);
242         SkPaint paint;
243         paint.setStyle(SkPaint::kStroke_Style);
244         paint.setColor(0xFFFFCCCC);
245         canvas->drawRect(SkRect::MakeIWH(bm.width(), bm.height()).makeOffset(x, y).makeOutset(0.5f, 0.5f), paint);
246     }
247 
drawLevels(SkCanvas * canvas,const SkBitmap & baseBM)248     void drawLevels(SkCanvas* canvas, const SkBitmap& baseBM) {
249         SkScalar x = 4;
250         SkScalar y = 4;
251 
252         sk_sp<SkMipmap> mm(SkMipmap::Build(baseBM, nullptr));
253 
254         int index = 0;
255         SkMipmap::Level level;
256         SkScalar scale = 0.5f;
257         while (mm->extractLevel(SkSize::Make(scale, scale), &level)) {
258             SkBitmap bm;
259             bm.installPixels(level.fPixmap);
260             DrawAndFrame(canvas, bm, x, y);
261 
262             if (level.fPixmap.width() <= 2 || level.fPixmap.height() <= 2) {
263                 break;
264             }
265             if (index & 1) {
266                 x += level.fPixmap.width() + 4;
267             } else {
268                 y += level.fPixmap.height() + 4;
269             }
270             scale /= 2;
271             index += 1;
272         }
273     }
274 
drawSet(SkCanvas * canvas,const SkBitmap & orig)275     void drawSet(SkCanvas* canvas, const SkBitmap& orig) {
276         const SkColorType ctypes[] = {
277             kN32_SkColorType, kRGB_565_SkColorType, kARGB_4444_SkColorType, kGray_8_SkColorType
278         };
279 
280         SkAutoCanvasRestore acr(canvas, true);
281 
282         for (auto ctype : ctypes) {
283             SkBitmap bm;
284             copy_to(&bm, ctype, orig);
285             drawLevels(canvas, bm);
286             canvas->translate(orig.width()/2 + 8.0f, 0);
287         }
288     }
289 
onOnceBeforeDraw()290     void onOnceBeforeDraw() override {
291         fBM[0] = ToolUtils::create_checkerboard_bitmap(fW, fH, SHOW_MIP_COLOR, SK_ColorWHITE, 2);
292         fBM[1] = make_bitmap(fW, fH);
293         fBM[2] = make_bitmap2(fW, fH);
294         fBM[3] = make_bitmap3(fW, fH);
295     }
296 
onDraw(SkCanvas * canvas)297     void onDraw(SkCanvas* canvas) override {
298         canvas->translate(4, 4);
299         for (const auto& bm : fBM) {
300             this->drawSet(canvas, bm);
301             // round so we always produce an integral translate, so the GOLD tool won't show
302             // unimportant diffs if this is drawn on a GPU with different rounding rules
303             // since we draw the bitmaps using nearest-neighbor
304             canvas->translate(0, SkScalarRoundToScalar(bm.height() * 0.85f));
305         }
306     }
307 
308 private:
309     using INHERITED = skiagm::GM;
310 };
311 DEF_GM( return new ShowMipLevels2(255, 255); )
312 DEF_GM( return new ShowMipLevels2(256, 255); )
313 DEF_GM( return new ShowMipLevels2(255, 256); )
314 DEF_GM( return new ShowMipLevels2(256, 256); )
315 
316 #include "tools/Resources.h"
317 
318 class ShowMipLevels3 : public skiagm::GM {
319     sk_sp<SkImage> fImg;
320 
onShortName()321     SkString onShortName() override { return SkString("showmiplevels_explicit"); }
322 
onISize()323     SkISize onISize() override { return {1130, 970}; }
324 
onOnceBeforeDraw()325     void onOnceBeforeDraw() override {
326         fImg = GetResourceAsImage("images/ship.png");
327         fImg = fImg->makeRasterImage(); // makeWithMips only works on raster for now
328 
329         const SkColor colors[] = { SK_ColorRED, SK_ColorGREEN, SK_ColorBLUE };
330 
331         SkMipmapBuilder builder(fImg->imageInfo());
332         for (int i = 0; i < builder.countLevels(); ++i) {
333             auto surf = SkSurface::MakeRasterDirect(builder.level(i));
334             surf->getCanvas()->drawColor(colors[i % SK_ARRAY_COUNT(colors)]);
335         }
336         fImg = builder.attachTo(fImg.get());
337     }
338 
onDraw(SkCanvas * canvas,SkString *)339     DrawResult onDraw(SkCanvas* canvas, SkString*) override {
340         if (canvas->recordingContext()) {
341             // mips not supported yet
342             return DrawResult::kSkip;
343         }
344 
345         canvas->drawColor(0xFFDDDDDD);
346 
347         canvas->translate(10, 10);
348         for (auto mm : {SkMipmapMode::kNone, SkMipmapMode::kNearest, SkMipmapMode::kLinear}) {
349             for (auto sa : {SkSamplingMode::kNearest, SkSamplingMode::kLinear}) {
350                 canvas->translate(0, draw_downscaling(canvas, {sa, mm}));
351             }
352         }
353         return DrawResult::kOk;
354     }
355 
356 private:
draw_downscaling(SkCanvas * canvas,SkFilterOptions options)357     SkScalar draw_downscaling(SkCanvas* canvas, SkFilterOptions options) {
358         SkAutoCanvasRestore acr(canvas, true);
359 
360         SkPaint paint;
361         SkRect r = {0, 0, 150, 150};
362         for (float scale = 1; scale >= 0.1f; scale *= 0.7f) {
363             SkMatrix matrix = SkMatrix::Scale(scale, scale);
364             paint.setShader(fImg->makeShader(SkTileMode::kRepeat, SkTileMode::kRepeat,
365                                              options, &matrix));
366             canvas->drawRect(r, paint);
367             canvas->translate(r.width() + 10, 0);
368         }
369         return r.height() + 10;
370     }
371 
372     using INHERITED = skiagm::GM;
373 };
374 DEF_GM( return new ShowMipLevels3; )
375