Flutter Engine
The Flutter Engine
MipMapTest.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2013 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
16#include "include/core/SkRect.h"
20#include "include/core/SkSize.h"
24#include "src/base/SkRandom.h"
25#include "src/core/SkMipmap.h"
27#include "tests/Test.h"
28#include "tools/DecodeUtils.h"
29
30static void make_bitmap(SkBitmap* bm, int width, int height) {
33}
34
36 SkBitmap bm;
37 SkRandom rand;
38
39 for (int i = 0; i < 500; ++i) {
40 int width = 1 + rand.nextU() % 1000;
41 int height = 1 + rand.nextU() % 1000;
43 sk_sp<SkMipmap> mm(SkMipmap::Build(bm, nullptr));
45 if (!mm) {
46 return;
47 }
48
51 nullptr));
53 nullptr));
54
55 SkMipmap::Level prevLevel;
56 sk_bzero(&prevLevel, sizeof(prevLevel));
57
59 for (int j = 0; j < 30; ++j) {
60 scale = scale * 2 / 3;
61
64 REPORTER_ASSERT(reporter, level.fPixmap.addr());
65 REPORTER_ASSERT(reporter, level.fPixmap.width() > 0);
66 REPORTER_ASSERT(reporter, level.fPixmap.height() > 0);
67 REPORTER_ASSERT(reporter, (int)level.fPixmap.rowBytes() >= level.fPixmap.width() * 4);
68
69 if (prevLevel.fPixmap.addr()) {
70 REPORTER_ASSERT(reporter, level.fPixmap.width() <= prevLevel.fPixmap.width());
71 REPORTER_ASSERT(reporter, level.fPixmap.height() <= prevLevel.fPixmap.height());
72 }
73 prevLevel = level;
74 }
75 }
76 }
77}
78
79static void test_mipmap_generation(int width, int height, int expectedMipLevelCount,
81 SkBitmap bm;
84 sk_sp<SkMipmap> mm(SkMipmap::Build(bm, nullptr));
86 if (!mm) {
87 return;
88 }
89
90 const int mipLevelCount = mm->countLevels();
91 REPORTER_ASSERT(reporter, mipLevelCount == expectedMipLevelCount);
93 for (int i = 0; i < mipLevelCount; ++i) {
96 // Make sure the mipmaps contain valid data and that the sizes are correct
97 REPORTER_ASSERT(reporter, level.fPixmap.addr());
99 REPORTER_ASSERT(reporter, level.fPixmap.width() == size.width());
100 REPORTER_ASSERT(reporter, level.fPixmap.height() == size.height());
101
102 // + 1 because SkMipmap does not include the base mipmap level.
103 int twoToTheMipLevel = 1 << (i + 1);
104 int currentWidth = width / twoToTheMipLevel;
105 int currentHeight = height / twoToTheMipLevel;
106 REPORTER_ASSERT(reporter, level.fPixmap.width() == currentWidth);
107 REPORTER_ASSERT(reporter, level.fPixmap.height() == currentHeight);
108 }
109}
110
111DEF_TEST(MipMap_DirectLevelAccess, reporter) {
112 // create mipmap with invalid size
113 {
114 // SkMipmap current requires the dimensions be greater than 2x2
115 SkBitmap bm;
116 bm.allocN32Pixels(1, 1);
118 sk_sp<SkMipmap> mm(SkMipmap::Build(bm, nullptr));
119
120 REPORTER_ASSERT(reporter, mm == nullptr);
121 }
122
123 // check small mipmap's count and levels
124 // There should be 5 mipmap levels generated:
125 // 16x16, 8x8, 4x4, 2x2, 1x1
127
128 // check large mipmap's count and levels
129 // There should be 9 mipmap levels generated:
130 // 500x500, 250x250, 125x125, 62x62, 31x31, 15x15, 7x7, 3x3, 1x1
131 test_mipmap_generation(1000, 1000, 9, reporter);
132}
133
138};
139
140DEF_TEST(MipMap_ComputeLevelCount, reporter) {
141 const LevelCountScenario tests[] = {
142 // Test mipmaps with negative sizes
143 {-100, 100, 0},
144 {100, -100, 0},
145 {-100, -100, 0},
146
147 // Test mipmaps with 0, 1, 2 as dimensions
148 // (SkMipmap::Build requires a min size of 1)
149 //
150 // 0
151 {0, 100, 0},
152 {100, 0, 0},
153 {0, 0, 0},
154 // 1
155 {1, 100, 6},
156 {100, 1, 6},
157 {1, 1, 0},
158 // 2
159 {2, 100, 6},
160 {100, 2, 6},
161 {2, 2, 1},
162
163 // Test a handful of boundaries such as 63x63 and 64x64
164 {63, 63, 5},
165 {64, 64, 6},
166 {127, 127, 6},
167 {128, 128, 7},
168 {255, 255, 7},
169 {256, 256, 8},
170
171 // Test different dimensions, such as 256x64
172 {64, 129, 7},
173 {255, 32, 7},
174 {500, 1000, 9}
175 };
176
177 for (auto& currentTest : tests) {
178 int levelCount = SkMipmap::ComputeLevelCount(currentTest.fWidth, currentTest.fHeight);
179 REPORTER_ASSERT(reporter, currentTest.fExpectedLevelCount == levelCount);
180 }
181}
182
188};
189
190DEF_TEST(MipMap_ComputeLevelSize, reporter) {
191 const LevelSizeScenario tests[] = {
192 // Test mipmaps with negative sizes
193 {-100, 100, 0, SkISize::Make(0, 0)},
194 {100, -100, 0, SkISize::Make(0, 0)},
195 {-100, -100, 0, SkISize::Make(0, 0)},
196
197 // Test mipmaps with 0, 1, 2 as dimensions
198 // (SkMipmap::Build requires a min size of 1)
199 //
200 // 0
201 {0, 100, 0, SkISize::Make(0, 0)},
202 {100, 0, 0, SkISize::Make(0, 0)},
203 {0, 0, 0, SkISize::Make(0, 0)},
204 // 1
205
206 {1, 100, 0, SkISize::Make(1, 50)},
207 {100, 1, 0, SkISize::Make(50, 1)},
208 {1, 1, 0, SkISize::Make(0, 0)},
209 // 2
210 {2, 100, 0, SkISize::Make(1, 50)},
211 {100, 2, 1, SkISize::Make(25, 1)},
212 {2, 2, 0, SkISize::Make(1, 1)},
213
214 // Test a handful of cases
215 {63, 63, 2, SkISize::Make(7, 7)},
216 {64, 64, 2, SkISize::Make(8, 8)},
217 {127, 127, 2, SkISize::Make(15, 15)},
218 {64, 129, 3, SkISize::Make(4, 8)},
219 {255, 32, 6, SkISize::Make(1, 1)},
220 {500, 1000, 1, SkISize::Make(125, 250)},
221 };
222
223 for (auto& currentTest : tests) {
224 SkISize levelSize = SkMipmap::ComputeLevelSize(currentTest.fBaseWidth,
225 currentTest.fBaseHeight,
226 currentTest.fLevel);
227 REPORTER_ASSERT(reporter, currentTest.fExpectedMipMapLevelSize == levelSize);
228 }
229}
230
231DEF_TEST(MipMap_F16, reporter) {
232 SkBitmap bmp;
234 bmp.eraseColor(0);
235 sk_sp<SkMipmap> mipmap(SkMipmap::Build(bmp, nullptr));
236}
237
239 int count = builder->countLevels();
240 for (int i = 0; i < count; ++i) {
241 SkPixmap pm = builder->level(i);
242 auto surf = SkSurfaces::WrapPixels(pm);
243 surf->getCanvas()->drawImageRect(img, SkRect::MakeIWH(pm.width(), pm.height()),
245 }
246}
247
248DEF_TEST(image_mip_factory, reporter) {
249 // TODO: what do to about lazy images and mipmaps?
250 auto img = ToolUtils::GetResourceAsImage("images/mandrill_128.png")->makeRasterImage();
251
252 REPORTER_ASSERT(reporter, !img->hasMipmaps());
253 auto img1 = img->withDefaultMipmaps();
254 REPORTER_ASSERT(reporter, img.get() != img1.get());
255 REPORTER_ASSERT(reporter, img1->hasMipmaps());
256
257 SkMipmapBuilder builder(img->imageInfo());
258 fill_in_mips(&builder, img);
259
260 auto img2 = builder.attachTo(img);
261 REPORTER_ASSERT(reporter, img.get() != img2.get());
262 REPORTER_ASSERT(reporter, img1.get() != img2.get());
263 REPORTER_ASSERT(reporter, img2->hasMipmaps());
264}
265
266// Ensure we can't attach mips that don't "match" the image
267//
268DEF_TEST(image_mip_mismatch, reporter) {
269 auto check_fails = [reporter](sk_sp<SkImage> img, const SkImageInfo& info) {
271 fill_in_mips(&builder, img);
272 auto img2 = builder.attachTo(img);
273 // if withMipmaps() succeeds, it returns a new image, otherwise it returns the original
274 REPORTER_ASSERT(reporter, img.get() == img2.get());
275 };
276
277 auto img = ToolUtils::GetResourceAsImage("images/mandrill_128.png")->makeRasterImage();
278
279 // check size, colortype, and alphatype
280
281 check_fails(img, img->imageInfo().makeWH(img->width() + 2, img->height() - 3));
282
284 check_fails(img, img->imageInfo().makeColorType(kRGB_565_SkColorType));
285
287 check_fails(img, img->imageInfo().makeAlphaType(kUnpremul_SkAlphaType));
288}
static BlurTest tests[]
Definition: BlurTest.cpp:84
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
sk_bzero(glyphs, sizeof(glyphs))
reporter
Definition: FontMgrTest.cpp:39
int count
Definition: FontMgrTest.cpp:50
static void make_bitmap(SkBitmap *bm, int width, int height)
Definition: MipMapTest.cpp:30
static void test_mipmap_generation(int width, int height, int expectedMipLevelCount, skiatest::Reporter *reporter)
Definition: MipMapTest.cpp:79
static void fill_in_mips(SkMipmapBuilder *builder, sk_sp< SkImage > img)
Definition: MipMapTest.cpp:238
DEF_TEST(MipMap, reporter)
Definition: MipMapTest.cpp:35
kUnpremul_SkAlphaType
@ kPremul_SkAlphaType
pixel components are premultiplied by alpha
Definition: SkAlphaType.h:29
#define SkASSERT(cond)
Definition: SkAssert.h:116
@ kRGBA_F16_SkColorType
pixel with half floats for red, green, blue, alpha;
Definition: SkColorType.h:38
@ kRGB_565_SkColorType
pixel with 5 bits red, 6 bits green, 5 bits blue, in 16-bit word
Definition: SkColorType.h:22
constexpr SkColor SK_ColorWHITE
Definition: SkColor.h:122
#define SK_Scalar1
Definition: SkScalar.h:18
#define REPORTER_ASSERT(r, cond,...)
Definition: Test.h:286
void allocPixels(const SkImageInfo &info, size_t rowBytes)
Definition: SkBitmap.cpp:258
void allocN32Pixels(int width, int height, bool isOpaque=false)
Definition: SkBitmap.cpp:232
void eraseColor(SkColor4f) const
Definition: SkBitmap.cpp:442
sk_sp< SkImage > makeRasterImage(GrDirectContext *, CachingHint cachingHint=kDisallow_CachingHint) const
Definition: SkImage.cpp:267
const SkImageInfo & imageInfo() const
Definition: SkImage.h:279
int width() const
Definition: SkImage.h:285
int height() const
Definition: SkImage.h:291
static SkMipmap * Build(const SkPixmap &src, SkDiscardableFactoryProc, bool computeContents=true)
Definition: SkMipmap.cpp:45
static SkISize ComputeLevelSize(int baseWidth, int baseHeight, int level)
Definition: SkMipmap.cpp:168
bool extractLevel(SkSize scale, Level *) const
Definition: SkMipmap.cpp:220
int countLevels() const
Definition: SkMipmap.cpp:276
bool getLevel(int index, Level *) const
Definition: SkMipmap.cpp:280
static int ComputeLevelCount(int baseWidth, int baseHeight)
Definition: SkMipmap.cpp:134
int width() const
Definition: SkPixmap.h:160
const void * addr() const
Definition: SkPixmap.h:153
int height() const
Definition: SkPixmap.h:166
uint32_t nextU()
Definition: SkRandom.h:42
T * get() const
Definition: SkRefCnt.h:303
float SkScalar
Definition: extension.cpp:12
SK_API sk_sp< SkSurface > WrapPixels(const SkImageInfo &imageInfo, void *pixels, size_t rowBytes, const SkSurfaceProps *surfaceProps=nullptr)
sk_sp< SkImage > GetResourceAsImage(const char *resource)
Definition: DecodeUtils.h:25
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
int32_t height
int32_t width
const Scalar scale
SkISize fExpectedMipMapLevelSize
Definition: MipMapTest.cpp:187
Definition: SkSize.h:16
static constexpr SkISize Make(int32_t w, int32_t h)
Definition: SkSize.h:20
SkImageInfo makeWH(int newWidth, int newHeight) const
Definition: SkImageInfo.h:444
SkImageInfo makeAlphaType(SkAlphaType newAlphaType) const
Definition: SkImageInfo.h:466
static SkImageInfo Make(int width, int height, SkColorType ct, SkAlphaType at)
SkAlphaType alphaType() const
Definition: SkImageInfo.h:375
SkColorType colorType() const
Definition: SkImageInfo.h:373
SkImageInfo makeColorType(SkColorType newColorType) const
Definition: SkImageInfo.h:475
SkPixmap fPixmap
Definition: SkMipmap.h:71
static SkRect MakeIWH(int w, int h)
Definition: SkRect.h:623
static constexpr SkSize Make(SkScalar w, SkScalar h)
Definition: SkSize.h:56