1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2013 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h" 9cb93a386Sopenharmony_ci#include "include/utils/SkRandom.h" 10cb93a386Sopenharmony_ci#include "src/core/SkMipmap.h" 11cb93a386Sopenharmony_ci#include "tests/Test.h" 12cb93a386Sopenharmony_ci#include "tools/Resources.h" 13cb93a386Sopenharmony_ci 14cb93a386Sopenharmony_cistatic void make_bitmap(SkBitmap* bm, int width, int height) { 15cb93a386Sopenharmony_ci bm->allocN32Pixels(width, height); 16cb93a386Sopenharmony_ci bm->eraseColor(SK_ColorWHITE); 17cb93a386Sopenharmony_ci} 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_ciDEF_TEST(MipMap, reporter) { 20cb93a386Sopenharmony_ci SkBitmap bm; 21cb93a386Sopenharmony_ci SkRandom rand; 22cb93a386Sopenharmony_ci 23cb93a386Sopenharmony_ci for (int i = 0; i < 500; ++i) { 24cb93a386Sopenharmony_ci int width = 1 + rand.nextU() % 1000; 25cb93a386Sopenharmony_ci int height = 1 + rand.nextU() % 1000; 26cb93a386Sopenharmony_ci make_bitmap(&bm, width, height); 27cb93a386Sopenharmony_ci sk_sp<SkMipmap> mm(SkMipmap::Build(bm, nullptr)); 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, mm->countLevels() == SkMipmap::ComputeLevelCount(width, height)); 30cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !mm->extractLevel(SkSize::Make(SK_Scalar1, SK_Scalar1), 31cb93a386Sopenharmony_ci nullptr)); 32cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !mm->extractLevel(SkSize::Make(SK_Scalar1 * 2, SK_Scalar1 * 2), 33cb93a386Sopenharmony_ci nullptr)); 34cb93a386Sopenharmony_ci 35cb93a386Sopenharmony_ci SkMipmap::Level prevLevel; 36cb93a386Sopenharmony_ci sk_bzero(&prevLevel, sizeof(prevLevel)); 37cb93a386Sopenharmony_ci 38cb93a386Sopenharmony_ci SkScalar scale = SK_Scalar1; 39cb93a386Sopenharmony_ci for (int j = 0; j < 30; ++j) { 40cb93a386Sopenharmony_ci scale = scale * 2 / 3; 41cb93a386Sopenharmony_ci 42cb93a386Sopenharmony_ci SkMipmap::Level level; 43cb93a386Sopenharmony_ci if (mm->extractLevel(SkSize::Make(scale, scale), &level)) { 44cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, level.fPixmap.addr()); 45cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, level.fPixmap.width() > 0); 46cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, level.fPixmap.height() > 0); 47cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, (int)level.fPixmap.rowBytes() >= level.fPixmap.width() * 4); 48cb93a386Sopenharmony_ci 49cb93a386Sopenharmony_ci if (prevLevel.fPixmap.addr()) { 50cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, level.fPixmap.width() <= prevLevel.fPixmap.width()); 51cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, level.fPixmap.height() <= prevLevel.fPixmap.height()); 52cb93a386Sopenharmony_ci } 53cb93a386Sopenharmony_ci prevLevel = level; 54cb93a386Sopenharmony_ci } 55cb93a386Sopenharmony_ci } 56cb93a386Sopenharmony_ci } 57cb93a386Sopenharmony_ci} 58cb93a386Sopenharmony_ci 59cb93a386Sopenharmony_cistatic void test_mipmap_generation(int width, int height, int expectedMipLevelCount, 60cb93a386Sopenharmony_ci skiatest::Reporter* reporter) { 61cb93a386Sopenharmony_ci SkBitmap bm; 62cb93a386Sopenharmony_ci bm.allocN32Pixels(width, height); 63cb93a386Sopenharmony_ci bm.eraseColor(SK_ColorWHITE); 64cb93a386Sopenharmony_ci sk_sp<SkMipmap> mm(SkMipmap::Build(bm, nullptr)); 65cb93a386Sopenharmony_ci 66cb93a386Sopenharmony_ci const int mipLevelCount = mm->countLevels(); 67cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, mipLevelCount == expectedMipLevelCount); 68cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, mipLevelCount == SkMipmap::ComputeLevelCount(width, height)); 69cb93a386Sopenharmony_ci for (int i = 0; i < mipLevelCount; ++i) { 70cb93a386Sopenharmony_ci SkMipmap::Level level; 71cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, mm->getLevel(i, &level)); 72cb93a386Sopenharmony_ci // Make sure the mipmaps contain valid data and that the sizes are correct 73cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, level.fPixmap.addr()); 74cb93a386Sopenharmony_ci SkISize size = SkMipmap::ComputeLevelSize(width, height, i); 75cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, level.fPixmap.width() == size.width()); 76cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, level.fPixmap.height() == size.height()); 77cb93a386Sopenharmony_ci 78cb93a386Sopenharmony_ci // + 1 because SkMipmap does not include the base mipmap level. 79cb93a386Sopenharmony_ci int twoToTheMipLevel = 1 << (i + 1); 80cb93a386Sopenharmony_ci int currentWidth = width / twoToTheMipLevel; 81cb93a386Sopenharmony_ci int currentHeight = height / twoToTheMipLevel; 82cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, level.fPixmap.width() == currentWidth); 83cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, level.fPixmap.height() == currentHeight); 84cb93a386Sopenharmony_ci } 85cb93a386Sopenharmony_ci} 86cb93a386Sopenharmony_ci 87cb93a386Sopenharmony_ciDEF_TEST(MipMap_DirectLevelAccess, reporter) { 88cb93a386Sopenharmony_ci // create mipmap with invalid size 89cb93a386Sopenharmony_ci { 90cb93a386Sopenharmony_ci // SkMipmap current requires the dimensions be greater than 2x2 91cb93a386Sopenharmony_ci SkBitmap bm; 92cb93a386Sopenharmony_ci bm.allocN32Pixels(1, 1); 93cb93a386Sopenharmony_ci bm.eraseColor(SK_ColorWHITE); 94cb93a386Sopenharmony_ci sk_sp<SkMipmap> mm(SkMipmap::Build(bm, nullptr)); 95cb93a386Sopenharmony_ci 96cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, mm == nullptr); 97cb93a386Sopenharmony_ci } 98cb93a386Sopenharmony_ci 99cb93a386Sopenharmony_ci // check small mipmap's count and levels 100cb93a386Sopenharmony_ci // There should be 5 mipmap levels generated: 101cb93a386Sopenharmony_ci // 16x16, 8x8, 4x4, 2x2, 1x1 102cb93a386Sopenharmony_ci test_mipmap_generation(32, 32, 5, reporter); 103cb93a386Sopenharmony_ci 104cb93a386Sopenharmony_ci // check large mipmap's count and levels 105cb93a386Sopenharmony_ci // There should be 9 mipmap levels generated: 106cb93a386Sopenharmony_ci // 500x500, 250x250, 125x125, 62x62, 31x31, 15x15, 7x7, 3x3, 1x1 107cb93a386Sopenharmony_ci test_mipmap_generation(1000, 1000, 9, reporter); 108cb93a386Sopenharmony_ci} 109cb93a386Sopenharmony_ci 110cb93a386Sopenharmony_cistruct LevelCountScenario { 111cb93a386Sopenharmony_ci int fWidth; 112cb93a386Sopenharmony_ci int fHeight; 113cb93a386Sopenharmony_ci int fExpectedLevelCount; 114cb93a386Sopenharmony_ci}; 115cb93a386Sopenharmony_ci 116cb93a386Sopenharmony_ciDEF_TEST(MipMap_ComputeLevelCount, reporter) { 117cb93a386Sopenharmony_ci const LevelCountScenario tests[] = { 118cb93a386Sopenharmony_ci // Test mipmaps with negative sizes 119cb93a386Sopenharmony_ci {-100, 100, 0}, 120cb93a386Sopenharmony_ci {100, -100, 0}, 121cb93a386Sopenharmony_ci {-100, -100, 0}, 122cb93a386Sopenharmony_ci 123cb93a386Sopenharmony_ci // Test mipmaps with 0, 1, 2 as dimensions 124cb93a386Sopenharmony_ci // (SkMipmap::Build requires a min size of 1) 125cb93a386Sopenharmony_ci // 126cb93a386Sopenharmony_ci // 0 127cb93a386Sopenharmony_ci {0, 100, 0}, 128cb93a386Sopenharmony_ci {100, 0, 0}, 129cb93a386Sopenharmony_ci {0, 0, 0}, 130cb93a386Sopenharmony_ci // 1 131cb93a386Sopenharmony_ci {1, 100, 6}, 132cb93a386Sopenharmony_ci {100, 1, 6}, 133cb93a386Sopenharmony_ci {1, 1, 0}, 134cb93a386Sopenharmony_ci // 2 135cb93a386Sopenharmony_ci {2, 100, 6}, 136cb93a386Sopenharmony_ci {100, 2, 6}, 137cb93a386Sopenharmony_ci {2, 2, 1}, 138cb93a386Sopenharmony_ci 139cb93a386Sopenharmony_ci // Test a handful of boundaries such as 63x63 and 64x64 140cb93a386Sopenharmony_ci {63, 63, 5}, 141cb93a386Sopenharmony_ci {64, 64, 6}, 142cb93a386Sopenharmony_ci {127, 127, 6}, 143cb93a386Sopenharmony_ci {128, 128, 7}, 144cb93a386Sopenharmony_ci {255, 255, 7}, 145cb93a386Sopenharmony_ci {256, 256, 8}, 146cb93a386Sopenharmony_ci 147cb93a386Sopenharmony_ci // Test different dimensions, such as 256x64 148cb93a386Sopenharmony_ci {64, 129, 7}, 149cb93a386Sopenharmony_ci {255, 32, 7}, 150cb93a386Sopenharmony_ci {500, 1000, 9} 151cb93a386Sopenharmony_ci }; 152cb93a386Sopenharmony_ci 153cb93a386Sopenharmony_ci for (auto& currentTest : tests) { 154cb93a386Sopenharmony_ci int levelCount = SkMipmap::ComputeLevelCount(currentTest.fWidth, currentTest.fHeight); 155cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, currentTest.fExpectedLevelCount == levelCount); 156cb93a386Sopenharmony_ci } 157cb93a386Sopenharmony_ci} 158cb93a386Sopenharmony_ci 159cb93a386Sopenharmony_cistruct LevelSizeScenario { 160cb93a386Sopenharmony_ci int fBaseWidth; 161cb93a386Sopenharmony_ci int fBaseHeight; 162cb93a386Sopenharmony_ci int fLevel; 163cb93a386Sopenharmony_ci SkISize fExpectedMipMapLevelSize; 164cb93a386Sopenharmony_ci}; 165cb93a386Sopenharmony_ci 166cb93a386Sopenharmony_ciDEF_TEST(MipMap_ComputeLevelSize, reporter) { 167cb93a386Sopenharmony_ci const LevelSizeScenario tests[] = { 168cb93a386Sopenharmony_ci // Test mipmaps with negative sizes 169cb93a386Sopenharmony_ci {-100, 100, 0, SkISize::Make(0, 0)}, 170cb93a386Sopenharmony_ci {100, -100, 0, SkISize::Make(0, 0)}, 171cb93a386Sopenharmony_ci {-100, -100, 0, SkISize::Make(0, 0)}, 172cb93a386Sopenharmony_ci 173cb93a386Sopenharmony_ci // Test mipmaps with 0, 1, 2 as dimensions 174cb93a386Sopenharmony_ci // (SkMipmap::Build requires a min size of 1) 175cb93a386Sopenharmony_ci // 176cb93a386Sopenharmony_ci // 0 177cb93a386Sopenharmony_ci {0, 100, 0, SkISize::Make(0, 0)}, 178cb93a386Sopenharmony_ci {100, 0, 0, SkISize::Make(0, 0)}, 179cb93a386Sopenharmony_ci {0, 0, 0, SkISize::Make(0, 0)}, 180cb93a386Sopenharmony_ci // 1 181cb93a386Sopenharmony_ci 182cb93a386Sopenharmony_ci {1, 100, 0, SkISize::Make(1, 50)}, 183cb93a386Sopenharmony_ci {100, 1, 0, SkISize::Make(50, 1)}, 184cb93a386Sopenharmony_ci {1, 1, 0, SkISize::Make(0, 0)}, 185cb93a386Sopenharmony_ci // 2 186cb93a386Sopenharmony_ci {2, 100, 0, SkISize::Make(1, 50)}, 187cb93a386Sopenharmony_ci {100, 2, 1, SkISize::Make(25, 1)}, 188cb93a386Sopenharmony_ci {2, 2, 0, SkISize::Make(1, 1)}, 189cb93a386Sopenharmony_ci 190cb93a386Sopenharmony_ci // Test a handful of cases 191cb93a386Sopenharmony_ci {63, 63, 2, SkISize::Make(7, 7)}, 192cb93a386Sopenharmony_ci {64, 64, 2, SkISize::Make(8, 8)}, 193cb93a386Sopenharmony_ci {127, 127, 2, SkISize::Make(15, 15)}, 194cb93a386Sopenharmony_ci {64, 129, 3, SkISize::Make(4, 8)}, 195cb93a386Sopenharmony_ci {255, 32, 6, SkISize::Make(1, 1)}, 196cb93a386Sopenharmony_ci {500, 1000, 1, SkISize::Make(125, 250)}, 197cb93a386Sopenharmony_ci }; 198cb93a386Sopenharmony_ci 199cb93a386Sopenharmony_ci for (auto& currentTest : tests) { 200cb93a386Sopenharmony_ci SkISize levelSize = SkMipmap::ComputeLevelSize(currentTest.fBaseWidth, 201cb93a386Sopenharmony_ci currentTest.fBaseHeight, 202cb93a386Sopenharmony_ci currentTest.fLevel); 203cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, currentTest.fExpectedMipMapLevelSize == levelSize); 204cb93a386Sopenharmony_ci } 205cb93a386Sopenharmony_ci} 206cb93a386Sopenharmony_ci 207cb93a386Sopenharmony_ciDEF_TEST(MipMap_F16, reporter) { 208cb93a386Sopenharmony_ci SkBitmap bmp; 209cb93a386Sopenharmony_ci bmp.allocPixels(SkImageInfo::Make(10, 10, kRGBA_F16_SkColorType, kPremul_SkAlphaType)); 210cb93a386Sopenharmony_ci bmp.eraseColor(0); 211cb93a386Sopenharmony_ci sk_sp<SkMipmap> mipmap(SkMipmap::Build(bmp, nullptr)); 212cb93a386Sopenharmony_ci} 213cb93a386Sopenharmony_ci 214cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 215cb93a386Sopenharmony_ci#include "include/core/SkSurface.h" 216cb93a386Sopenharmony_ci#include "src/core/SkMipmapBuilder.h" 217cb93a386Sopenharmony_ci 218cb93a386Sopenharmony_cistatic void fill_in_mips(SkMipmapBuilder* builder, sk_sp<SkImage> img) { 219cb93a386Sopenharmony_ci int count = builder->countLevels(); 220cb93a386Sopenharmony_ci for (int i = 0; i < count; ++i) { 221cb93a386Sopenharmony_ci SkPixmap pm = builder->level(i); 222cb93a386Sopenharmony_ci auto surf = SkSurface::MakeRasterDirect(pm); 223cb93a386Sopenharmony_ci surf->getCanvas()->drawImageRect(img, SkRect::MakeIWH(pm.width(), pm.height()), 224cb93a386Sopenharmony_ci SkSamplingOptions()); 225cb93a386Sopenharmony_ci } 226cb93a386Sopenharmony_ci} 227cb93a386Sopenharmony_ci 228cb93a386Sopenharmony_ciDEF_TEST(image_mip_factory, reporter) { 229cb93a386Sopenharmony_ci // TODO: what do to about lazy images and mipmaps? 230cb93a386Sopenharmony_ci auto img = GetResourceAsImage("images/mandrill_128.png")->makeRasterImage(); 231cb93a386Sopenharmony_ci 232cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, !img->hasMipmaps()); 233cb93a386Sopenharmony_ci auto img1 = img->withDefaultMipmaps(); 234cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, img.get() != img1.get()); 235cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, img1->hasMipmaps()); 236cb93a386Sopenharmony_ci 237cb93a386Sopenharmony_ci SkMipmapBuilder builder(img->imageInfo()); 238cb93a386Sopenharmony_ci fill_in_mips(&builder, img); 239cb93a386Sopenharmony_ci 240cb93a386Sopenharmony_ci auto img2 = builder.attachTo(img); 241cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, img.get() != img2.get()); 242cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, img1.get() != img2.get()); 243cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, img2->hasMipmaps()); 244cb93a386Sopenharmony_ci} 245cb93a386Sopenharmony_ci 246cb93a386Sopenharmony_ci// Ensure we can't attach mips that don't "match" the image 247cb93a386Sopenharmony_ci// 248cb93a386Sopenharmony_ciDEF_TEST(image_mip_mismatch, reporter) { 249cb93a386Sopenharmony_ci auto check_fails = [reporter](sk_sp<SkImage> img, const SkImageInfo& info) { 250cb93a386Sopenharmony_ci SkMipmapBuilder builder(info); 251cb93a386Sopenharmony_ci fill_in_mips(&builder, img); 252cb93a386Sopenharmony_ci auto img2 = builder.attachTo(img); 253cb93a386Sopenharmony_ci // if withMipmaps() succeeds, it returns a new image, otherwise it returns the original 254cb93a386Sopenharmony_ci REPORTER_ASSERT(reporter, img.get() == img2.get()); 255cb93a386Sopenharmony_ci }; 256cb93a386Sopenharmony_ci 257cb93a386Sopenharmony_ci auto img = GetResourceAsImage("images/mandrill_128.png")->makeRasterImage(); 258cb93a386Sopenharmony_ci 259cb93a386Sopenharmony_ci // check size, colortype, and alphatype 260cb93a386Sopenharmony_ci 261cb93a386Sopenharmony_ci check_fails(img, img->imageInfo().makeWH(img->width() + 2, img->height() - 3)); 262cb93a386Sopenharmony_ci 263cb93a386Sopenharmony_ci SkASSERT(img->imageInfo().colorType() != kRGB_565_SkColorType); 264cb93a386Sopenharmony_ci check_fails(img, img->imageInfo().makeColorType(kRGB_565_SkColorType)); 265cb93a386Sopenharmony_ci 266cb93a386Sopenharmony_ci SkASSERT(img->imageInfo().alphaType() != kUnpremul_SkAlphaType); 267cb93a386Sopenharmony_ci check_fails(img, img->imageInfo().makeAlphaType(kUnpremul_SkAlphaType)); 268cb93a386Sopenharmony_ci} 269