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 "SkColorPriv.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 
make_bitmap(int w,int h)22 static 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 
make_bitmap2(int w,int h)35 static 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"
make_bitmap3(int w,int h)55 static 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 
75 class ShowMipLevels : public skiagm::GM {
76     const int fN;
77     SkBitmap  fBM[4];
78 
79 public:
gamma(unsigned n)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 
apply_gamma(const SkBitmap & bm)94     static void apply_gamma(const SkBitmap& bm) {
95         return; // below is our experiment for sRGB correction
96         for (int y = 0; y < bm.height(); ++y) {
97             for (int x = 0; x < bm.width(); ++x) {
98                 SkPMColor c = *bm.getAddr32(x, y);
99                 unsigned r = gamma(SkGetPackedR32(c));
100                 unsigned g = gamma(SkGetPackedG32(c));
101                 unsigned b = gamma(SkGetPackedB32(c));
102                 *bm.getAddr32(x, y) = SkPackARGB32(0xFF, r, g, b);
103             }
104         }
105     }
106 
ShowMipLevels(int N)107     ShowMipLevels(int N) : fN(N) { }
108 
109 protected:
110 
onShortName()111     SkString onShortName() override {
112         SkString str;
113         str.printf("showmiplevels_%d", fN);
114         return str;
115     }
116 
onISize()117     SkISize onISize() override { return { 150, 862 }; }
118 
DrawAndFrame(SkCanvas * canvas,const SkBitmap & orig,SkScalar x,SkScalar y)119     static void DrawAndFrame(SkCanvas* canvas, const SkBitmap& orig, SkScalar x, SkScalar y) {
120         SkBitmap bm;
121         sk_tool_utils::copy_to(&bm, orig.colorType(), orig);
122         apply_gamma(bm);
123 
124         canvas->drawBitmap(bm, x, y, nullptr);
125         SkPaint paint;
126         paint.setStyle(SkPaint::kStroke_Style);
127         paint.setColor(0xFFFFCCCC);
128         canvas->drawRect(SkRect::MakeIWH(bm.width(), bm.height()).makeOffset(x, y).makeOutset(0.5f, 0.5f), paint);
129     }
130 
drawLevels(SkCanvas * canvas,const SkBitmap & baseBM,F func)131     template <typename F> void drawLevels(SkCanvas* canvas, const SkBitmap& baseBM, F func) {
132         SkScalar x = 4;
133         SkScalar y = 4;
134 
135         SkPixmap prevPM;
136         baseBM.peekPixels(&prevPM);
137 
138         sk_sp<SkMipMap> mm(SkMipMap::Build(baseBM, nullptr));
139 
140         int index = 0;
141         SkMipMap::Level level;
142         SkScalar scale = 0.5f;
143         while (mm->extractLevel(SkSize::Make(scale, scale), &level)) {
144             SkBitmap bm = func(prevPM, level.fPixmap);
145             DrawAndFrame(canvas, bm, x, y);
146 
147             if (level.fPixmap.width() <= 2 || level.fPixmap.height() <= 2) {
148                 break;
149             }
150             if (index & 1) {
151                 x += level.fPixmap.width() + 4;
152             } else {
153                 y += level.fPixmap.height() + 4;
154             }
155             scale /= 2;
156             prevPM = level.fPixmap;
157             index += 1;
158         }
159     }
160 
drawSet(SkCanvas * canvas,const SkBitmap & orig)161     void drawSet(SkCanvas* canvas, const SkBitmap& orig) {
162         SkAutoCanvasRestore acr(canvas, true);
163 
164         drawLevels(canvas, orig, [](const SkPixmap& prev, const SkPixmap& curr) {
165             SkBitmap bm;
166             bm.installPixels(curr);
167             return bm;
168         });
169     }
170 
onOnceBeforeDraw()171     void onOnceBeforeDraw() override {
172         fBM[0] = sk_tool_utils::create_checkerboard_bitmap(fN, fN, SK_ColorBLACK, SK_ColorWHITE, 2);
173         fBM[1] = make_bitmap(fN, fN);
174         fBM[2] = make_bitmap2(fN, fN);
175         fBM[3] = make_bitmap3(fN, fN);
176     }
177 
onDraw(SkCanvas * canvas)178     void onDraw(SkCanvas* canvas) override {
179         canvas->translate(4, 4);
180         for (const auto& bm : fBM) {
181             this->drawSet(canvas, bm);
182             // round so we always produce an integral translate, so the GOLD tool won't show
183             // unimportant diffs if this is drawn on a GPU with different rounding rules
184             // since we draw the bitmaps using nearest-neighbor
185             canvas->translate(0, SkScalarRoundToScalar(bm.height() * 0.85f));
186         }
187     }
188 
189 private:
190     typedef skiagm::GM INHERITED;
191 };
192 DEF_GM( return new ShowMipLevels(255); )
193 DEF_GM( return new ShowMipLevels(256); )
194 
195 ///////////////////////////////////////////////////////////////////////////////////////////////////
196 
copy_to(SkBitmap * dst,SkColorType dstColorType,const SkBitmap & src)197 void copy_to(SkBitmap* dst, SkColorType dstColorType, const SkBitmap& src) {
198     if (kGray_8_SkColorType == dstColorType) {
199         return sk_tool_utils::copy_to_g8(dst, src);
200     }
201 
202     const SkBitmap* srcPtr = &src;
203     SkBitmap tmp(src);
204     if (kRGB_565_SkColorType == dstColorType) {
205         tmp.setAlphaType(kOpaque_SkAlphaType);
206         srcPtr = &tmp;
207     }
208 
209     sk_tool_utils::copy_to(dst, dstColorType, *srcPtr);
210 }
211 
212 /**
213  *  Show mip levels that were built, for all supported colortypes
214  */
215 class ShowMipLevels2 : public skiagm::GM {
216     const int fW, fH;
217     SkBitmap  fBM[4];
218 
219 public:
ShowMipLevels2(int w,int h)220     ShowMipLevels2(int w, int h) : fW(w), fH(h) { }
221 
222 protected:
223 
onShortName()224     SkString onShortName() override {
225         SkString str;
226         str.printf("showmiplevels2_%dx%d", fW, fH);
227         return str;
228     }
229 
onISize()230     SkISize onISize() override {
231         return { 824, 862 };
232     }
233 
DrawAndFrame(SkCanvas * canvas,const SkBitmap & bm,SkScalar x,SkScalar y)234     static void DrawAndFrame(SkCanvas* canvas, const SkBitmap& bm, SkScalar x, SkScalar y) {
235         canvas->drawBitmap(bm, x, y, nullptr);
236         SkPaint paint;
237         paint.setStyle(SkPaint::kStroke_Style);
238         paint.setColor(0xFFFFCCCC);
239         canvas->drawRect(SkRect::MakeIWH(bm.width(), bm.height()).makeOffset(x, y).makeOutset(0.5f, 0.5f), paint);
240     }
241 
drawLevels(SkCanvas * canvas,const SkBitmap & baseBM)242     void drawLevels(SkCanvas* canvas, const SkBitmap& baseBM) {
243         SkScalar x = 4;
244         SkScalar y = 4;
245 
246         sk_sp<SkMipMap> mm(SkMipMap::Build(baseBM, nullptr));
247 
248         int index = 0;
249         SkMipMap::Level level;
250         SkScalar scale = 0.5f;
251         while (mm->extractLevel(SkSize::Make(scale, scale), &level)) {
252             SkBitmap bm;
253             bm.installPixels(level.fPixmap);
254             DrawAndFrame(canvas, bm, x, y);
255 
256             if (level.fPixmap.width() <= 2 || level.fPixmap.height() <= 2) {
257                 break;
258             }
259             if (index & 1) {
260                 x += level.fPixmap.width() + 4;
261             } else {
262                 y += level.fPixmap.height() + 4;
263             }
264             scale /= 2;
265             index += 1;
266         }
267     }
268 
drawSet(SkCanvas * canvas,const SkBitmap & orig)269     void drawSet(SkCanvas* canvas, const SkBitmap& orig) {
270         const SkColorType ctypes[] = {
271             kN32_SkColorType, kRGB_565_SkColorType, kARGB_4444_SkColorType, kGray_8_SkColorType
272         };
273 
274         SkAutoCanvasRestore acr(canvas, true);
275 
276         for (auto ctype : ctypes) {
277             SkBitmap bm;
278             copy_to(&bm, ctype, orig);
279             drawLevels(canvas, bm);
280             canvas->translate(orig.width()/2 + 8.0f, 0);
281         }
282     }
283 
onOnceBeforeDraw()284     void onOnceBeforeDraw() override {
285         fBM[0] = sk_tool_utils::create_checkerboard_bitmap(fW, fH,
286                                                            SHOW_MIP_COLOR, SK_ColorWHITE, 2);
287         fBM[1] = make_bitmap(fW, fH);
288         fBM[2] = make_bitmap2(fW, fH);
289         fBM[3] = make_bitmap3(fW, fH);
290     }
291 
onDraw(SkCanvas * canvas)292     void onDraw(SkCanvas* canvas) override {
293         canvas->translate(4, 4);
294         for (const auto& bm : fBM) {
295             this->drawSet(canvas, bm);
296             // round so we always produce an integral translate, so the GOLD tool won't show
297             // unimportant diffs if this is drawn on a GPU with different rounding rules
298             // since we draw the bitmaps using nearest-neighbor
299             canvas->translate(0, SkScalarRoundToScalar(bm.height() * 0.85f));
300         }
301     }
302 
303 private:
304     typedef skiagm::GM INHERITED;
305 };
306 DEF_GM( return new ShowMipLevels2(255, 255); )
307 DEF_GM( return new ShowMipLevels2(256, 255); )
308 DEF_GM( return new ShowMipLevels2(255, 256); )
309 DEF_GM( return new ShowMipLevels2(256, 256); )
310