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

Side by Side Diff: src/codec/SkPngCodec.cpp

Issue 1671003004: Skip memcpy() swizzles in SkPngCodec (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: First Approach Created 4 years, 10 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
OLDNEW
1 /* 1 /*
2 * Copyright 2015 Google Inc. 2 * Copyright 2015 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 "SkCodecPriv.h" 8 #include "SkCodecPriv.h"
9 #include "SkColorPriv.h" 9 #include "SkColorPriv.h"
10 #include "SkColorTable.h" 10 #include "SkColorTable.h"
(...skipping 408 matching lines...) Expand 10 before | Expand all | Expand 10 after
419 fSrcConfig = SkSwizzler::kRGBA; 419 fSrcConfig = SkSwizzler::kRGBA;
420 } 420 }
421 } 421 }
422 break; 422 break;
423 } 423 }
424 default: 424 default:
425 // We will always recommend one of the above colorTypes. 425 // We will always recommend one of the above colorTypes.
426 SkASSERT(false); 426 SkASSERT(false);
427 } 427 }
428 428
429 // If we are not performing a subset decode, and the swizzle will not change the
430 // number of bytes per pixel, we can swizzle in place.
431 fInPlaceSwizzle = (SkSwizzler::BytesPerPixel(fSrcConfig) ==
432 SkColorTypeBytesPerPixel(requestedInfo.colorType()) && !options.fSub set);
433
429 // Copy the color table to the client if they request kIndex8 mode 434 // Copy the color table to the client if they request kIndex8 mode
430 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount); 435 copy_color_table(requestedInfo, fColorTable, ctable, ctableCount);
431 436
432 // Create the swizzler. SkPngCodec retains ownership of the color table. 437 // Create the swizzler. SkPngCodec retains ownership of the color table.
433 const SkPMColor* colors = get_color_ptr(fColorTable.get()); 438 const SkPMColor* colors = get_color_ptr(fColorTable.get());
434 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo , options)); 439 fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo , options));
435 SkASSERT(fSwizzler); 440 SkASSERT(fSwizzler);
436 441
437 return kSuccess; 442 return kSuccess;
438 } 443 }
(...skipping 29 matching lines...) Expand all
468 if (options.fSubset) { 473 if (options.fSubset) {
469 // Subsets are not supported. 474 // Subsets are not supported.
470 return kUnimplemented; 475 return kUnimplemented;
471 } 476 }
472 477
473 // Note that ctable and ctableCount may be modified if there is a color tabl e 478 // Note that ctable and ctableCount may be modified if there is a color tabl e
474 const Result result = this->initializeSwizzler(requestedInfo, options, ctabl e, ctableCount); 479 const Result result = this->initializeSwizzler(requestedInfo, options, ctabl e, ctableCount);
475 if (result != kSuccess) { 480 if (result != kSuccess) {
476 return result; 481 return result;
477 } 482 }
483
484 const int width = requestedInfo.width();
485 const int height = requestedInfo.height();
486 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig);
487
478 // FIXME: Could we use the return value of setjmp to specify the type of 488 // FIXME: Could we use the return value of setjmp to specify the type of
479 // error? 489 // error?
480 int row = 0; 490 int row = 0;
481 // This must be declared above the call to setjmp to avoid memory leaks on i ncomplete images. 491 // This must be declared above the call to setjmp to avoid memory leaks on i ncomplete images.
482 SkAutoTMalloc<uint8_t> storage; 492 SkAutoTMalloc<uint8_t> storage;
483 if (setjmp(png_jmpbuf(fPng_ptr))) { 493 if (setjmp(png_jmpbuf(fPng_ptr))) {
484 // Assume that any error that occurs while reading rows is caused by an incomplete input. 494 // Assume that any error that occurs while reading rows is caused by an incomplete input.
485 if (fNumberPasses > 1) { 495 if (fNumberPasses > 1) {
486 // FIXME (msarett): Handle incomplete interlaced pngs. 496 // FIXME (msarett): Handle incomplete interlaced pngs.
487 return kInvalidInput; 497 return row == height ? kSuccess : kInvalidInput;
488 } 498 }
489 // FIXME: We do a poor job on incomplete pngs compared to other decoders (ex: Chromium, 499 // FIXME: We do a poor job on incomplete pngs compared to other decoders (ex: Chromium,
490 // Ubuntu Image Viewer). This is because we use the default buffer size in libpng (8192 500 // Ubuntu Image Viewer). This is because we use the default buffer size in libpng (8192
491 // bytes), and if we can't fill the buffer, we immediately fail. 501 // bytes), and if we can't fill the buffer, we immediately fail.
492 // For example, if we try to read 8192 bytes, and the image (incorrectly ) only contains 502 // For example, if we try to read 8192 bytes, and the image (incorrectly ) only contains
493 // half that, which may have been enough to contain a non-zero number of lines, we fail 503 // half that, which may have been enough to contain a non-zero number of lines, we fail
494 // when we could have decoded a few more lines and then failed. 504 // when we could have decoded a few more lines and then failed.
495 // The read function that we provide for libpng has no way of indicating that we have 505 // The read function that we provide for libpng has no way of indicating that we have
496 // made a partial read. 506 // made a partial read.
497 // Making our buffer size smaller improves our incomplete decodes, but w hat impact does 507 // Making our buffer size smaller improves our incomplete decodes, but w hat impact does
498 // it have on regular decode performance? Should we investigate using a different API 508 // it have on regular decode performance? Should we investigate using a different API
499 // instead of png_read_row(s)? Chromium uses png_process_data. 509 // instead of png_read_row(s)? Chromium uses png_process_data.
500 *rowsDecoded = row; 510 *rowsDecoded = row;
501 return kIncompleteInput; 511 return row == height ? kSuccess : kIncompleteInput;
502 } 512 }
503 513
504 // FIXME: We could split these out based on subclass. 514 // FIXME: We could split these out based on subclass.
505 void* dstRow = dst; 515 void* dstRow = dst;
506 if (fNumberPasses > 1) { 516 if (fNumberPasses > 1) {
507 const int width = requestedInfo.width(); 517 uint8_t* const base = fInPlaceSwizzle ? (uint8_t*) dstRow :
508 const int height = requestedInfo.height(); 518 storage.reset(width * height * bpp);
509 const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig); 519 const size_t srcRowBytes = fInPlaceSwizzle ? dstRowBytes : width * bpp;
510 const size_t srcRowBytes = width * bpp;
511
512 storage.reset(width * height * bpp);
513 uint8_t* const base = storage.get();
514 520
515 for (int i = 0; i < fNumberPasses; i++) { 521 for (int i = 0; i < fNumberPasses; i++) {
516 uint8_t* srcRow = base; 522 uint8_t* srcRow = base;
517 for (int y = 0; y < height; y++) { 523 for (int y = 0; y < height; y++) {
518 uint8_t* bmRow = srcRow; 524 png_read_rows(fPng_ptr, &srcRow, nullptr, 1);
519 png_read_rows(fPng_ptr, &bmRow, nullptr, 1);
520 srcRow += srcRowBytes; 525 srcRow += srcRowBytes;
521 } 526 }
522 } 527 }
523 528
524 // Now swizzle it. 529 // Now swizzle it.
525 uint8_t* srcRow = base; 530 uint8_t* srcRow = base;
526 for (int y = 0; y < height; y++) { 531 for (int y = 0; y < height; y++) {
527 fSwizzler->swizzle(dstRow, srcRow); 532 fSwizzler->swizzle(dstRow, srcRow);
msarett 2016/02/05 20:48:18 Problem: I think this will still perform a functi
528 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 533 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
529 srcRow += srcRowBytes; 534 srcRow += srcRowBytes;
530 } 535 }
531 } else { 536 } else {
532 storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConf ig)); 537 uint8_t* srcRow = fInPlaceSwizzle ? (uint8_t*) dstRow : storage.reset(wi dth * bpp);
533 uint8_t* srcRow = storage.get(); 538 const size_t srcRowBytes = fInPlaceSwizzle ? dstRowBytes : 0;
534 for (; row < requestedInfo.height(); row++) { 539 for (; row < requestedInfo.height(); row++) {
535 png_read_rows(fPng_ptr, &srcRow, nullptr, 1); 540 png_read_rows(fPng_ptr, &srcRow, nullptr, 1);
536 // FIXME: Only call IsOpaque once, outside the loop. Same for onGetS canlines.
537 fSwizzler->swizzle(dstRow, srcRow); 541 fSwizzler->swizzle(dstRow, srcRow);
538 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 542 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
543 srcRow += srcRowBytes;
539 } 544 }
540 } 545 }
541 546
542 if (setjmp(png_jmpbuf(fPng_ptr))) {
543 // We've already read all the scanlines. This is a success.
544 return kSuccess;
545 }
546
547 // read rest of file, and get additional comment and time chunks in info_ptr 547 // read rest of file, and get additional comment and time chunks in info_ptr
548 png_read_end(fPng_ptr, fInfo_ptr); 548 png_read_end(fPng_ptr, fInfo_ptr);
549 549
550 return kSuccess; 550 return kSuccess;
551 } 551 }
552 552
553 uint32_t SkPngCodec::onGetFillValue(SkColorType colorType) const { 553 uint32_t SkPngCodec::onGetFillValue(SkColorType colorType) const {
554 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get()); 554 const SkPMColor* colorPtr = get_color_ptr(fColorTable.get());
555 if (colorPtr) { 555 if (colorPtr) {
556 return get_color_table_fill_value(colorType, colorPtr, 0); 556 return get_color_table_fill_value(colorType, colorPtr, 0);
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
588 int onGetScanlines(void* dst, int count, size_t rowBytes) override { 588 int onGetScanlines(void* dst, int count, size_t rowBytes) override {
589 // Assume that an error in libpng indicates an incomplete input. 589 // Assume that an error in libpng indicates an incomplete input.
590 int row = 0; 590 int row = 0;
591 if (setjmp(png_jmpbuf(this->png_ptr()))) { 591 if (setjmp(png_jmpbuf(this->png_ptr()))) {
592 SkCodecPrintf("setjmp long jump!\n"); 592 SkCodecPrintf("setjmp long jump!\n");
593 return row; 593 return row;
594 } 594 }
595 595
596 void* dstRow = dst; 596 void* dstRow = dst;
597 for (; row < count; row++) { 597 for (; row < count; row++) {
598 png_read_rows(this->png_ptr(), &fSrcRow, nullptr, 1); 598 uint8_t* srcRow = this->inPlaceSwizzle() ? (uint8_t*) dstRow : fSrcR ow;
599 this->swizzler()->swizzle(dstRow, fSrcRow); 599 png_read_rows(this->png_ptr(), &srcRow, nullptr, 1);
600 this->swizzler()->swizzle(dstRow, srcRow);
600 dstRow = SkTAddOffset<void>(dstRow, rowBytes); 601 dstRow = SkTAddOffset<void>(dstRow, rowBytes);
601 } 602 }
602 603
603 return row; 604 return row;
604 } 605 }
605 606
606 bool onSkipScanlines(int count) override { 607 bool onSkipScanlines(int count) override {
607 // Assume that an error in libpng indicates an incomplete input. 608 // Assume that an error in libpng indicates an incomplete input.
608 if (setjmp(png_jmpbuf(this->png_ptr()))) { 609 if (setjmp(png_jmpbuf(this->png_ptr()))) {
609 SkCodecPrintf("setjmp long jump!\n"); 610 SkCodecPrintf("setjmp long jump!\n");
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
683 this->updateCurrScanline(currScanline); 684 this->updateCurrScanline(currScanline);
684 } 685 }
685 686
686 if (setjmp(png_jmpbuf(this->png_ptr()))) { 687 if (setjmp(png_jmpbuf(this->png_ptr()))) {
687 SkCodecPrintf("setjmp long jump!\n"); 688 SkCodecPrintf("setjmp long jump!\n");
688 // FIXME (msarett): Returning 0 is pessimistic. If we can complete a single pass, 689 // FIXME (msarett): Returning 0 is pessimistic. If we can complete a single pass,
689 // we may be able to report that all of the memory has been initiali zed. Even if we 690 // we may be able to report that all of the memory has been initiali zed. Even if we
690 // fail on the first pass, we can still report than some scanlines a re initialized. 691 // fail on the first pass, we can still report than some scanlines a re initialized.
691 return 0; 692 return 0;
692 } 693 }
693 SkAutoTMalloc<uint8_t> storage(count * fSrcRowBytes); 694 SkAutoTMalloc<uint8_t> storage;
694 uint8_t* storagePtr = storage.get(); 695 uint8_t* const base = this->inPlaceSwizzle() ? (uint8_t*) dst :
696 storage.reset(count * fSrcRowBytes);
697 const size_t srcRowBytes = this->inPlaceSwizzle() ? dstRowBytes : fSrcRo wBytes;
695 uint8_t* srcRow; 698 uint8_t* srcRow;
696 const int startRow = this->nextScanline(); 699 const int startRow = this->nextScanline();
697 for (int i = 0; i < this->numberPasses(); i++) { 700 for (int i = 0; i < this->numberPasses(); i++) {
698 // read rows we planned to skip into garbage row 701 // read rows we planned to skip into garbage row
699 for (int y = 0; y < startRow; y++){ 702 for (int y = 0; y < startRow; y++){
700 png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1); 703 png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1);
701 } 704 }
702 // read rows we care about into buffer 705 // read rows we care about into buffer
703 srcRow = storagePtr; 706 uint8_t* srcRow = base;
704 for (int y = 0; y < count; y++) { 707 for (int y = 0; y < count; y++) {
705 png_read_rows(this->png_ptr(), &srcRow, nullptr, 1); 708 png_read_rows(this->png_ptr(), &srcRow, nullptr, 1);
706 srcRow += fSrcRowBytes; 709 srcRow += srcRowBytes;
707 } 710 }
708 // read rows we don't want into garbage buffer 711 // read rows we don't want into garbage buffer
709 for (int y = 0; y < fHeight - startRow - count; y++) { 712 for (int y = 0; y < fHeight - startRow - count; y++) {
710 png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1); 713 png_read_rows(this->png_ptr(), &fGarbageRowPtr, nullptr, 1);
711 } 714 }
712 } 715 }
713 //swizzle the rows we care about 716 //swizzle the rows we care about
714 srcRow = storagePtr; 717 srcRow = base;
715 void* dstRow = dst; 718 void* dstRow = dst;
716 for (int y = 0; y < count; y++) { 719 for (int y = 0; y < count; y++) {
717 this->swizzler()->swizzle(dstRow, srcRow); 720 this->swizzler()->swizzle(dstRow, srcRow);
718 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes); 721 dstRow = SkTAddOffset<void>(dstRow, dstRowBytes);
719 srcRow += fSrcRowBytes; 722 srcRow += srcRowBytes;
720 } 723 }
721 724
722 return count; 725 return count;
723 } 726 }
724 727
725 bool onSkipScanlines(int count) override { 728 bool onSkipScanlines(int count) override {
726 // The non-virtual version will update fCurrScanline. 729 // The non-virtual version will update fCurrScanline.
727 return true; 730 return true;
728 } 731 }
729 732
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
763 } 766 }
764 767
765 if (1 == numberPasses) { 768 if (1 == numberPasses) {
766 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk Reader, 769 return new SkPngScanlineDecoder(imageInfo, streamDeleter.detach(), chunk Reader,
767 png_ptr, info_ptr, bitDepth); 770 png_ptr, info_ptr, bitDepth);
768 } 771 }
769 772
770 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader, 773 return new SkPngInterlacedScanlineDecoder(imageInfo, streamDeleter.detach(), chunkReader,
771 png_ptr, info_ptr, bitDepth, numbe rPasses); 774 png_ptr, info_ptr, bitDepth, numbe rPasses);
772 } 775 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698