⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 136189 in webkit


Ignore:
Timestamp:
Nov 29, 2012, 5:15:15 PM (14 years ago)
Author:
commit-queue@webkit.org
Message:

Optimization in image decoding.
​https://bugs.webkit.org/show_bug.cgi?id=88424

Patch by Viatcheslav Ostapenko <​v.ostapenko@samsung.com> on 2012-11-29
Reviewed by Brent Fulgham.

Reduce branching and multiplications in JPEG image decoding loops and functions.
Code is moved to the template functions with scale and color space template parameters
because they were reason of branches inside loops. With templated funtions compiler
will generate separate instance of function for every set of parameters removing
unreachable code in every condition where constant value is used.

Rebase and update of original patch by Misha Tyutyunik <​michael.tyuytunik@nokia.com> .

Thanks to Noel Gordon for his help in cleaning up remaining issues.

Covered by existing tests.

  • platform/image-decoders/jpeg/JPEGImageDecoder.cpp:

(WebCore):
(WebCore::setPixel):
(WebCore::JPEGImageDecoder::outputScanlines):

  • platform/image-decoders/jpeg/JPEGImageDecoder.h:

(JPEGImageDecoder):

Location:
trunk/Source/WebCore
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r136188 r136189  
     12012-11-29  Viatcheslav Ostapenko  <v.ostapenko@samsung.com>
     2
     3        Optimization in image decoding.
     4        https://bugs.webkit.org/show_bug.cgi?id=88424
     5
     6        Reviewed by Brent Fulgham.
     7
     8        Reduce branching and multiplications in JPEG image decoding loops and functions.
     9        Code is moved to the template functions with scale and color space template parameters
     10        because they were reason of branches inside loops. With templated funtions compiler
     11        will generate separate instance of function for every set of parameters removing
     12        unreachable code in every condition where constant value is used.
     13
     14        Rebase and update of original patch by Misha Tyutyunik <michael.tyuytunik@nokia.com> .
     15
     16        Thanks to Noel Gordon for his help in cleaning up remaining issues.
     17
     18        Covered by existing tests.
     19
     20        * platform/image-decoders/jpeg/JPEGImageDecoder.cpp:
     21        (WebCore):
     22        (WebCore::setPixel):
     23        (WebCore::JPEGImageDecoder::outputScanlines):
     24        * platform/image-decoders/jpeg/JPEGImageDecoder.h:
     25        (JPEGImageDecoder):
     26
    1272012-11-29  Kentaro Hara  <haraken@chromium.org>
    228
  • trunk/Source/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.cpp

    r132961 r136189  
    647647}
    648648
     649template <int colorSpace>
     650void setPixel(ImageFrame& buffer, ImageFrame::PixelData* currentAddress, JSAMPARRAY samples, int column)
     651{
     652    JSAMPLE* jsample = *samples + column * (static_cast<J_COLOR_SPACE>(colorSpace) == JCS_RGB ? 3 : 4);
     653
     654    switch (static_cast<J_COLOR_SPACE>(colorSpace)) {
     655#if defined(TURBO_JPEG_RGB_SWIZZLE)
     656    case JCS_EXT_BGRA:
     657        buffer.setRGBA(currentAddress, jsample[2], jsample[1], jsample[1], 0xFF);
     658        break;
     659    case JCS_EXT_RGBA: // Fallback to JSC_RGB case here.
     660#endif
     661    case JCS_RGB:
     662        buffer.setRGBA(currentAddress, jsample[0], jsample[1], jsample[2], 0xFF);
     663        break;
     664    case JCS_CMYK:
     665        // Source is 'Inverted CMYK', output is RGB.
     666        // See: http://www.easyrgb.com/math.php?MATH=M12#text12
     667        // Or: http://www.ilkeratalay.com/colorspacesfaq.php#rgb
     668        // From CMYK to CMY:
     669        // X =   X    * (1 -   K   ) +   K  [for X = C, M, or Y]
     670        // Thus, from Inverted CMYK to CMY is:
     671        // X = (1-iX) * (1 - (1-iK)) + (1-iK) => 1 - iX*iK
     672        // From CMY (0..1) to RGB (0..1):
     673        // R = 1 - C => 1 - (1 - iC*iK) => iC*iK  [G and B similar]
     674        unsigned k = jsample[3];
     675        buffer.setRGBA(currentAddress, jsample[0] * k / 255, jsample[1] * k / 255, jsample[2] * k / 255, 0xFF);
     676        break;
     677    }
     678}
     679
     680template <int colorSpace, bool isScaled>
     681bool JPEGImageDecoder::outputScanlines(ImageFrame& buffer)
     682{
     683    JSAMPARRAY samples = m_reader->samples();
     684    jpeg_decompress_struct* info = m_reader->info();
     685
     686    int width = isScaled ? m_scaledColumns.size() : info->output_width;
     687
     688    while (info->output_scanline < info->output_height) {
     689        // jpeg_read_scanlines will increase the scanline counter, so we
     690        // save the scanline before calling it.
     691        int sourceY = info->output_scanline;
     692        /* Request one scanline.  Returns 0 or 1 scanlines. */
     693        if (jpeg_read_scanlines(info, samples, 1) != 1)
     694            return false;
     695
     696        int destY = scaledY(sourceY);
     697        if (destY < 0)
     698            continue;
     699
     700#if USE(QCMSLIB)
     701        if (m_reader->colorTransform() && colorSpace == JCS_RGB)
     702            qcms_transform_data(m_reader->colorTransform(), *samples, *samples, info->output_width);
     703#endif
     704
     705        ImageFrame::PixelData* currentAddress = buffer.getAddr(0, destY);
     706
     707        for (int x = 0; x < width; ++x) {
     708            setPixel<colorSpace>(buffer, currentAddress, samples, isScaled ? m_scaledColumns[x] : x);
     709            ++currentAddress;
     710        }
     711    }
     712    return true;
     713}
     714
     715template <int colorSpace>
     716bool JPEGImageDecoder::outputScanlines(ImageFrame& buffer)
     717{
     718    return m_scaled ? outputScanlines<colorSpace, true>(buffer) : outputScanlines<colorSpace, false>(buffer);
     719}
     720
    649721bool JPEGImageDecoder::outputScanlines()
    650722{
    … …  
    685757#endif
    686758
    687     JSAMPARRAY samples = m_reader->samples();
    688 
    689     while (info->output_scanline < info->output_height) {
    690         // jpeg_read_scanlines will increase the scanline counter, so we
    691         // save the scanline before calling it.
    692         int sourceY = info->output_scanline;
    693         /* Request one scanline.  Returns 0 or 1 scanlines. */
    694         if (jpeg_read_scanlines(info, samples, 1) != 1)
    695             return false;
    696 
    697         int destY = scaledY(sourceY);
    698         if (destY < 0)
    699             continue;
    700 #if USE(QCMSLIB)
    701         if (m_reader->colorTransform() && info->out_color_space == JCS_RGB)
    702             qcms_transform_data(m_reader->colorTransform(), *samples, *samples, info->output_width);
    703 #endif
    704         int width = m_scaled ? m_scaledColumns.size() : info->output_width;
    705         for (int x = 0; x < width; ++x) {
    706             JSAMPLE* jsample = *samples + (m_scaled ? m_scaledColumns[x] : x) * ((info->out_color_space == JCS_RGB) ? 3 : 4);
    707             if (info->out_color_space == JCS_RGB)
    708                 buffer.setRGBA(x, destY, jsample[0], jsample[1], jsample[2], 0xFF);
     759    switch (info->out_color_space) {
     760    // The code inside outputScanlines<int, bool> will be executed
     761    // for each pixel, so we want to avoid any extra comparisons there.
     762    // That is why we use template and template specializations here so
     763    // the proper code will be generated at compile time.
     764    case JCS_RGB:
     765        return outputScanlines<JCS_RGB>(buffer);
    709766#if defined(TURBO_JPEG_RGB_SWIZZLE)
    710             else if (info->out_color_space == JCS_EXT_RGBA)
    711                 buffer.setRGBA(x, destY, jsample[0], jsample[1], jsample[2], 0xFF);
    712             else if (info->out_color_space == JCS_EXT_BGRA)
    713                 buffer.setRGBA(x, destY, jsample[2], jsample[1], jsample[0], 0xFF);
    714 #endif
    715             else if (info->out_color_space == JCS_CMYK) {
    716                 // Source is 'Inverted CMYK', output is RGB.
    717                 // See: http://www.easyrgb.com/math.php?MATH=M12#text12
    718                 // Or:  http://www.ilkeratalay.com/colorspacesfaq.php#rgb
    719                 // From CMYK to CMY:
    720                 // X =   X    * (1 -   K   ) +   K  [for X = C, M, or Y]
    721                 // Thus, from Inverted CMYK to CMY is:
    722                 // X = (1-iX) * (1 - (1-iK)) + (1-iK) => 1 - iX*iK
    723                 // From CMY (0..1) to RGB (0..1):
    724                 // R = 1 - C => 1 - (1 - iC*iK) => iC*iK  [G and B similar]
    725                 unsigned k = jsample[3];
    726                 buffer.setRGBA(x, destY, jsample[0] * k / 255, jsample[1] * k / 255, jsample[2] * k / 255, 0xFF);
    727             } else {
    728                 ASSERT_NOT_REACHED();
    729                 return setFailed();
    730             }
    731         }
    732     }
    733 
    734     return true;
     767    case JCS_EXT_RGBA:
     768        return outputScanlines<JCS_EXT_RGBA>(buffer);
     769    case JCS_EXT_BGRA:
     770        return outputScanlines<JCS_EXT_BGRA>(buffer);
     771#endif
     772    case JCS_CMYK:
     773        return outputScanlines<JCS_CMYK>(buffer);
     774    default:
     775        ASSERT_NOT_REACHED();
     776    }
     777
     778    return setFailed();
    735779}
    736780
  • trunk/Source/WebCore/platform/image-decoders/jpeg/JPEGImageDecoder.h

    r132260 r136189  
    6363        void decode(bool onlySize);
    6464
     65        template <int colorSpace>
     66        bool outputScanlines(ImageFrame& buffer);
     67
     68        template <int colorSpace, bool isScaled>
     69        bool outputScanlines(ImageFrame& buffer);
     70
    6571        OwnPtr<JPEGImageReader> m_reader;
    6672    };
Note: See TracChangeset for help on using the changeset viewer.