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 typedef skiagm::GM INHERITED;
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 typedef skiagm::GM INHERITED;
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