SkMipMap.cpp revision 6644d9353f3f0c09914385fd762e073f98d54205
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 8#include "SkMipMap.h" 9#include "SkBitmap.h" 10#include "SkColorPriv.h" 11#include "SkHalf.h" 12#include "SkMathPriv.h" 13#include "SkNx.h" 14#include "SkPM4fPriv.h" 15#include "SkTypes.h" 16 17// 18// ColorTypeFilter is the "Type" we pass to some downsample template functions. 19// It controls how we expand a pixel into a large type, with space between each component, 20// so we can then perform our simple filter (either box or triangle) and store the intermediates 21// in the expanded type. 22// 23 24struct ColorTypeFilter_8888 { 25 typedef uint32_t Type; 26#if defined(SKNX_IS_FAST) 27 static Sk4h Expand(uint32_t x) { 28 return SkNx_cast<uint16_t>(Sk4b::Load(&x)); 29 } 30 static uint32_t Compact(const Sk4h& x) { 31 uint32_t r; 32 SkNx_cast<uint8_t>(x).store(&r); 33 return r; 34 } 35#else 36 static uint64_t Expand(uint32_t x) { 37 return (x & 0xFF00FF) | ((uint64_t)(x & 0xFF00FF00) << 24); 38 } 39 static uint32_t Compact(uint64_t x) { 40 return (uint32_t)((x & 0xFF00FF) | ((x >> 24) & 0xFF00FF00)); 41 } 42#endif 43}; 44 45struct ColorTypeFilter_S32 { 46 typedef uint32_t Type; 47 static Sk4f Expand(uint32_t x) { 48 return Sk4f_fromS32(x); 49 } 50 static uint32_t Compact(const Sk4f& x) { 51 return Sk4f_toS32(x); 52 } 53}; 54 55struct ColorTypeFilter_565 { 56 typedef uint16_t Type; 57 static uint32_t Expand(uint16_t x) { 58 return (x & ~SK_G16_MASK_IN_PLACE) | ((x & SK_G16_MASK_IN_PLACE) << 16); 59 } 60 static uint16_t Compact(uint32_t x) { 61 return (x & ~SK_G16_MASK_IN_PLACE) | ((x >> 16) & SK_G16_MASK_IN_PLACE); 62 } 63}; 64 65struct ColorTypeFilter_4444 { 66 typedef uint16_t Type; 67 static uint32_t Expand(uint16_t x) { 68 return (x & 0xF0F) | ((x & ~0xF0F) << 12); 69 } 70 static uint16_t Compact(uint32_t x) { 71 return (x & 0xF0F) | ((x >> 12) & ~0xF0F); 72 } 73}; 74 75struct ColorTypeFilter_8 { 76 typedef uint8_t Type; 77 static unsigned Expand(unsigned x) { 78 return x; 79 } 80 static uint8_t Compact(unsigned x) { 81 return (uint8_t)x; 82 } 83}; 84 85struct ColorTypeFilter_F16 { 86 typedef uint64_t Type; // SkHalf x4 87 static Sk4f Expand(uint64_t x) { 88 return SkHalfToFloat_01(x); 89 } 90 static uint64_t Compact(const Sk4f& x) { 91 return SkFloatToHalf_01(x); 92 } 93}; 94 95template <typename T> T add_121(const T& a, const T& b, const T& c) { 96 return a + b + b + c; 97} 98 99template <typename T> T shift_right(const T& x, int bits) { 100 return x >> bits; 101} 102 103Sk4f shift_right(const Sk4f& x, int bits) { 104 return x * (1.0f / (1 << bits)); 105} 106 107template <typename T> T shift_left(const T& x, int bits) { 108 return x << bits; 109} 110 111Sk4f shift_left(const Sk4f& x, int bits) { 112 return x * (1 << bits); 113} 114 115// 116// To produce each mip level, we need to filter down by 1/2 (e.g. 100x100 -> 50,50) 117// If the starting dimension is odd, we floor the size of the lower level (e.g. 101 -> 50) 118// In those (odd) cases, we use a triangle filter, with 1-pixel overlap between samplings, 119// else for even cases, we just use a 2x box filter. 120// 121// This produces 4 possible isotropic filters: 2x2 2x3 3x2 3x3 where WxH indicates the number of 122// src pixels we need to sample in each dimension to produce 1 dst pixel. 123// 124// OpenGL expects a full mipmap stack to contain anisotropic space as well. 125// This means a 100x1 image would continue down to a 50x1 image, 25x1 image... 126// Because of this, we need 4 more anisotropic filters: 1x2, 1x3, 2x1, 3x1. 127 128template <typename F> void downsample_1_2(void* dst, const void* src, size_t srcRB, int count) { 129 SkASSERT(count > 0); 130 auto p0 = static_cast<const typename F::Type*>(src); 131 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); 132 auto d = static_cast<typename F::Type*>(dst); 133 134 for (int i = 0; i < count; ++i) { 135 auto c00 = F::Expand(p0[0]); 136 auto c10 = F::Expand(p1[0]); 137 138 auto c = c00 + c10; 139 d[i] = F::Compact(shift_right(c, 1)); 140 p0 += 2; 141 p1 += 2; 142 } 143} 144 145template <typename F> void downsample_1_3(void* dst, const void* src, size_t srcRB, int count) { 146 SkASSERT(count > 0); 147 auto p0 = static_cast<const typename F::Type*>(src); 148 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); 149 auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); 150 auto d = static_cast<typename F::Type*>(dst); 151 152 for (int i = 0; i < count; ++i) { 153 auto c00 = F::Expand(p0[0]); 154 auto c10 = F::Expand(p1[0]); 155 auto c20 = F::Expand(p2[0]); 156 157 auto c = add_121(c00, c10, c20); 158 d[i] = F::Compact(shift_right(c, 2)); 159 p0 += 2; 160 p1 += 2; 161 p2 += 2; 162 } 163} 164 165template <typename F> void downsample_2_1(void* dst, const void* src, size_t srcRB, int count) { 166 SkASSERT(count > 0); 167 auto p0 = static_cast<const typename F::Type*>(src); 168 auto d = static_cast<typename F::Type*>(dst); 169 170 for (int i = 0; i < count; ++i) { 171 auto c00 = F::Expand(p0[0]); 172 auto c01 = F::Expand(p0[1]); 173 174 auto c = c00 + c01; 175 d[i] = F::Compact(shift_right(c, 1)); 176 p0 += 2; 177 } 178} 179 180template <typename F> void downsample_2_2(void* dst, const void* src, size_t srcRB, int count) { 181 SkASSERT(count > 0); 182 auto p0 = static_cast<const typename F::Type*>(src); 183 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); 184 auto d = static_cast<typename F::Type*>(dst); 185 186 for (int i = 0; i < count; ++i) { 187 auto c00 = F::Expand(p0[0]); 188 auto c01 = F::Expand(p0[1]); 189 auto c10 = F::Expand(p1[0]); 190 auto c11 = F::Expand(p1[1]); 191 192 auto c = c00 + c10 + c01 + c11; 193 d[i] = F::Compact(shift_right(c, 2)); 194 p0 += 2; 195 p1 += 2; 196 } 197} 198 199template <typename F> void downsample_2_3(void* dst, const void* src, size_t srcRB, int count) { 200 SkASSERT(count > 0); 201 auto p0 = static_cast<const typename F::Type*>(src); 202 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); 203 auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); 204 auto d = static_cast<typename F::Type*>(dst); 205 206 for (int i = 0; i < count; ++i) { 207 auto c00 = F::Expand(p0[0]); 208 auto c01 = F::Expand(p0[1]); 209 auto c10 = F::Expand(p1[0]); 210 auto c11 = F::Expand(p1[1]); 211 auto c20 = F::Expand(p2[0]); 212 auto c21 = F::Expand(p2[1]); 213 214 auto c = add_121(c00, c10, c20) + add_121(c01, c11, c21); 215 d[i] = F::Compact(shift_right(c, 3)); 216 p0 += 2; 217 p1 += 2; 218 p2 += 2; 219 } 220} 221 222template <typename F> void downsample_3_1(void* dst, const void* src, size_t srcRB, int count) { 223 SkASSERT(count > 0); 224 auto p0 = static_cast<const typename F::Type*>(src); 225 auto d = static_cast<typename F::Type*>(dst); 226 227 auto c02 = F::Expand(p0[0]); 228 for (int i = 0; i < count; ++i) { 229 auto c00 = c02; 230 auto c01 = F::Expand(p0[1]); 231 c02 = F::Expand(p0[2]); 232 233 auto c = add_121(c00, c01, c02); 234 d[i] = F::Compact(shift_right(c, 2)); 235 p0 += 2; 236 } 237} 238 239template <typename F> void downsample_3_2(void* dst, const void* src, size_t srcRB, int count) { 240 SkASSERT(count > 0); 241 auto p0 = static_cast<const typename F::Type*>(src); 242 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); 243 auto d = static_cast<typename F::Type*>(dst); 244 245 auto c02 = F::Expand(p0[0]); 246 auto c12 = F::Expand(p1[0]); 247 for (int i = 0; i < count; ++i) { 248 auto c00 = c02; 249 auto c01 = F::Expand(p0[1]); 250 c02 = F::Expand(p0[2]); 251 auto c10 = c12; 252 auto c11 = F::Expand(p1[1]); 253 c12 = F::Expand(p1[2]); 254 255 auto c = add_121(c00, c01, c02) + add_121(c10, c11, c12); 256 d[i] = F::Compact(shift_right(c, 3)); 257 p0 += 2; 258 p1 += 2; 259 } 260} 261 262template <typename F> void downsample_3_3(void* dst, const void* src, size_t srcRB, int count) { 263 SkASSERT(count > 0); 264 auto p0 = static_cast<const typename F::Type*>(src); 265 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); 266 auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); 267 auto d = static_cast<typename F::Type*>(dst); 268 269 auto c02 = F::Expand(p0[0]); 270 auto c12 = F::Expand(p1[0]); 271 auto c22 = F::Expand(p2[0]); 272 for (int i = 0; i < count; ++i) { 273 auto c00 = c02; 274 auto c01 = F::Expand(p0[1]); 275 c02 = F::Expand(p0[2]); 276 auto c10 = c12; 277 auto c11 = F::Expand(p1[1]); 278 c12 = F::Expand(p1[2]); 279 auto c20 = c22; 280 auto c21 = F::Expand(p2[1]); 281 c22 = F::Expand(p2[2]); 282 283 auto c = 284 add_121(c00, c01, c02) + 285 shift_left(add_121(c10, c11, c12), 1) + 286 add_121(c20, c21, c22); 287 d[i] = F::Compact(shift_right(c, 4)); 288 p0 += 2; 289 p1 += 2; 290 p2 += 2; 291 } 292} 293 294/////////////////////////////////////////////////////////////////////////////////////////////////// 295 296size_t SkMipMap::AllocLevelsSize(int levelCount, size_t pixelSize) { 297 if (levelCount < 0) { 298 return 0; 299 } 300 int64_t size = sk_64_mul(levelCount + 1, sizeof(Level)) + pixelSize; 301 if (!sk_64_isS32(size)) { 302 return 0; 303 } 304 return sk_64_asS32(size); 305} 306 307static bool treat_like_srgb(const SkImageInfo& info) { 308 if (info.colorSpace()) { 309 return SkColorSpace::k2Dot2Curve_GammaNamed == info.colorSpace()->gammaNamed(); 310 } else { 311 return kSRGB_SkColorProfileType == info.profileType(); 312 } 313} 314 315SkMipMap* SkMipMap::Build(const SkPixmap& src, SkSourceGammaTreatment treatment, 316 SkDiscardableFactoryProc fact) { 317 typedef void FilterProc(void*, const void* srcPtr, size_t srcRB, int count); 318 319 FilterProc* proc_1_2 = nullptr; 320 FilterProc* proc_1_3 = nullptr; 321 FilterProc* proc_2_1 = nullptr; 322 FilterProc* proc_2_2 = nullptr; 323 FilterProc* proc_2_3 = nullptr; 324 FilterProc* proc_3_1 = nullptr; 325 FilterProc* proc_3_2 = nullptr; 326 FilterProc* proc_3_3 = nullptr; 327 328 const SkColorType ct = src.colorType(); 329 const SkAlphaType at = src.alphaType(); 330 const bool srgbGamma = (SkSourceGammaTreatment::kRespect == treatment) 331 && treat_like_srgb(src.info()); 332 333 switch (ct) { 334 case kRGBA_8888_SkColorType: 335 case kBGRA_8888_SkColorType: 336 if (srgbGamma) { 337 proc_1_2 = downsample_1_2<ColorTypeFilter_S32>; 338 proc_1_3 = downsample_1_3<ColorTypeFilter_S32>; 339 proc_2_1 = downsample_2_1<ColorTypeFilter_S32>; 340 proc_2_2 = downsample_2_2<ColorTypeFilter_S32>; 341 proc_2_3 = downsample_2_3<ColorTypeFilter_S32>; 342 proc_3_1 = downsample_3_1<ColorTypeFilter_S32>; 343 proc_3_2 = downsample_3_2<ColorTypeFilter_S32>; 344 proc_3_3 = downsample_3_3<ColorTypeFilter_S32>; 345 } else { 346 proc_1_2 = downsample_1_2<ColorTypeFilter_8888>; 347 proc_1_3 = downsample_1_3<ColorTypeFilter_8888>; 348 proc_2_1 = downsample_2_1<ColorTypeFilter_8888>; 349 proc_2_2 = downsample_2_2<ColorTypeFilter_8888>; 350 proc_2_3 = downsample_2_3<ColorTypeFilter_8888>; 351 proc_3_1 = downsample_3_1<ColorTypeFilter_8888>; 352 proc_3_2 = downsample_3_2<ColorTypeFilter_8888>; 353 proc_3_3 = downsample_3_3<ColorTypeFilter_8888>; 354 } 355 break; 356 case kRGB_565_SkColorType: 357 proc_1_2 = downsample_1_2<ColorTypeFilter_565>; 358 proc_1_3 = downsample_1_3<ColorTypeFilter_565>; 359 proc_2_1 = downsample_2_1<ColorTypeFilter_565>; 360 proc_2_2 = downsample_2_2<ColorTypeFilter_565>; 361 proc_2_3 = downsample_2_3<ColorTypeFilter_565>; 362 proc_3_1 = downsample_3_1<ColorTypeFilter_565>; 363 proc_3_2 = downsample_3_2<ColorTypeFilter_565>; 364 proc_3_3 = downsample_3_3<ColorTypeFilter_565>; 365 break; 366 case kARGB_4444_SkColorType: 367 proc_1_2 = downsample_1_2<ColorTypeFilter_4444>; 368 proc_1_3 = downsample_1_3<ColorTypeFilter_4444>; 369 proc_2_1 = downsample_2_1<ColorTypeFilter_4444>; 370 proc_2_2 = downsample_2_2<ColorTypeFilter_4444>; 371 proc_2_3 = downsample_2_3<ColorTypeFilter_4444>; 372 proc_3_1 = downsample_3_1<ColorTypeFilter_4444>; 373 proc_3_2 = downsample_3_2<ColorTypeFilter_4444>; 374 proc_3_3 = downsample_3_3<ColorTypeFilter_4444>; 375 break; 376 case kAlpha_8_SkColorType: 377 case kGray_8_SkColorType: 378 proc_1_2 = downsample_1_2<ColorTypeFilter_8>; 379 proc_1_3 = downsample_1_3<ColorTypeFilter_8>; 380 proc_2_1 = downsample_2_1<ColorTypeFilter_8>; 381 proc_2_2 = downsample_2_2<ColorTypeFilter_8>; 382 proc_2_3 = downsample_2_3<ColorTypeFilter_8>; 383 proc_3_1 = downsample_3_1<ColorTypeFilter_8>; 384 proc_3_2 = downsample_3_2<ColorTypeFilter_8>; 385 proc_3_3 = downsample_3_3<ColorTypeFilter_8>; 386 break; 387 case kRGBA_F16_SkColorType: 388 proc_1_2 = downsample_1_2<ColorTypeFilter_F16>; 389 proc_1_3 = downsample_1_3<ColorTypeFilter_F16>; 390 proc_2_1 = downsample_2_1<ColorTypeFilter_F16>; 391 proc_2_2 = downsample_2_2<ColorTypeFilter_F16>; 392 proc_2_3 = downsample_2_3<ColorTypeFilter_F16>; 393 proc_3_1 = downsample_3_1<ColorTypeFilter_F16>; 394 proc_3_2 = downsample_3_2<ColorTypeFilter_F16>; 395 proc_3_3 = downsample_3_3<ColorTypeFilter_F16>; 396 break; 397 default: 398 // TODO: We could build miplevels for kIndex8 if the levels were in 8888. 399 // Means using more ram, but the quality would be fine. 400 return nullptr; 401 } 402 403 if (src.width() <= 1 && src.height() <= 1) { 404 return nullptr; 405 } 406 // whip through our loop to compute the exact size needed 407 size_t size = 0; 408 int countLevels = ComputeLevelCount(src.width(), src.height()); 409 for (int currentMipLevel = countLevels; currentMipLevel >= 0; currentMipLevel--) { 410 SkISize mipSize = ComputeLevelSize(src.width(), src.height(), currentMipLevel); 411 size += SkColorTypeMinRowBytes(ct, mipSize.fWidth) * mipSize.fHeight; 412 } 413 414 size_t storageSize = SkMipMap::AllocLevelsSize(countLevels, size); 415 if (0 == storageSize) { 416 return nullptr; 417 } 418 419 SkMipMap* mipmap; 420 if (fact) { 421 SkDiscardableMemory* dm = fact(storageSize); 422 if (nullptr == dm) { 423 return nullptr; 424 } 425 mipmap = new SkMipMap(storageSize, dm); 426 } else { 427 mipmap = new SkMipMap(sk_malloc_throw(storageSize), storageSize); 428 } 429 430 // init 431 mipmap->fCS = sk_ref_sp(src.info().colorSpace()); 432 mipmap->fCount = countLevels; 433 mipmap->fLevels = (Level*)mipmap->writable_data(); 434 SkASSERT(mipmap->fLevels); 435 436 Level* levels = mipmap->fLevels; 437 uint8_t* baseAddr = (uint8_t*)&levels[countLevels]; 438 uint8_t* addr = baseAddr; 439 int width = src.width(); 440 int height = src.height(); 441 uint32_t rowBytes; 442 SkPixmap srcPM(src); 443 444 for (int i = 0; i < countLevels; ++i) { 445 FilterProc* proc; 446 if (height & 1) { 447 if (height == 1) { // src-height is 1 448 if (width & 1) { // src-width is 3 449 proc = proc_3_1; 450 } else { // src-width is 2 451 proc = proc_2_1; 452 } 453 } else { // src-height is 3 454 if (width & 1) { 455 if (width == 1) { // src-width is 1 456 proc = proc_1_3; 457 } else { // src-width is 3 458 proc = proc_3_3; 459 } 460 } else { // src-width is 2 461 proc = proc_2_3; 462 } 463 } 464 } else { // src-height is 2 465 if (width & 1) { 466 if (width == 1) { // src-width is 1 467 proc = proc_1_2; 468 } else { // src-width is 3 469 proc = proc_3_2; 470 } 471 } else { // src-width is 2 472 proc = proc_2_2; 473 } 474 } 475 width = SkTMax(1, width >> 1); 476 height = SkTMax(1, height >> 1); 477 rowBytes = SkToU32(SkColorTypeMinRowBytes(ct, width)); 478 479 // We make the Info w/o any colorspace, since that storage is not under our control, and 480 // will not be deleted in a controlled fashion. When the caller is given the pixmap for 481 // a given level, we augment this pixmap with fCS (which we do manage). 482 new (&levels[i].fPixmap) SkPixmap(SkImageInfo::Make(width, height, ct, at), addr, rowBytes); 483 levels[i].fScale = SkSize::Make(SkIntToScalar(width) / src.width(), 484 SkIntToScalar(height) / src.height()); 485 486 const SkPixmap& dstPM = levels[i].fPixmap; 487 const void* srcBasePtr = srcPM.addr(); 488 void* dstBasePtr = dstPM.writable_addr(); 489 490 const size_t srcRB = srcPM.rowBytes(); 491 for (int y = 0; y < height; y++) { 492 proc(dstBasePtr, srcBasePtr, srcRB, width); 493 srcBasePtr = (char*)srcBasePtr + srcRB * 2; // jump two rows 494 dstBasePtr = (char*)dstBasePtr + dstPM.rowBytes(); 495 } 496 srcPM = dstPM; 497 addr += height * rowBytes; 498 } 499 SkASSERT(addr == baseAddr + size); 500 501 SkASSERT(mipmap->fLevels); 502 return mipmap; 503} 504 505int SkMipMap::ComputeLevelCount(int baseWidth, int baseHeight) { 506 if (baseWidth < 1 || baseHeight < 1) { 507 return 0; 508 } 509 510 // OpenGL's spec requires that each mipmap level have height/width equal to 511 // max(1, floor(original_height / 2^i) 512 // (or original_width) where i is the mipmap level. 513 // Continue scaling down until both axes are size 1. 514 515 const int largestAxis = SkTMax(baseWidth, baseHeight); 516 if (largestAxis < 2) { 517 // SkMipMap::Build requires a minimum size of 2. 518 return 0; 519 } 520 const int leadingZeros = SkCLZ(static_cast<uint32_t>(largestAxis)); 521 // If the value 00011010 has 3 leading 0s then it has 5 significant bits 522 // (the bits which are not leading zeros) 523 const int significantBits = (sizeof(uint32_t) * 8) - leadingZeros; 524 // This is making the assumption that the size of a byte is 8 bits 525 // and that sizeof(uint32_t)'s implementation-defined behavior is 4. 526 int mipLevelCount = significantBits; 527 528 // SkMipMap does not include the base mip level. 529 // For example, it contains levels 1-x instead of 0-x. 530 // This is because the image used to create SkMipMap is the base level. 531 // So subtract 1 from the mip level count. 532 if (mipLevelCount > 0) { 533 --mipLevelCount; 534 } 535 536 return mipLevelCount; 537} 538 539SkISize SkMipMap::ComputeLevelSize(int baseWidth, int baseHeight, int level) { 540 if (baseWidth < 1 || baseHeight < 1) { 541 return SkISize::Make(0, 0); 542 } 543 544 int maxLevelCount = ComputeLevelCount(baseWidth, baseHeight); 545 if (level >= maxLevelCount || level < 0) { 546 return SkISize::Make(0, 0); 547 } 548 // OpenGL's spec requires that each mipmap level have height/width equal to 549 // max(1, floor(original_height / 2^i) 550 // (or original_width) where i is the mipmap level. 551 552 // SkMipMap does not include the base mip level. 553 // For example, it contains levels 1-x instead of 0-x. 554 // This is because the image used to create SkMipMap is the base level. 555 // So subtract 1 from the mip level to get the index stored by SkMipMap. 556 int width = SkTMax(1, baseWidth >> (level + 1)); 557 int height = SkTMax(1, baseHeight >> (level + 1)); 558 559 return SkISize::Make(width, height); 560} 561 562/////////////////////////////////////////////////////////////////////////////// 563 564bool SkMipMap::extractLevel(const SkSize& scaleSize, Level* levelPtr) const { 565 if (nullptr == fLevels) { 566 return false; 567 } 568 569 SkASSERT(scaleSize.width() >= 0 && scaleSize.height() >= 0); 570 571#ifndef SK_SUPPORT_LEGACY_ANISOTROPIC_MIPMAP_SCALE 572 // Use the smallest scale to match the GPU impl. 573 const SkScalar scale = SkTMin(scaleSize.width(), scaleSize.height()); 574#else 575 // Ideally we'd pick the smaller scale, to match Ganesh. But ignoring one of the 576 // scales can produce some atrocious results, so for now we use the geometric mean. 577 // (https://bugs.chromium.org/p/skia/issues/detail?id=4863) 578 const SkScalar scale = SkScalarSqrt(scaleSize.width() * scaleSize.height()); 579#endif 580 581 if (scale >= SK_Scalar1 || scale <= 0 || !SkScalarIsFinite(scale)) { 582 return false; 583 } 584 585 SkScalar L = -SkScalarLog2(scale); 586 if (!SkScalarIsFinite(L)) { 587 return false; 588 } 589 SkASSERT(L >= 0); 590 int level = SkScalarFloorToInt(L); 591 592 SkASSERT(level >= 0); 593 if (level <= 0) { 594 return false; 595 } 596 597 if (level > fCount) { 598 level = fCount; 599 } 600 if (levelPtr) { 601 *levelPtr = fLevels[level - 1]; 602 // need to augment with our colorspace 603 levelPtr->fPixmap.setColorSpace(fCS); 604 } 605 return true; 606} 607 608// Helper which extracts a pixmap from the src bitmap 609// 610SkMipMap* SkMipMap::Build(const SkBitmap& src, SkSourceGammaTreatment treatment, 611 SkDiscardableFactoryProc fact) { 612 SkAutoPixmapUnlock srcUnlocker; 613 if (!src.requestLock(&srcUnlocker)) { 614 return nullptr; 615 } 616 const SkPixmap& srcPixmap = srcUnlocker.pixmap(); 617 // Try to catch where we might have returned nullptr for src crbug.com/492818 618 if (nullptr == srcPixmap.addr()) { 619 sk_throw(); 620 } 621 return Build(srcPixmap, treatment, fact); 622} 623 624int SkMipMap::countLevels() const { 625 return fCount; 626} 627 628bool SkMipMap::getLevel(int index, Level* levelPtr) const { 629 if (NULL == fLevels) { 630 return false; 631 } 632 if (index < 0) { 633 return false; 634 } 635 if (index > fCount - 1) { 636 return false; 637 } 638 if (levelPtr) { 639 *levelPtr = fLevels[index]; 640 } 641 return true; 642} 643