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, SkSourceGammaTreatment treatment, |
| 317 SkDiscardableFactoryProc fact) { |
297 typedef void FilterProc(void*, const void* srcPtr, size_t srcRB, int count); | 318 typedef void FilterProc(void*, const void* srcPtr, size_t srcRB, int count); |
298 | 319 |
299 FilterProc* proc_1_2 = nullptr; | 320 FilterProc* proc_1_2 = nullptr; |
300 FilterProc* proc_1_3 = nullptr; | 321 FilterProc* proc_1_3 = nullptr; |
301 FilterProc* proc_2_1 = nullptr; | 322 FilterProc* proc_2_1 = nullptr; |
302 FilterProc* proc_2_2 = nullptr; | 323 FilterProc* proc_2_2 = nullptr; |
303 FilterProc* proc_2_3 = nullptr; | 324 FilterProc* proc_2_3 = nullptr; |
304 FilterProc* proc_3_1 = nullptr; | 325 FilterProc* proc_3_1 = nullptr; |
305 FilterProc* proc_3_2 = nullptr; | 326 FilterProc* proc_3_2 = nullptr; |
306 FilterProc* proc_3_3 = nullptr; | 327 FilterProc* proc_3_3 = nullptr; |
307 | 328 |
308 const SkColorType ct = src.colorType(); | 329 const SkColorType ct = src.colorType(); |
309 const SkAlphaType at = src.alphaType(); | 330 const SkAlphaType at = src.alphaType(); |
| 331 const bool srgbGamma = (SkSourceGammaTreatment::kRespect == treatment) |
| 332 && treat_like_srgb(src.info()); |
| 333 |
310 switch (ct) { | 334 switch (ct) { |
311 case kRGBA_8888_SkColorType: | 335 case kRGBA_8888_SkColorType: |
312 case kBGRA_8888_SkColorType: | 336 case kBGRA_8888_SkColorType: |
313 proc_1_2 = downsample_1_2<ColorTypeFilter_8888>; | 337 if (srgbGamma) { |
314 proc_1_3 = downsample_1_3<ColorTypeFilter_8888>; | 338 proc_1_2 = downsample_1_2<ColorTypeFilter_S32>; |
315 proc_2_1 = downsample_2_1<ColorTypeFilter_8888>; | 339 proc_1_3 = downsample_1_3<ColorTypeFilter_S32>; |
316 proc_2_2 = downsample_2_2<ColorTypeFilter_8888>; | 340 proc_2_1 = downsample_2_1<ColorTypeFilter_S32>; |
317 proc_2_3 = downsample_2_3<ColorTypeFilter_8888>; | 341 proc_2_2 = downsample_2_2<ColorTypeFilter_S32>; |
318 proc_3_1 = downsample_3_1<ColorTypeFilter_8888>; | 342 proc_2_3 = downsample_2_3<ColorTypeFilter_S32>; |
319 proc_3_2 = downsample_3_2<ColorTypeFilter_8888>; | 343 proc_3_1 = downsample_3_1<ColorTypeFilter_S32>; |
320 proc_3_3 = downsample_3_3<ColorTypeFilter_8888>; | 344 proc_3_2 = downsample_3_2<ColorTypeFilter_S32>; |
| 345 proc_3_3 = downsample_3_3<ColorTypeFilter_S32>; |
| 346 } else { |
| 347 proc_1_2 = downsample_1_2<ColorTypeFilter_8888>; |
| 348 proc_1_3 = downsample_1_3<ColorTypeFilter_8888>; |
| 349 proc_2_1 = downsample_2_1<ColorTypeFilter_8888>; |
| 350 proc_2_2 = downsample_2_2<ColorTypeFilter_8888>; |
| 351 proc_2_3 = downsample_2_3<ColorTypeFilter_8888>; |
| 352 proc_3_1 = downsample_3_1<ColorTypeFilter_8888>; |
| 353 proc_3_2 = downsample_3_2<ColorTypeFilter_8888>; |
| 354 proc_3_3 = downsample_3_3<ColorTypeFilter_8888>; |
| 355 } |
321 break; | 356 break; |
322 case kRGB_565_SkColorType: | 357 case kRGB_565_SkColorType: |
323 proc_1_2 = downsample_1_2<ColorTypeFilter_565>; | 358 proc_1_2 = downsample_1_2<ColorTypeFilter_565>; |
324 proc_1_3 = downsample_1_3<ColorTypeFilter_565>; | 359 proc_1_3 = downsample_1_3<ColorTypeFilter_565>; |
325 proc_2_1 = downsample_2_1<ColorTypeFilter_565>; | 360 proc_2_1 = downsample_2_1<ColorTypeFilter_565>; |
326 proc_2_2 = downsample_2_2<ColorTypeFilter_565>; | 361 proc_2_2 = downsample_2_2<ColorTypeFilter_565>; |
327 proc_2_3 = downsample_2_3<ColorTypeFilter_565>; | 362 proc_2_3 = downsample_2_3<ColorTypeFilter_565>; |
328 proc_3_1 = downsample_3_1<ColorTypeFilter_565>; | 363 proc_3_1 = downsample_3_1<ColorTypeFilter_565>; |
329 proc_3_2 = downsample_3_2<ColorTypeFilter_565>; | 364 proc_3_2 = downsample_3_2<ColorTypeFilter_565>; |
330 proc_3_3 = downsample_3_3<ColorTypeFilter_565>; | 365 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); | 422 SkDiscardableMemory* dm = fact(storageSize); |
388 if (nullptr == dm) { | 423 if (nullptr == dm) { |
389 return nullptr; | 424 return nullptr; |
390 } | 425 } |
391 mipmap = new SkMipMap(storageSize, dm); | 426 mipmap = new SkMipMap(storageSize, dm); |
392 } else { | 427 } else { |
393 mipmap = new SkMipMap(sk_malloc_throw(storageSize), storageSize); | 428 mipmap = new SkMipMap(sk_malloc_throw(storageSize), storageSize); |
394 } | 429 } |
395 | 430 |
396 // init | 431 // init |
| 432 mipmap->fCS = sk_ref_sp(src.info().colorSpace()); |
397 mipmap->fCount = countLevels; | 433 mipmap->fCount = countLevels; |
398 mipmap->fLevels = (Level*)mipmap->writable_data(); | 434 mipmap->fLevels = (Level*)mipmap->writable_data(); |
| 435 SkASSERT(mipmap->fLevels); |
399 | 436 |
400 Level* levels = mipmap->fLevels; | 437 Level* levels = mipmap->fLevels; |
401 uint8_t* baseAddr = (uint8_t*)&levels[countLevels]; | 438 uint8_t* baseAddr = (uint8_t*)&levels[countLevels]; |
402 uint8_t* addr = baseAddr; | 439 uint8_t* addr = baseAddr; |
403 int width = src.width(); | 440 int width = src.width(); |
404 int height = src.height(); | 441 int height = src.height(); |
405 uint32_t rowBytes; | 442 uint32_t rowBytes; |
406 SkPixmap srcPM(src); | 443 SkPixmap srcPM(src); |
407 | 444 |
408 for (int i = 0; i < countLevels; ++i) { | 445 for (int i = 0; i < countLevels; ++i) { |
(...skipping 24 matching lines...) Expand all Loading... |
433 proc = proc_3_2; | 470 proc = proc_3_2; |
434 } | 471 } |
435 } else { // src-width is 2 | 472 } else { // src-width is 2 |
436 proc = proc_2_2; | 473 proc = proc_2_2; |
437 } | 474 } |
438 } | 475 } |
439 width = SkTMax(1, width >> 1); | 476 width = SkTMax(1, width >> 1); |
440 height = SkTMax(1, height >> 1); | 477 height = SkTMax(1, height >> 1); |
441 rowBytes = SkToU32(SkColorTypeMinRowBytes(ct, width)); | 478 rowBytes = SkToU32(SkColorTypeMinRowBytes(ct, width)); |
442 | 479 |
| 480 // We make the Info w/o any colorspace, since that storage is not under
our control, and |
| 481 // will not be deleted in a controlled fashion. When the caller is given
the pixmap for |
| 482 // a given level, we augment this pixmap with fCS (which we do manage). |
443 new (&levels[i].fPixmap) SkPixmap(SkImageInfo::Make(width, height, ct, a
t), addr, rowBytes); | 483 new (&levels[i].fPixmap) SkPixmap(SkImageInfo::Make(width, height, ct, a
t), addr, rowBytes); |
444 levels[i].fScale = SkSize::Make(SkIntToScalar(width) / src.width(), | 484 levels[i].fScale = SkSize::Make(SkIntToScalar(width) / src.width(), |
445 SkIntToScalar(height) / src.height()); | 485 SkIntToScalar(height) / src.height()); |
446 | 486 |
447 const SkPixmap& dstPM = levels[i].fPixmap; | 487 const SkPixmap& dstPM = levels[i].fPixmap; |
448 const void* srcBasePtr = srcPM.addr(); | 488 const void* srcBasePtr = srcPM.addr(); |
449 void* dstBasePtr = dstPM.writable_addr(); | 489 void* dstBasePtr = dstPM.writable_addr(); |
450 | 490 |
451 const size_t srcRB = srcPM.rowBytes(); | 491 const size_t srcRB = srcPM.rowBytes(); |
452 for (int y = 0; y < height; y++) { | 492 for (int y = 0; y < height; y++) { |
453 proc(dstBasePtr, srcBasePtr, srcRB, width); | 493 proc(dstBasePtr, srcBasePtr, srcRB, width); |
454 srcBasePtr = (char*)srcBasePtr + srcRB * 2; // jump two rows | 494 srcBasePtr = (char*)srcBasePtr + srcRB * 2; // jump two rows |
455 dstBasePtr = (char*)dstBasePtr + dstPM.rowBytes(); | 495 dstBasePtr = (char*)dstBasePtr + dstPM.rowBytes(); |
456 } | 496 } |
457 srcPM = dstPM; | 497 srcPM = dstPM; |
458 addr += height * rowBytes; | 498 addr += height * rowBytes; |
459 } | 499 } |
460 SkASSERT(addr == baseAddr + size); | 500 SkASSERT(addr == baseAddr + size); |
461 | 501 |
| 502 SkASSERT(mipmap->fLevels); |
462 return mipmap; | 503 return mipmap; |
463 } | 504 } |
464 | 505 |
465 int SkMipMap::ComputeLevelCount(int baseWidth, int baseHeight) { | 506 int SkMipMap::ComputeLevelCount(int baseWidth, int baseHeight) { |
466 if (baseWidth < 1 || baseHeight < 1) { | 507 if (baseWidth < 1 || baseHeight < 1) { |
467 return 0; | 508 return 0; |
468 } | 509 } |
469 | 510 |
470 // OpenGL's spec requires that each mipmap level have height/width equal to | 511 // OpenGL's spec requires that each mipmap level have height/width equal to |
471 // max(1, floor(original_height / 2^i) | 512 // max(1, floor(original_height / 2^i) |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
540 | 581 |
541 if (scale >= SK_Scalar1 || scale <= 0 || !SkScalarIsFinite(scale)) { | 582 if (scale >= SK_Scalar1 || scale <= 0 || !SkScalarIsFinite(scale)) { |
542 return false; | 583 return false; |
543 } | 584 } |
544 | 585 |
545 SkScalar L = -SkScalarLog2(scale); | 586 SkScalar L = -SkScalarLog2(scale); |
546 if (!SkScalarIsFinite(L)) { | 587 if (!SkScalarIsFinite(L)) { |
547 return false; | 588 return false; |
548 } | 589 } |
549 SkASSERT(L >= 0); | 590 SkASSERT(L >= 0); |
550 // int rndLevel = SkScalarRoundToInt(L); | |
551 int level = SkScalarFloorToInt(L); | 591 int level = SkScalarFloorToInt(L); |
552 // SkDebugf("mipmap scale=%g L=%g level=%d rndLevel=%d\n", scale, L, level, r
ndLevel); | |
553 | 592 |
554 SkASSERT(level >= 0); | 593 SkASSERT(level >= 0); |
555 if (level <= 0) { | 594 if (level <= 0) { |
556 return false; | 595 return false; |
557 } | 596 } |
558 | 597 |
559 if (level > fCount) { | 598 if (level > fCount) { |
560 level = fCount; | 599 level = fCount; |
561 } | 600 } |
562 if (levelPtr) { | 601 if (levelPtr) { |
563 *levelPtr = fLevels[level - 1]; | 602 *levelPtr = fLevels[level - 1]; |
| 603 // need to augment with our colorspace |
| 604 levelPtr->fPixmap.setColorSpace(fCS); |
564 } | 605 } |
565 return true; | 606 return true; |
566 } | 607 } |
567 | 608 |
568 // Helper which extracts a pixmap from the src bitmap | 609 // Helper which extracts a pixmap from the src bitmap |
569 // | 610 // |
570 SkMipMap* SkMipMap::Build(const SkBitmap& src, SkDiscardableFactoryProc fact) { | 611 SkMipMap* SkMipMap::Build(const SkBitmap& src, SkSourceGammaTreatment treatment, |
| 612 SkDiscardableFactoryProc fact) { |
571 SkAutoPixmapUnlock srcUnlocker; | 613 SkAutoPixmapUnlock srcUnlocker; |
572 if (!src.requestLock(&srcUnlocker)) { | 614 if (!src.requestLock(&srcUnlocker)) { |
573 return nullptr; | 615 return nullptr; |
574 } | 616 } |
575 const SkPixmap& srcPixmap = srcUnlocker.pixmap(); | 617 const SkPixmap& srcPixmap = srcUnlocker.pixmap(); |
576 // Try to catch where we might have returned nullptr for src crbug.com/49281
8 | 618 // Try to catch where we might have returned nullptr for src crbug.com/49281
8 |
577 if (nullptr == srcPixmap.addr()) { | 619 if (nullptr == srcPixmap.addr()) { |
578 sk_throw(); | 620 sk_throw(); |
579 } | 621 } |
580 return Build(srcPixmap, fact); | 622 return Build(srcPixmap, treatment, fact); |
581 } | 623 } |
582 | 624 |
583 int SkMipMap::countLevels() const { | 625 int SkMipMap::countLevels() const { |
584 return fCount; | 626 return fCount; |
585 } | 627 } |
586 | 628 |
587 bool SkMipMap::getLevel(int index, Level* levelPtr) const { | 629 bool SkMipMap::getLevel(int index, Level* levelPtr) const { |
588 if (NULL == fLevels) { | 630 if (NULL == fLevels) { |
589 return false; | 631 return false; |
590 } | 632 } |
591 if (index < 0) { | 633 if (index < 0) { |
592 return false; | 634 return false; |
593 } | 635 } |
594 if (index > fCount - 1) { | 636 if (index > fCount - 1) { |
595 return false; | 637 return false; |
596 } | 638 } |
597 if (levelPtr) { | 639 if (levelPtr) { |
598 *levelPtr = fLevels[index]; | 640 *levelPtr = fLevels[index]; |
599 } | 641 } |
600 return true; | 642 return true; |
601 } | 643 } |
OLD | NEW |