blob: fe1a2341f6dcc10d5a2a8f664ae75390945e48c3 [file] [log] [blame]
reeda40be092016-01-14 09:11:51 -08001/*
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
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "gm/gm.h"
Ben Wagner7fde8e12019-05-01 17:28:53 -04009#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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050023#include "tools/ToolUtils.h"
reeda40be092016-01-14 09:11:51 -080024
Ben Wagner7fde8e12019-05-01 17:28:53 -040025#include <math.h>
reeda40be092016-01-14 09:11:51 -080026
reed32e0b4a2016-01-15 13:17:08 -080027#define SHOW_MIP_COLOR 0xFF000000
28
reed01dc44a2016-01-15 10:51:08 -080029static SkBitmap make_bitmap(int w, int h) {
reeda40be092016-01-14 09:11:51 -080030 SkBitmap bm;
reed01dc44a2016-01-15 10:51:08 -080031 bm.allocN32Pixels(w, h);
reeda40be092016-01-14 09:11:51 -080032 SkCanvas canvas(bm);
33 canvas.clear(0xFFFFFFFF);
34 SkPaint paint;
35 paint.setStyle(SkPaint::kStroke_Style);
reed01dc44a2016-01-15 10:51:08 -080036 paint.setStrokeWidth(w / 16.0f);
reed32e0b4a2016-01-15 13:17:08 -080037 paint.setColor(SHOW_MIP_COLOR);
reed01dc44a2016-01-15 10:51:08 -080038 canvas.drawCircle(w/2.0f, h/2.0f, w/3.0f, paint);
reeda40be092016-01-14 09:11:51 -080039 return bm;
40}
41
reed01dc44a2016-01-15 10:51:08 -080042static SkBitmap make_bitmap2(int w, int h) {
reeda40be092016-01-14 09:11:51 -080043 SkBitmap bm;
reed01dc44a2016-01-15 10:51:08 -080044 bm.allocN32Pixels(w, h);
reeda40be092016-01-14 09:11:51 -080045 SkCanvas canvas(bm);
46 canvas.clear(0xFFFFFFFF);
47 SkPaint paint;
reed32e0b4a2016-01-15 13:17:08 -080048 paint.setColor(SHOW_MIP_COLOR);
reeda40be092016-01-14 09:11:51 -080049 paint.setStyle(SkPaint::kStroke_Style);
50
51 SkScalar inset = 2;
reed01dc44a2016-01-15 10:51:08 -080052 SkRect r = SkRect::MakeIWH(w, h).makeInset(0.5f, 0.5f);
reeda40be092016-01-14 09:11:51 -080053 while (r.width() > 4) {
54 canvas.drawRect(r, paint);
55 r.inset(inset, inset);
56 inset += 1;
57 }
58 return bm;
59}
60
reed01dc44a2016-01-15 10:51:08 -080061static SkBitmap make_bitmap3(int w, int h) {
reeda40be092016-01-14 09:11:51 -080062 SkBitmap bm;
reed01dc44a2016-01-15 10:51:08 -080063 bm.allocN32Pixels(w, h);
reeda40be092016-01-14 09:11:51 -080064 SkCanvas canvas(bm);
65 canvas.clear(0xFFFFFFFF);
66 SkPaint paint;
67 paint.setStyle(SkPaint::kStroke_Style);
68 paint.setStrokeWidth(2.1f);
reed32e0b4a2016-01-15 13:17:08 -080069 paint.setColor(SHOW_MIP_COLOR);
reeda40be092016-01-14 09:11:51 -080070
reed01dc44a2016-01-15 10:51:08 -080071 SkScalar s = SkIntToScalar(w);
reeda40be092016-01-14 09:11:51 -080072 Sk4f p(s, -s, -s, s);
73 Sk4f d(5);
mtklein7c249e52016-02-21 10:54:19 -080074 while (p[1] < s) {
75 canvas.drawLine(p[0],p[1], p[2], p[3], paint);
reeda40be092016-01-14 09:11:51 -080076 p = p + d;
77 }
78 return bm;
79}
80
81class ShowMipLevels : public skiagm::GM {
82 const int fN;
83 SkBitmap fBM[4];
84
85public:
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
100 static void apply_gamma(const SkBitmap& bm) {
101 return; // below is our experiment for sRGB correction
reeda40be092016-01-14 09:11:51 -0800102 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
robertphillips55713af2016-08-26 10:04:26 -0700113 ShowMipLevels(int N) : fN(N) { }
reeda40be092016-01-14 09:11:51 -0800114
115protected:
116
117 SkString onShortName() override {
118 SkString str;
119 str.printf("showmiplevels_%d", fN);
120 return str;
121 }
122
Mike Reede32500f2017-07-19 17:20:37 -0400123 SkISize onISize() override { return { 150, 862 }; }
reeda40be092016-01-14 09:11:51 -0800124
125 static void DrawAndFrame(SkCanvas* canvas, const SkBitmap& orig, SkScalar x, SkScalar y) {
126 SkBitmap bm;
Mike Kleinea3f0142019-03-20 11:12:10 -0500127 ToolUtils::copy_to(&bm, orig.colorType(), orig);
reeda40be092016-01-14 09:11:51 -0800128 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
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;
reeda40be092016-01-14 09:11:51 -0800142 baseBM.peekPixels(&prevPM);
143
Brian Osman2b23c4b2018-06-01 12:25:08 -0400144 sk_sp<SkMipMap> mm(SkMipMap::Build(baseBM, nullptr));
reeda40be092016-01-14 09:11:51 -0800145
146 int index = 0;
147 SkMipMap::Level level;
148 SkScalar scale = 0.5f;
fmalita33ed3ad2016-02-09 08:20:18 -0800149 while (mm->extractLevel(SkSize::Make(scale, scale), &level)) {
reed67b09bf2016-01-16 18:50:35 -0800150 SkBitmap bm = func(prevPM, level.fPixmap);
reeda40be092016-01-14 09:11:51 -0800151 DrawAndFrame(canvas, bm, x, y);
152
reed67b09bf2016-01-16 18:50:35 -0800153 if (level.fPixmap.width() <= 2 || level.fPixmap.height() <= 2) {
reeda40be092016-01-14 09:11:51 -0800154 break;
155 }
156 if (index & 1) {
reed67b09bf2016-01-16 18:50:35 -0800157 x += level.fPixmap.width() + 4;
reeda40be092016-01-14 09:11:51 -0800158 } else {
reed67b09bf2016-01-16 18:50:35 -0800159 y += level.fPixmap.height() + 4;
reeda40be092016-01-14 09:11:51 -0800160 }
161 scale /= 2;
reed67b09bf2016-01-16 18:50:35 -0800162 prevPM = level.fPixmap;
reeda40be092016-01-14 09:11:51 -0800163 index += 1;
164 }
165 }
166
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 });
reeda40be092016-01-14 09:11:51 -0800175 }
176
robertphillips55713af2016-08-26 10:04:26 -0700177 void onOnceBeforeDraw() override {
Mike Kleinea3f0142019-03-20 11:12:10 -0500178 fBM[0] = ToolUtils::create_checkerboard_bitmap(fN, fN, SK_ColorBLACK, SK_ColorWHITE, 2);
robertphillips55713af2016-08-26 10:04:26 -0700179 fBM[1] = make_bitmap(fN, fN);
180 fBM[2] = make_bitmap2(fN, fN);
181 fBM[3] = make_bitmap3(fN, fN);
182 }
183
reeda40be092016-01-14 09:11:51 -0800184 void onDraw(SkCanvas* canvas) override {
185 canvas->translate(4, 4);
186 for (const auto& bm : fBM) {
187 this->drawSet(canvas, bm);
Greg Daniel7785dd22017-06-07 10:01:48 -0400188 // 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));
reeda40be092016-01-14 09:11:51 -0800192 }
193 }
halcanary9d524f22016-03-29 09:03:52 -0700194
reeda40be092016-01-14 09:11:51 -0800195private:
196 typedef skiagm::GM INHERITED;
197};
198DEF_GM( return new ShowMipLevels(255); )
199DEF_GM( return new ShowMipLevels(256); )
200
reed01dc44a2016-01-15 10:51:08 -0800201///////////////////////////////////////////////////////////////////////////////////////////////////
202
Matt Sarettcb6266b2017-01-17 10:48:53 -0500203void copy_to(SkBitmap* dst, SkColorType dstColorType, const SkBitmap& src) {
204 if (kGray_8_SkColorType == dstColorType) {
Mike Kleinea3f0142019-03-20 11:12:10 -0500205 return ToolUtils::copy_to_g8(dst, src);
Matt Sarettcb6266b2017-01-17 10:48:53 -0500206 }
207
Matt Sarett68b8e3d2017-04-28 11:15:22 -0400208 const SkBitmap* srcPtr = &src;
209 SkBitmap tmp(src);
210 if (kRGB_565_SkColorType == dstColorType) {
211 tmp.setAlphaType(kOpaque_SkAlphaType);
212 srcPtr = &tmp;
213 }
214
Mike Kleinea3f0142019-03-20 11:12:10 -0500215 ToolUtils::copy_to(dst, dstColorType, *srcPtr);
Matt Sarettcb6266b2017-01-17 10:48:53 -0500216}
217
reed01dc44a2016-01-15 10:51:08 -0800218/**
219 * Show mip levels that were built, for all supported colortypes
220 */
221class ShowMipLevels2 : public skiagm::GM {
222 const int fW, fH;
223 SkBitmap fBM[4];
224
225public:
robertphillips55713af2016-08-26 10:04:26 -0700226 ShowMipLevels2(int w, int h) : fW(w), fH(h) { }
reed01dc44a2016-01-15 10:51:08 -0800227
228protected:
229
230 SkString onShortName() override {
231 SkString str;
232 str.printf("showmiplevels2_%dx%d", fW, fH);
233 return str;
234 }
235
236 SkISize onISize() override {
237 return { 824, 862 };
238 }
239
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
248 void drawLevels(SkCanvas* canvas, const SkBitmap& baseBM) {
249 SkScalar x = 4;
250 SkScalar y = 4;
251
Brian Osman2b23c4b2018-06-01 12:25:08 -0400252 sk_sp<SkMipMap> mm(SkMipMap::Build(baseBM, nullptr));
reed01dc44a2016-01-15 10:51:08 -0800253
254 int index = 0;
255 SkMipMap::Level level;
256 SkScalar scale = 0.5f;
fmalita33ed3ad2016-02-09 08:20:18 -0800257 while (mm->extractLevel(SkSize::Make(scale, scale), &level)) {
reed01dc44a2016-01-15 10:51:08 -0800258 SkBitmap bm;
reed67b09bf2016-01-16 18:50:35 -0800259 bm.installPixels(level.fPixmap);
reed01dc44a2016-01-15 10:51:08 -0800260 DrawAndFrame(canvas, bm, x, y);
261
reed67b09bf2016-01-16 18:50:35 -0800262 if (level.fPixmap.width() <= 2 || level.fPixmap.height() <= 2) {
reed01dc44a2016-01-15 10:51:08 -0800263 break;
264 }
265 if (index & 1) {
reed67b09bf2016-01-16 18:50:35 -0800266 x += level.fPixmap.width() + 4;
reed01dc44a2016-01-15 10:51:08 -0800267 } else {
reed67b09bf2016-01-16 18:50:35 -0800268 y += level.fPixmap.height() + 4;
reed01dc44a2016-01-15 10:51:08 -0800269 }
270 scale /= 2;
271 index += 1;
272 }
273 }
274
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;
Matt Sarettcb6266b2017-01-17 10:48:53 -0500284 copy_to(&bm, ctype, orig);
reed01dc44a2016-01-15 10:51:08 -0800285 drawLevels(canvas, bm);
286 canvas->translate(orig.width()/2 + 8.0f, 0);
287 }
288 }
289
robertphillips55713af2016-08-26 10:04:26 -0700290 void onOnceBeforeDraw() override {
Mike Kleinea3f0142019-03-20 11:12:10 -0500291 fBM[0] = ToolUtils::create_checkerboard_bitmap(fW, fH, SHOW_MIP_COLOR, SK_ColorWHITE, 2);
robertphillips55713af2016-08-26 10:04:26 -0700292 fBM[1] = make_bitmap(fW, fH);
293 fBM[2] = make_bitmap2(fW, fH);
294 fBM[3] = make_bitmap3(fW, fH);
295 }
296
reed01dc44a2016-01-15 10:51:08 -0800297 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 }
halcanary9d524f22016-03-29 09:03:52 -0700307
reed01dc44a2016-01-15 10:51:08 -0800308private:
309 typedef skiagm::GM INHERITED;
310};
311DEF_GM( return new ShowMipLevels2(255, 255); )
312DEF_GM( return new ShowMipLevels2(256, 255); )
313DEF_GM( return new ShowMipLevels2(255, 256); )
314DEF_GM( return new ShowMipLevels2(256, 256); )