Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(238)

Side by Side Diff: src/core/SkMipMap.cpp

Issue 1592473002: use triangle filter for odd dimensions in mip-levels (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: address naming comments Created 4 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « gm/showmiplevels.cpp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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 }
OLDNEW
« no previous file with comments | « gm/showmiplevels.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698