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