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 | 11 |
| 12 #ifdef SK_SUPPORT_LEGACY_MIPLEVEL_BUILDER |
| 13 |
12 static void downsample32_nocheck(void* dst, int, int, const void* srcPtr, const
SkPixmap& srcPM) { | 14 static void downsample32_nocheck(void* dst, int, int, const void* srcPtr, const
SkPixmap& srcPM) { |
13 const uint32_t* p = static_cast<const uint32_t*>(srcPtr); | 15 const uint32_t* p = static_cast<const uint32_t*>(srcPtr); |
14 const uint32_t* baseP = p; | 16 const uint32_t* baseP = p; |
15 uint32_t c, ag, rb; | 17 uint32_t c, ag, rb; |
16 | 18 |
17 c = *p; ag = (c >> 8) & 0xFF00FF; rb = c & 0xFF00FF; | 19 c = *p; ag = (c >> 8) & 0xFF00FF; rb = c & 0xFF00FF; |
18 p += 1; | 20 p += 1; |
19 | 21 |
20 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; | 22 c = *p; ag += (c >> 8) & 0xFF00FF; rb += c & 0xFF00FF; |
21 | 23 |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
125 p = baseP; | 127 p = baseP; |
126 if (y < srcPM.height() - 1) { | 128 if (y < srcPM.height() - 1) { |
127 p += srcPM.rowBytes() >> 1; | 129 p += srcPM.rowBytes() >> 1; |
128 } | 130 } |
129 c += expand4444(*p); | 131 c += expand4444(*p); |
130 if (x < srcPM.width() - 1) { | 132 if (x < srcPM.width() - 1) { |
131 p += 1; | 133 p += 1; |
132 } | 134 } |
133 c += expand4444(*p); | 135 c += expand4444(*p); |
134 | 136 |
135 *((uint16_t*)dst) = (uint16_t)collaps4444(c >> 2); | 137 *((uint16_t*)dst) = (uint16_t)collaps4444(c >> 2); |
136 } | 138 } |
137 | 139 |
138 static void downsample8_nocheck(void* dst, int, int, const void* srcPtr, const S
kPixmap& srcPM) { | 140 static void downsample8_nocheck(void* dst, int, int, const void* srcPtr, const S
kPixmap& srcPM) { |
139 const size_t rb = srcPM.rowBytes(); | 141 const size_t rb = srcPM.rowBytes(); |
140 const uint8_t* p = static_cast<const uint8_t*>(srcPtr); | 142 const uint8_t* p = static_cast<const uint8_t*>(srcPtr); |
141 *(uint8_t*)dst = (p[0] + p[1] + p[rb] + p[rb + 1]) >> 2; | 143 *(uint8_t*)dst = (p[0] + p[1] + p[rb] + p[rb + 1]) >> 2; |
142 } | 144 } |
143 | 145 |
144 static void downsample8_check(void* dst, int x, int y, const void* srcPtr, const
SkPixmap& srcPM) { | 146 static void downsample8_check(void* dst, int x, int y, const void* srcPtr, const
SkPixmap& srcPM) { |
145 const uint8_t* p = static_cast<const uint8_t*>(srcPtr); | 147 const uint8_t* p = static_cast<const uint8_t*>(srcPtr); |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
307 for (int x = 0; x < width; x++) { | 309 for (int x = 0; x < width; x++) { |
308 proc_check(dstPtr, x, heightEven, srcPtr, srcPM); | 310 proc_check(dstPtr, x, heightEven, srcPtr, srcPM); |
309 srcPtr = (char*)srcPtr + pixelSize * 2; | 311 srcPtr = (char*)srcPtr + pixelSize * 2; |
310 dstPtr = (char*)dstPtr + pixelSize; | 312 dstPtr = (char*)dstPtr + pixelSize; |
311 } | 313 } |
312 } | 314 } |
313 srcPM = dstPM; | 315 srcPM = dstPM; |
314 addr += height * rowBytes; | 316 addr += height * rowBytes; |
315 } | 317 } |
316 SkASSERT(addr == baseAddr + size); | 318 SkASSERT(addr == baseAddr + size); |
317 | 319 |
318 return mipmap; | 320 return mipmap; |
319 } | 321 } |
320 | 322 |
| 323 #else // new technique that handles odd dimensions better |
| 324 |
| 325 // |
| 326 // ColorTypeFilter is the "Type" we pass to some downsample template functions. |
| 327 // It controls how we expand a pixel into a large type, with space between each
component, |
| 328 // so we can then perform our simple filter (either box or triangle) and store t
he intermediates |
| 329 // in the expanded type. |
| 330 // |
| 331 |
| 332 struct ColorTypeFilter_8888 { |
| 333 typedef uint32_t Type; |
| 334 static uint64_t Expand(uint32_t x) { |
| 335 return (x & 0xFF00FF) | ((uint64_t)(x & 0xFF00FF00) << 24); |
| 336 } |
| 337 static uint32_t Compact(uint64_t x) { |
| 338 return (uint32_t)((x & 0xFF00FF) | ((x >> 24) & 0xFF00FF00)); |
| 339 } |
| 340 }; |
| 341 |
| 342 struct ColorTypeFilter_565 { |
| 343 typedef uint16_t Type; |
| 344 static uint32_t Expand(uint16_t x) { |
| 345 return (x & ~SK_G16_MASK_IN_PLACE) | ((x & SK_G16_MASK_IN_PLACE) << 16); |
| 346 } |
| 347 static uint16_t Compact(uint32_t x) { |
| 348 return (x & ~SK_G16_MASK_IN_PLACE) | ((x >> 16) & SK_G16_MASK_IN_PLACE); |
| 349 } |
| 350 }; |
| 351 |
| 352 struct ColorTypeFilter_4444 { |
| 353 typedef uint16_t Type; |
| 354 static uint32_t Expand(uint16_t x) { |
| 355 return (x & 0xF0F) | ((x & ~0xF0F) << 12); |
| 356 } |
| 357 static uint16_t Compact(uint32_t x) { |
| 358 return (x & 0xF0F) | ((x >> 12) & ~0xF0F); |
| 359 } |
| 360 }; |
| 361 |
| 362 struct ColorTypeFilter_8 { |
| 363 typedef uint8_t Type; |
| 364 static unsigned Expand(unsigned x) { |
| 365 return x; |
| 366 } |
| 367 static uint8_t Compact(unsigned x) { |
| 368 return (uint8_t)x; |
| 369 } |
| 370 }; |
| 371 |
| 372 template <typename T> T add_121(T a, T b, T c) { |
| 373 return a + b + b + c; |
| 374 } |
| 375 |
| 376 // |
| 377 // To produce each mip level, we need to filter down by 1/2 (e.g. 100x100 -> 50
,50) |
| 378 // If the starting dimension is odd, we floor the size of the lower level (e.g.
101 -> 50) |
| 379 // In those (odd) cases, we use a triangle filter, with 1-pixel overlap between
samplings, |
| 380 // else for even cases, we just use a 2x box filter. |
| 381 // |
| 382 // This produces 4 possible filters: 2x2 2x3 3x2 3x3 where WxH indicates the nu
mber of src pixels |
| 383 // we need to sample in each dimension to produce 1 dst pixel. |
| 384 // |
| 385 |
| 386 template <typename F> void downsample_2_2(void* dst, const void* src, size_t src
RB) { |
| 387 auto p0 = static_cast<const typename F::Type*>(src); |
| 388 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); |
| 389 |
| 390 auto c00 = F::Expand(p0[0]); |
| 391 auto c01 = F::Expand(p0[1]); |
| 392 auto c10 = F::Expand(p1[0]); |
| 393 auto c11 = F::Expand(p1[1]); |
| 394 |
| 395 auto c = c00 + c10 + c01 + c11; |
| 396 *(typename F::Type*)dst = F::Compact(c >> 2); |
| 397 } |
| 398 |
| 399 template <typename F> void downsample_3_2(void* dst, const void* src, size_t src
RB) { |
| 400 auto p0 = static_cast<const typename F::Type*>(src); |
| 401 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); |
| 402 |
| 403 auto c00 = F::Expand(p0[0]); |
| 404 auto c01 = F::Expand(p0[1]); |
| 405 auto c02 = F::Expand(p0[2]); |
| 406 auto c10 = F::Expand(p1[0]); |
| 407 auto c11 = F::Expand(p1[1]); |
| 408 auto c12 = F::Expand(p1[2]); |
| 409 |
| 410 auto c = add_121(c00, c01, c02) + add_121(c10, c11, c12); |
| 411 *(typename F::Type*)dst = F::Compact(c >> 3); |
| 412 } |
| 413 |
| 414 template <typename F> void downsample_2_3(void* dst, const void* src, size_t src
RB) { |
| 415 auto p0 = static_cast<const typename F::Type*>(src); |
| 416 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); |
| 417 auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); |
| 418 |
| 419 auto c00 = F::Expand(p0[0]); |
| 420 auto c01 = F::Expand(p0[1]); |
| 421 auto c10 = F::Expand(p1[0]); |
| 422 auto c11 = F::Expand(p1[1]); |
| 423 auto c20 = F::Expand(p2[0]); |
| 424 auto c21 = F::Expand(p2[1]); |
| 425 auto c = add_121(c00, c10, c20) + add_121(c01, c11, c21); |
| 426 *(typename F::Type*)dst = F::Compact(c >> 3); |
| 427 } |
| 428 |
| 429 template <typename F> void downsample_3_3(void* dst, const void* src, size_t src
RB) { |
| 430 auto p0 = static_cast<const typename F::Type*>(src); |
| 431 auto p1 = (const typename F::Type*)((const char*)p0 + srcRB); |
| 432 auto p2 = (const typename F::Type*)((const char*)p1 + srcRB); |
| 433 |
| 434 auto c00 = F::Expand(p0[0]); |
| 435 auto c01 = F::Expand(p0[1]); |
| 436 auto c02 = F::Expand(p0[2]); |
| 437 auto c10 = F::Expand(p1[0]); |
| 438 auto c11 = F::Expand(p1[1]); |
| 439 auto c12 = F::Expand(p1[2]); |
| 440 auto c20 = F::Expand(p2[0]); |
| 441 auto c21 = F::Expand(p2[1]); |
| 442 auto c22 = F::Expand(p2[2]); |
| 443 |
| 444 auto c = add_121(c00, c01, c02) + (add_121(c10, c11, c12) << 1) + add_121(c2
0, c21, c22); |
| 445 *(typename F::Type*)dst = F::Compact(c >> 4); |
| 446 } |
| 447 |
| 448 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 449 |
| 450 size_t SkMipMap::AllocLevelsSize(int levelCount, size_t pixelSize) { |
| 451 if (levelCount < 0) { |
| 452 return 0; |
| 453 } |
| 454 int64_t size = sk_64_mul(levelCount + 1, sizeof(Level)) + pixelSize; |
| 455 if (!sk_64_isS32(size)) { |
| 456 return 0; |
| 457 } |
| 458 return sk_64_asS32(size); |
| 459 } |
| 460 |
| 461 SkMipMap* SkMipMap::Build(const SkBitmap& src, SkDiscardableFactoryProc fact) { |
| 462 typedef void FilterProc(void*, const void* srcPtr, size_t srcRB); |
| 463 |
| 464 FilterProc* proc_2_2 = nullptr; |
| 465 FilterProc* proc_2_3 = nullptr; |
| 466 FilterProc* proc_3_2 = nullptr; |
| 467 FilterProc* proc_3_3 = nullptr; |
| 468 |
| 469 const SkColorType ct = src.colorType(); |
| 470 const SkAlphaType at = src.alphaType(); |
| 471 switch (ct) { |
| 472 case kRGBA_8888_SkColorType: |
| 473 case kBGRA_8888_SkColorType: |
| 474 proc_2_2 = downsample_2_2<ColorTypeFilter_8888>; |
| 475 proc_2_3 = downsample_2_3<ColorTypeFilter_8888>; |
| 476 proc_3_2 = downsample_3_2<ColorTypeFilter_8888>; |
| 477 proc_3_3 = downsample_3_3<ColorTypeFilter_8888>; |
| 478 break; |
| 479 case kRGB_565_SkColorType: |
| 480 proc_2_2 = downsample_2_2<ColorTypeFilter_565>; |
| 481 proc_2_3 = downsample_2_3<ColorTypeFilter_565>; |
| 482 proc_3_2 = downsample_3_2<ColorTypeFilter_565>; |
| 483 proc_3_3 = downsample_3_3<ColorTypeFilter_565>; |
| 484 break; |
| 485 case kARGB_4444_SkColorType: |
| 486 proc_2_2 = downsample_2_2<ColorTypeFilter_4444>; |
| 487 proc_2_3 = downsample_2_3<ColorTypeFilter_4444>; |
| 488 proc_3_2 = downsample_3_2<ColorTypeFilter_4444>; |
| 489 proc_3_3 = downsample_3_3<ColorTypeFilter_4444>; |
| 490 break; |
| 491 case kAlpha_8_SkColorType: |
| 492 case kGray_8_SkColorType: |
| 493 proc_2_2 = downsample_2_2<ColorTypeFilter_8>; |
| 494 proc_2_3 = downsample_2_3<ColorTypeFilter_8>; |
| 495 proc_3_2 = downsample_3_2<ColorTypeFilter_8>; |
| 496 proc_3_3 = downsample_3_3<ColorTypeFilter_8>; |
| 497 break; |
| 498 default: |
| 499 // TODO: We could build miplevels for kIndex8 if the levels were in
8888. |
| 500 // Means using more ram, but the quality would be fine. |
| 501 return nullptr; |
| 502 } |
| 503 |
| 504 // whip through our loop to compute the exact size needed |
| 505 size_t size = 0; |
| 506 int countLevels = 0; |
| 507 { |
| 508 int width = src.width(); |
| 509 int height = src.height(); |
| 510 for (;;) { |
| 511 width >>= 1; |
| 512 height >>= 1; |
| 513 if (0 == width || 0 == height) { |
| 514 break; |
| 515 } |
| 516 size += SkColorTypeMinRowBytes(ct, width) * height; |
| 517 countLevels += 1; |
| 518 } |
| 519 } |
| 520 if (0 == countLevels) { |
| 521 return nullptr; |
| 522 } |
| 523 |
| 524 size_t storageSize = SkMipMap::AllocLevelsSize(countLevels, size); |
| 525 if (0 == storageSize) { |
| 526 return nullptr; |
| 527 } |
| 528 |
| 529 SkAutoPixmapUnlock srcUnlocker; |
| 530 if (!src.requestLock(&srcUnlocker)) { |
| 531 return nullptr; |
| 532 } |
| 533 const SkPixmap& srcPixmap = srcUnlocker.pixmap(); |
| 534 // Try to catch where we might have returned nullptr for src crbug.com/49281
8 |
| 535 if (nullptr == srcPixmap.addr()) { |
| 536 sk_throw(); |
| 537 } |
| 538 |
| 539 SkMipMap* mipmap; |
| 540 if (fact) { |
| 541 SkDiscardableMemory* dm = fact(storageSize); |
| 542 if (nullptr == dm) { |
| 543 return nullptr; |
| 544 } |
| 545 mipmap = new SkMipMap(storageSize, dm); |
| 546 } else { |
| 547 mipmap = new SkMipMap(sk_malloc_throw(storageSize), storageSize); |
| 548 } |
| 549 |
| 550 // init |
| 551 mipmap->fCount = countLevels; |
| 552 mipmap->fLevels = (Level*)mipmap->writable_data(); |
| 553 |
| 554 Level* levels = mipmap->fLevels; |
| 555 uint8_t* baseAddr = (uint8_t*)&levels[countLevels]; |
| 556 uint8_t* addr = baseAddr; |
| 557 int width = src.width(); |
| 558 int height = src.height(); |
| 559 uint32_t rowBytes; |
| 560 SkPixmap srcPM(srcPixmap); |
| 561 |
| 562 int prevW = width; |
| 563 int prevH = height; |
| 564 for (int i = 0; i < countLevels; ++i) { |
| 565 width >>= 1; |
| 566 height >>= 1; |
| 567 rowBytes = SkToU32(SkColorTypeMinRowBytes(ct, width)); |
| 568 |
| 569 levels[i].fPixels = addr; |
| 570 levels[i].fWidth = width; |
| 571 levels[i].fHeight = height; |
| 572 levels[i].fRowBytes = rowBytes; |
| 573 levels[i].fScale = (float)width / src.width(); |
| 574 |
| 575 SkPixmap dstPM(SkImageInfo::Make(width, height, ct, at), addr, rowBytes)
; |
| 576 |
| 577 const size_t pixelSize = srcPM.info().bytesPerPixel(); |
| 578 |
| 579 const void* srcBasePtr = srcPM.addr(); |
| 580 void* dstBasePtr = dstPM.writable_addr(); |
| 581 |
| 582 FilterProc* proc; |
| 583 if (prevH & 1) { // src-height is 3 |
| 584 if (prevW & 1) { // src-width is 3 |
| 585 proc = proc_3_3; |
| 586 } else { // src-width is 2 |
| 587 proc = proc_2_3; |
| 588 } |
| 589 } else { // src-height is 2 |
| 590 if (prevW & 1) { // src-width is 3 |
| 591 proc = proc_3_2; |
| 592 } else { // src-width is 2 |
| 593 proc = proc_2_2; |
| 594 } |
| 595 } |
| 596 |
| 597 const size_t srcRB = srcPM.rowBytes(); |
| 598 for (int y = 0; y < height; y++) { |
| 599 const void* srcPtr = srcBasePtr; |
| 600 void* dstPtr = dstBasePtr; |
| 601 |
| 602 for (int x = 0; x < width; x++) { |
| 603 proc(dstPtr, srcPtr, srcRB); |
| 604 srcPtr = (char*)srcPtr + pixelSize * 2; |
| 605 dstPtr = (char*)dstPtr + pixelSize; |
| 606 } |
| 607 |
| 608 srcBasePtr = (char*)srcBasePtr + srcRB * 2; // jump two rows |
| 609 dstBasePtr = (char*)dstBasePtr + dstPM.rowBytes(); |
| 610 } |
| 611 srcPM = dstPM; |
| 612 addr += height * rowBytes; |
| 613 prevW = width; |
| 614 prevH = height; |
| 615 } |
| 616 SkASSERT(addr == baseAddr + size); |
| 617 |
| 618 return mipmap; |
| 619 } |
| 620 #endif |
| 621 |
321 /////////////////////////////////////////////////////////////////////////////// | 622 /////////////////////////////////////////////////////////////////////////////// |
322 | 623 |
323 bool SkMipMap::extractLevel(SkScalar scale, Level* levelPtr) const { | 624 bool SkMipMap::extractLevel(SkScalar scale, Level* levelPtr) const { |
324 if (nullptr == fLevels) { | 625 if (nullptr == fLevels) { |
325 return false; | 626 return false; |
326 } | 627 } |
327 | 628 |
328 if (scale >= SK_Scalar1 || scale <= 0 || !SkScalarIsFinite(scale)) { | 629 if (scale >= SK_Scalar1 || scale <= 0 || !SkScalarIsFinite(scale)) { |
329 return false; | 630 return false; |
330 } | 631 } |
(...skipping 13 matching lines...) Expand all Loading... |
344 } | 645 } |
345 | 646 |
346 if (level > fCount) { | 647 if (level > fCount) { |
347 level = fCount; | 648 level = fCount; |
348 } | 649 } |
349 if (levelPtr) { | 650 if (levelPtr) { |
350 *levelPtr = fLevels[level - 1]; | 651 *levelPtr = fLevels[level - 1]; |
351 } | 652 } |
352 return true; | 653 return true; |
353 } | 654 } |
OLD | NEW |