Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "SkMipMap.h" | 8 #include "SkMipMap.h" |
| 9 #include "SkBitmap.h" | 9 #include "SkBitmap.h" |
| 10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
| 11 #include "SkHalf.h" | 11 #include "SkHalf.h" |
| 12 #include "SkMath.h" | 12 #include "SkMath.h" |
| 13 #include "SkNx.h" | 13 #include "SkNx.h" |
| 14 #include "SkPM4fPriv.h" | |
| 14 #include "SkTypes.h" | 15 #include "SkTypes.h" |
| 15 | 16 |
| 16 // | 17 // |
| 17 // ColorTypeFilter is the "Type" we pass to some downsample template functions. | 18 // ColorTypeFilter is the "Type" we pass to some downsample template functions. |
| 18 // It controls how we expand a pixel into a large type, with space between each component, | 19 // It controls how we expand a pixel into a large type, with space between each component, |
| 19 // so we can then perform our simple filter (either box or triangle) and store t he intermediates | 20 // so we can then perform our simple filter (either box or triangle) and store t he intermediates |
| 20 // in the expanded type. | 21 // in the expanded type. |
| 21 // | 22 // |
| 22 | 23 |
| 23 struct ColorTypeFilter_8888 { | 24 struct ColorTypeFilter_8888 { |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 34 #else | 35 #else |
| 35 static uint64_t Expand(uint32_t x) { | 36 static uint64_t Expand(uint32_t x) { |
| 36 return (x & 0xFF00FF) | ((uint64_t)(x & 0xFF00FF00) << 24); | 37 return (x & 0xFF00FF) | ((uint64_t)(x & 0xFF00FF00) << 24); |
| 37 } | 38 } |
| 38 static uint32_t Compact(uint64_t x) { | 39 static uint32_t Compact(uint64_t x) { |
| 39 return (uint32_t)((x & 0xFF00FF) | ((x >> 24) & 0xFF00FF00)); | 40 return (uint32_t)((x & 0xFF00FF) | ((x >> 24) & 0xFF00FF00)); |
| 40 } | 41 } |
| 41 #endif | 42 #endif |
| 42 }; | 43 }; |
| 43 | 44 |
| 45 struct ColorTypeFilter_S32 { | |
| 46 typedef uint32_t Type; | |
| 47 static Sk4f Expand(uint32_t x) { | |
| 48 // does not bother to normalize to 1.0, so result range is 0 ... 255*255 | |
| 49 return srgb_to_linear(to_4f(x)); | |
| 50 } | |
| 51 static uint32_t Compact(const Sk4f& x) { | |
| 52 return to_4b(linear_to_srgb(x)); | |
| 53 } | |
| 54 }; | |
| 55 | |
| 44 struct ColorTypeFilter_565 { | 56 struct ColorTypeFilter_565 { |
| 45 typedef uint16_t Type; | 57 typedef uint16_t Type; |
| 46 static uint32_t Expand(uint16_t x) { | 58 static uint32_t Expand(uint16_t x) { |
| 47 return (x & ~SK_G16_MASK_IN_PLACE) | ((x & SK_G16_MASK_IN_PLACE) << 16); | 59 return (x & ~SK_G16_MASK_IN_PLACE) | ((x & SK_G16_MASK_IN_PLACE) << 16); |
| 48 } | 60 } |
| 49 static uint16_t Compact(uint32_t x) { | 61 static uint16_t Compact(uint32_t x) { |
| 50 return (x & ~SK_G16_MASK_IN_PLACE) | ((x >> 16) & SK_G16_MASK_IN_PLACE); | 62 return (x & ~SK_G16_MASK_IN_PLACE) | ((x >> 16) & SK_G16_MASK_IN_PLACE); |
| 51 } | 63 } |
| 52 }; | 64 }; |
| 53 | 65 |
| (...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 286 if (levelCount < 0) { | 298 if (levelCount < 0) { |
| 287 return 0; | 299 return 0; |
| 288 } | 300 } |
| 289 int64_t size = sk_64_mul(levelCount + 1, sizeof(Level)) + pixelSize; | 301 int64_t size = sk_64_mul(levelCount + 1, sizeof(Level)) + pixelSize; |
| 290 if (!sk_64_isS32(size)) { | 302 if (!sk_64_isS32(size)) { |
| 291 return 0; | 303 return 0; |
| 292 } | 304 } |
| 293 return sk_64_asS32(size); | 305 return sk_64_asS32(size); |
| 294 } | 306 } |
| 295 | 307 |
| 296 SkMipMap* SkMipMap::Build(const SkPixmap& src, SkDiscardableFactoryProc fact) { | 308 static bool treat_like_srgb(const SkImageInfo& info) { |
| 309 if (info.colorSpace()) { | |
| 310 return SkColorSpace::k2Dot2Curve_GammaNamed == info.colorSpace()->gammaN amed(); | |
| 311 } else { | |
| 312 return kSRGB_SkColorProfileType == info.profileType(); | |
| 313 } | |
| 314 } | |
| 315 | |
| 316 SkMipMap* SkMipMap::Build(const SkPixmap& src, SrcGammaMode mode, SkDiscardableF actoryProc fact) { | |
| 297 typedef void FilterProc(void*, const void* srcPtr, size_t srcRB, int count); | 317 typedef void FilterProc(void*, const void* srcPtr, size_t srcRB, int count); |
| 298 | 318 |
| 299 FilterProc* proc_1_2 = nullptr; | 319 FilterProc* proc_1_2 = nullptr; |
| 300 FilterProc* proc_1_3 = nullptr; | 320 FilterProc* proc_1_3 = nullptr; |
| 301 FilterProc* proc_2_1 = nullptr; | 321 FilterProc* proc_2_1 = nullptr; |
| 302 FilterProc* proc_2_2 = nullptr; | 322 FilterProc* proc_2_2 = nullptr; |
| 303 FilterProc* proc_2_3 = nullptr; | 323 FilterProc* proc_2_3 = nullptr; |
| 304 FilterProc* proc_3_1 = nullptr; | 324 FilterProc* proc_3_1 = nullptr; |
| 305 FilterProc* proc_3_2 = nullptr; | 325 FilterProc* proc_3_2 = nullptr; |
| 306 FilterProc* proc_3_3 = nullptr; | 326 FilterProc* proc_3_3 = nullptr; |
| 307 | 327 |
| 308 const SkColorType ct = src.colorType(); | 328 const SkColorType ct = src.colorType(); |
| 309 const SkAlphaType at = src.alphaType(); | 329 const SkAlphaType at = src.alphaType(); |
| 330 const bool srgbGamma = (kRespect_SrcGammaMode == mode) && treat_like_srgb(sr c.info()); | |
| 331 | |
| 310 switch (ct) { | 332 switch (ct) { |
| 311 case kRGBA_8888_SkColorType: | 333 case kRGBA_8888_SkColorType: |
| 312 case kBGRA_8888_SkColorType: | 334 case kBGRA_8888_SkColorType: |
| 313 proc_1_2 = downsample_1_2<ColorTypeFilter_8888>; | 335 if (srgbGamma) { |
| 314 proc_1_3 = downsample_1_3<ColorTypeFilter_8888>; | 336 proc_1_2 = downsample_1_2<ColorTypeFilter_S32>; |
| 315 proc_2_1 = downsample_2_1<ColorTypeFilter_8888>; | 337 proc_1_3 = downsample_1_3<ColorTypeFilter_S32>; |
| 316 proc_2_2 = downsample_2_2<ColorTypeFilter_8888>; | 338 proc_2_1 = downsample_2_1<ColorTypeFilter_S32>; |
| 317 proc_2_3 = downsample_2_3<ColorTypeFilter_8888>; | 339 proc_2_2 = downsample_2_2<ColorTypeFilter_S32>; |
| 318 proc_3_1 = downsample_3_1<ColorTypeFilter_8888>; | 340 proc_2_3 = downsample_2_3<ColorTypeFilter_S32>; |
| 319 proc_3_2 = downsample_3_2<ColorTypeFilter_8888>; | 341 proc_3_1 = downsample_3_1<ColorTypeFilter_S32>; |
| 320 proc_3_3 = downsample_3_3<ColorTypeFilter_8888>; | 342 proc_3_2 = downsample_3_2<ColorTypeFilter_S32>; |
| 343 proc_3_3 = downsample_3_3<ColorTypeFilter_S32>; | |
| 344 } else { | |
| 345 proc_1_2 = downsample_1_2<ColorTypeFilter_8888>; | |
| 346 proc_1_3 = downsample_1_3<ColorTypeFilter_8888>; | |
| 347 proc_2_1 = downsample_2_1<ColorTypeFilter_8888>; | |
| 348 proc_2_2 = downsample_2_2<ColorTypeFilter_8888>; | |
| 349 proc_2_3 = downsample_2_3<ColorTypeFilter_8888>; | |
| 350 proc_3_1 = downsample_3_1<ColorTypeFilter_8888>; | |
| 351 proc_3_2 = downsample_3_2<ColorTypeFilter_8888>; | |
| 352 proc_3_3 = downsample_3_3<ColorTypeFilter_8888>; | |
| 353 } | |
| 321 break; | 354 break; |
| 322 case kRGB_565_SkColorType: | 355 case kRGB_565_SkColorType: |
| 323 proc_1_2 = downsample_1_2<ColorTypeFilter_565>; | 356 proc_1_2 = downsample_1_2<ColorTypeFilter_565>; |
| 324 proc_1_3 = downsample_1_3<ColorTypeFilter_565>; | 357 proc_1_3 = downsample_1_3<ColorTypeFilter_565>; |
| 325 proc_2_1 = downsample_2_1<ColorTypeFilter_565>; | 358 proc_2_1 = downsample_2_1<ColorTypeFilter_565>; |
| 326 proc_2_2 = downsample_2_2<ColorTypeFilter_565>; | 359 proc_2_2 = downsample_2_2<ColorTypeFilter_565>; |
| 327 proc_2_3 = downsample_2_3<ColorTypeFilter_565>; | 360 proc_2_3 = downsample_2_3<ColorTypeFilter_565>; |
| 328 proc_3_1 = downsample_3_1<ColorTypeFilter_565>; | 361 proc_3_1 = downsample_3_1<ColorTypeFilter_565>; |
| 329 proc_3_2 = downsample_3_2<ColorTypeFilter_565>; | 362 proc_3_2 = downsample_3_2<ColorTypeFilter_565>; |
| 330 proc_3_3 = downsample_3_3<ColorTypeFilter_565>; | 363 proc_3_3 = downsample_3_3<ColorTypeFilter_565>; |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 387 SkDiscardableMemory* dm = fact(storageSize); | 420 SkDiscardableMemory* dm = fact(storageSize); |
| 388 if (nullptr == dm) { | 421 if (nullptr == dm) { |
| 389 return nullptr; | 422 return nullptr; |
| 390 } | 423 } |
| 391 mipmap = new SkMipMap(storageSize, dm); | 424 mipmap = new SkMipMap(storageSize, dm); |
| 392 } else { | 425 } else { |
| 393 mipmap = new SkMipMap(sk_malloc_throw(storageSize), storageSize); | 426 mipmap = new SkMipMap(sk_malloc_throw(storageSize), storageSize); |
| 394 } | 427 } |
| 395 | 428 |
| 396 // init | 429 // init |
| 430 mipmap->fCS = sk_ref_sp(src.info().colorSpace()); | |
| 397 mipmap->fCount = countLevels; | 431 mipmap->fCount = countLevels; |
| 398 mipmap->fLevels = (Level*)mipmap->writable_data(); | 432 mipmap->fLevels = (Level*)mipmap->writable_data(); |
| 433 SkASSERT(mipmap->fLevels); | |
| 399 | 434 |
| 400 Level* levels = mipmap->fLevels; | 435 Level* levels = mipmap->fLevels; |
| 401 uint8_t* baseAddr = (uint8_t*)&levels[countLevels]; | 436 uint8_t* baseAddr = (uint8_t*)&levels[countLevels]; |
| 402 uint8_t* addr = baseAddr; | 437 uint8_t* addr = baseAddr; |
| 403 int width = src.width(); | 438 int width = src.width(); |
| 404 int height = src.height(); | 439 int height = src.height(); |
| 405 uint32_t rowBytes; | 440 uint32_t rowBytes; |
| 406 SkPixmap srcPM(src); | 441 SkPixmap srcPM(src); |
| 407 | 442 |
| 408 for (int i = 0; i < countLevels; ++i) { | 443 for (int i = 0; i < countLevels; ++i) { |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 433 proc = proc_3_2; | 468 proc = proc_3_2; |
| 434 } | 469 } |
| 435 } else { // src-width is 2 | 470 } else { // src-width is 2 |
| 436 proc = proc_2_2; | 471 proc = proc_2_2; |
| 437 } | 472 } |
| 438 } | 473 } |
| 439 width = SkTMax(1, width >> 1); | 474 width = SkTMax(1, width >> 1); |
| 440 height = SkTMax(1, height >> 1); | 475 height = SkTMax(1, height >> 1); |
| 441 rowBytes = SkToU32(SkColorTypeMinRowBytes(ct, width)); | 476 rowBytes = SkToU32(SkColorTypeMinRowBytes(ct, width)); |
| 442 | 477 |
| 478 // We make the Info w/o any colorspace, since that storage is not under our control, and | |
| 479 // will not be deleted in a controlled fashion. When the caller is given the pixmap for | |
| 480 // a given level, we augment this pixmap with fCS (which we do managed). | |
|
msarett
2016/06/03 16:54:17
nit: *manage
reed1
2016/06/07 16:01:10
Done.
| |
| 443 new (&levels[i].fPixmap) SkPixmap(SkImageInfo::Make(width, height, ct, a t), addr, rowBytes); | 481 new (&levels[i].fPixmap) SkPixmap(SkImageInfo::Make(width, height, ct, a t), addr, rowBytes); |
| 444 levels[i].fScale = SkSize::Make(SkIntToScalar(width) / src.width(), | 482 levels[i].fScale = SkSize::Make(SkIntToScalar(width) / src.width(), |
| 445 SkIntToScalar(height) / src.height()); | 483 SkIntToScalar(height) / src.height()); |
| 446 | 484 |
| 447 const SkPixmap& dstPM = levels[i].fPixmap; | 485 const SkPixmap& dstPM = levels[i].fPixmap; |
| 448 const void* srcBasePtr = srcPM.addr(); | 486 const void* srcBasePtr = srcPM.addr(); |
| 449 void* dstBasePtr = dstPM.writable_addr(); | 487 void* dstBasePtr = dstPM.writable_addr(); |
| 450 | 488 |
| 451 const size_t srcRB = srcPM.rowBytes(); | 489 const size_t srcRB = srcPM.rowBytes(); |
| 452 for (int y = 0; y < height; y++) { | 490 for (int y = 0; y < height; y++) { |
| 453 proc(dstBasePtr, srcBasePtr, srcRB, width); | 491 proc(dstBasePtr, srcBasePtr, srcRB, width); |
| 454 srcBasePtr = (char*)srcBasePtr + srcRB * 2; // jump two rows | 492 srcBasePtr = (char*)srcBasePtr + srcRB * 2; // jump two rows |
| 455 dstBasePtr = (char*)dstBasePtr + dstPM.rowBytes(); | 493 dstBasePtr = (char*)dstBasePtr + dstPM.rowBytes(); |
| 456 } | 494 } |
| 457 srcPM = dstPM; | 495 srcPM = dstPM; |
| 458 addr += height * rowBytes; | 496 addr += height * rowBytes; |
| 459 } | 497 } |
| 460 SkASSERT(addr == baseAddr + size); | 498 SkASSERT(addr == baseAddr + size); |
| 461 | 499 |
| 500 SkASSERT(mipmap->fLevels); | |
| 462 return mipmap; | 501 return mipmap; |
| 463 } | 502 } |
| 464 | 503 |
| 465 int SkMipMap::ComputeLevelCount(int baseWidth, int baseHeight) { | 504 int SkMipMap::ComputeLevelCount(int baseWidth, int baseHeight) { |
| 466 if (baseWidth < 1 || baseHeight < 1) { | 505 if (baseWidth < 1 || baseHeight < 1) { |
| 467 return 0; | 506 return 0; |
| 468 } | 507 } |
| 469 | 508 |
| 470 // OpenGL's spec requires that each mipmap level have height/width equal to | 509 // OpenGL's spec requires that each mipmap level have height/width equal to |
| 471 // max(1, floor(original_height / 2^i) | 510 // max(1, floor(original_height / 2^i) |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 540 | 579 |
| 541 if (scale >= SK_Scalar1 || scale <= 0 || !SkScalarIsFinite(scale)) { | 580 if (scale >= SK_Scalar1 || scale <= 0 || !SkScalarIsFinite(scale)) { |
| 542 return false; | 581 return false; |
| 543 } | 582 } |
| 544 | 583 |
| 545 SkScalar L = -SkScalarLog2(scale); | 584 SkScalar L = -SkScalarLog2(scale); |
| 546 if (!SkScalarIsFinite(L)) { | 585 if (!SkScalarIsFinite(L)) { |
| 547 return false; | 586 return false; |
| 548 } | 587 } |
| 549 SkASSERT(L >= 0); | 588 SkASSERT(L >= 0); |
| 550 // int rndLevel = SkScalarRoundToInt(L); | |
| 551 int level = SkScalarFloorToInt(L); | 589 int level = SkScalarFloorToInt(L); |
| 552 // SkDebugf("mipmap scale=%g L=%g level=%d rndLevel=%d\n", scale, L, level, r ndLevel); | |
| 553 | 590 |
| 554 SkASSERT(level >= 0); | 591 SkASSERT(level >= 0); |
| 555 if (level <= 0) { | 592 if (level <= 0) { |
| 556 return false; | 593 return false; |
| 557 } | 594 } |
| 558 | 595 |
| 559 if (level > fCount) { | 596 if (level > fCount) { |
| 560 level = fCount; | 597 level = fCount; |
| 561 } | 598 } |
| 562 if (levelPtr) { | 599 if (levelPtr) { |
| 563 *levelPtr = fLevels[level - 1]; | 600 *levelPtr = fLevels[level - 1]; |
| 601 // need to augment with our colorspace | |
| 602 levelPtr->fPixmap.setColorSpace(fCS); | |
| 564 } | 603 } |
| 565 return true; | 604 return true; |
| 566 } | 605 } |
| 567 | 606 |
| 568 // Helper which extracts a pixmap from the src bitmap | 607 // Helper which extracts a pixmap from the src bitmap |
| 569 // | 608 // |
| 570 SkMipMap* SkMipMap::Build(const SkBitmap& src, SkDiscardableFactoryProc fact) { | 609 SkMipMap* SkMipMap::Build(const SkBitmap& src, SrcGammaMode mode, SkDiscardableF actoryProc fact) { |
| 571 SkAutoPixmapUnlock srcUnlocker; | 610 SkAutoPixmapUnlock srcUnlocker; |
| 572 if (!src.requestLock(&srcUnlocker)) { | 611 if (!src.requestLock(&srcUnlocker)) { |
| 573 return nullptr; | 612 return nullptr; |
| 574 } | 613 } |
| 575 const SkPixmap& srcPixmap = srcUnlocker.pixmap(); | 614 const SkPixmap& srcPixmap = srcUnlocker.pixmap(); |
| 576 // Try to catch where we might have returned nullptr for src crbug.com/49281 8 | 615 // Try to catch where we might have returned nullptr for src crbug.com/49281 8 |
| 577 if (nullptr == srcPixmap.addr()) { | 616 if (nullptr == srcPixmap.addr()) { |
| 578 sk_throw(); | 617 sk_throw(); |
| 579 } | 618 } |
| 580 return Build(srcPixmap, fact); | 619 return Build(srcPixmap, mode, fact); |
| 581 } | 620 } |
| 582 | 621 |
| 583 int SkMipMap::countLevels() const { | 622 int SkMipMap::countLevels() const { |
| 584 return fCount; | 623 return fCount; |
| 585 } | 624 } |
| 586 | 625 |
| 587 bool SkMipMap::getLevel(int index, Level* levelPtr) const { | 626 bool SkMipMap::getLevel(int index, Level* levelPtr) const { |
| 588 if (NULL == fLevels) { | 627 if (NULL == fLevels) { |
| 589 return false; | 628 return false; |
| 590 } | 629 } |
| 591 if (index < 0) { | 630 if (index < 0) { |
| 592 return false; | 631 return false; |
| 593 } | 632 } |
| 594 if (index > fCount - 1) { | 633 if (index > fCount - 1) { |
| 595 return false; | 634 return false; |
| 596 } | 635 } |
| 597 if (levelPtr) { | 636 if (levelPtr) { |
| 598 *levelPtr = fLevels[index]; | 637 *levelPtr = fLevels[index]; |
| 599 } | 638 } |
| 600 return true; | 639 return true; |
| 601 } | 640 } |
| OLD | NEW |