Changeset 166084 in webkit


Ignore:
Timestamp:
Mar 21, 2014 12:02:35 PM (10 years ago)
Author:
cavalcantii@gmail.com
Message:

Optimize FEGaussian blur
https://bugs.webkit.org/show_bug.cgi?id=50881

Reviewed by Dirk Schulze.

Currently boxBlur() will calculate the filter for each channel in
a loop and also uses Uint8ClampedArray::set() to write the
resulting pixels into destination array.

Using Uint8ClampedArray::set() requires lots of unnecessary type
conversions, not to mention other function calls. This patch
updates the original written by Simon Fraser to apply cleanly to current
trunk.

It also implements code to handle EdgeModes and finally avoids use
of ::set() in the newly added boxBlurAlphaOnly()
function. Assignment of calculated pixel values rely on pointers.

No new tests, no change on behavior.

  • platform/graphics/filters/FEGaussianBlur.cpp:

(WebCore::boxBlurAlphaOnly): Specialized version for alpha only cases.
(WebCore::boxBlur):

Location:
trunk/Source/WebCore
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r166082 r166084  
     12014-03-21  Adenilson Cavalcanti  <cavalcantii@gmail.com>
     2
     3        Optimize FEGaussian blur
     4        https://bugs.webkit.org/show_bug.cgi?id=50881
     5
     6        Reviewed by Dirk Schulze.
     7
     8        Currently boxBlur() will calculate the filter for each channel in
     9        a loop and also uses Uint8ClampedArray::set() to write the
     10        resulting pixels into destination array.
     11
     12        Using Uint8ClampedArray::set() requires lots of unnecessary type
     13        conversions, not to mention other function calls. This patch
     14        updates the original written by Simon Fraser to apply cleanly to current
     15        trunk.
     16
     17        It also implements code to handle EdgeModes and finally avoids use
     18        of ::set() in the newly added boxBlurAlphaOnly()
     19        function. Assignment of calculated pixel values rely on pointers.
     20
     21        No new tests, no change on behavior.
     22
     23        * platform/graphics/filters/FEGaussianBlur.cpp:
     24        (WebCore::boxBlurAlphaOnly): Specialized version for alpha only cases.
     25        (WebCore::boxBlur):
     26
    1272014-03-21  Simon Fraser  <simon.fraser@apple.com>
    228
  • trunk/Source/WebCore/platform/graphics/filters/FEGaussianBlur.cpp

    r165077 r166084  
    9191}
    9292
    93 inline void boxBlur(Uint8ClampedArray* srcPixelArray, Uint8ClampedArray* dstPixelArray,
    94     unsigned dx, int dxLeft, int dxRight, int stride, int strideLine, int effectWidth, int effectHeight, bool alphaImage, EdgeModeType edgeMode)
    95 {
     93// This function only operates on Alpha channel.
     94inline void boxBlurAlphaOnly(const Uint8ClampedArray* srcPixelArray, Uint8ClampedArray* dstPixelArray,
     95    unsigned dx, int& dxLeft, int& dxRight, int& stride, int& strideLine, int& effectWidth, int& effectHeight, const int& maxKernelSize)
     96{
     97    unsigned char* srcData = srcPixelArray->data();
     98    unsigned char* dstData = dstPixelArray->data();
     99    // Memory alignment is: RGBA, zero-index based.
     100    const int channel = 3;
     101
    96102    for (int y = 0; y < effectHeight; ++y) {
    97103        int line = y * strideLine;
    98         for (int channel = 3; channel >= 0; --channel) {
    99             int sum = 0;
    100             // The code for edgeMode='none' is the common case and highly optimized.
    101             // Furthermore, this code path affects more than just the input area.
    102             if (edgeMode == EDGEMODE_NONE) {
    103                 // Fill the kernel
    104                 int maxKernelSize = std::min(dxRight, effectWidth);
    105                 for (int i = 0; i < maxKernelSize; ++i)
    106                     sum += srcPixelArray->item(line + i * stride + channel);
    107 
    108                 // Blurring
    109                 for (int x = 0; x < effectWidth; ++x) {
    110                     int pixelByteOffset = line + x * stride + channel;
    111                     dstPixelArray->set(pixelByteOffset, static_cast<unsigned char>(sum / dx));
    112                     // Shift kernel.
    113                     if (x >= dxLeft)
    114                         sum -= srcPixelArray->item(pixelByteOffset - dxLeft * stride);
    115                     if (x + dxRight < effectWidth)
    116                         sum += srcPixelArray->item(pixelByteOffset + dxRight * stride);
    117                 }
    118             } else {
    119                 // FIXME: Add support for 'wrap' here.
    120                 // Get edge values for edgeMode 'duplicate'.
    121                 int edgeValueLeft = srcPixelArray->item(line + channel);
    122                 int edgeValueRight = srcPixelArray->item(line + (effectWidth - 1) * stride + channel);
    123                 // Fill the kernel
    124                 for (int i = dxLeft * -1; i < dxRight; ++i) {
    125                     if (i < 0)
    126                         sum += edgeValueLeft;
    127                     else if (i >= effectWidth)
    128                         sum += edgeValueRight;
    129                     else
    130                         sum += srcPixelArray->item(line + i * stride + channel);
    131                 }
    132                 // Blurring
    133                 for (int x = 0; x < effectWidth; ++x) {
    134                     int pixelByteOffset = line + x * stride + channel;
    135                     dstPixelArray->set(pixelByteOffset, static_cast<unsigned char>(sum / dx));
    136                     // Shift kernel.
    137                     if (x < dxLeft)
    138                         sum -= edgeValueLeft;
    139                     else
    140                         sum -= srcPixelArray->item(pixelByteOffset - dxLeft * stride);
    141                     if (x + dxRight >= effectWidth)
    142                         sum += edgeValueRight;
    143                     else
    144                         sum += srcPixelArray->item(pixelByteOffset + dxRight * stride);
    145                 }
    146             }
    147             if (alphaImage) // Source image is black, it just has different alpha values
    148                 break;
     104        int sum = 0;
     105
     106        // Fill the kernel.
     107        for (int i = 0; i < maxKernelSize; ++i) {
     108            unsigned offset = line + i * stride;
     109            unsigned char* srcPtr = srcData + offset;
     110            sum += srcPtr[channel];
     111        }
     112
     113        // Blurring.
     114        for (int x = 0; x < effectWidth; ++x) {
     115            unsigned pixelByteOffset = line + x * stride + channel;
     116            unsigned char* dstPtr = dstData + pixelByteOffset;
     117            *dstPtr = static_cast<unsigned char>(sum / dx);
     118
     119            // Shift kernel.
     120            if (x >= dxLeft) {
     121                unsigned leftOffset = pixelByteOffset - dxLeft * stride;
     122                unsigned char* srcPtr = srcData + leftOffset;
     123                sum -= *srcPtr;
     124            }
     125
     126            if (x + dxRight < effectWidth) {
     127                unsigned rightOffset = pixelByteOffset + dxRight * stride;
     128                unsigned char* srcPtr = srcData + rightOffset;
     129                sum += *srcPtr;
     130            }
     131        }
     132    }
     133}
     134
     135inline void boxBlur(const Uint8ClampedArray* srcPixelArray, Uint8ClampedArray* dstPixelArray,
     136    unsigned dx, int dxLeft, int dxRight, int stride, int strideLine, int effectWidth, int effectHeight, bool alphaImage, EdgeModeType edgeMode)
     137{
     138    const int maxKernelSize = std::min(dxRight, effectWidth);
     139    if (alphaImage) {
     140        return boxBlurAlphaOnly(srcPixelArray, dstPixelArray, dx, dxLeft, dxRight, stride, strideLine,
     141            effectWidth, effectHeight, maxKernelSize);
     142    }
     143
     144    unsigned char* srcData = srcPixelArray->data();
     145    unsigned char* dstData = dstPixelArray->data();
     146
     147    // Concerning the array width/length: it is Element size + Margin + Border. The number of pixels will be
     148    // P = width * height * channels.
     149    for (int y = 0; y < effectHeight; ++y) {
     150        int line = y * strideLine;
     151        int sumR = 0, sumG = 0, sumB = 0, sumA = 0;
     152
     153        if (edgeMode == EDGEMODE_NONE) {
     154            // Fill the kernel.
     155            for (int i = 0; i < maxKernelSize; ++i) {
     156                unsigned offset = line + i * stride;
     157                unsigned char* srcPtr = srcData + offset;
     158                sumR += *srcPtr++;
     159                sumG += *srcPtr++;
     160                sumB += *srcPtr++;
     161                sumA += *srcPtr;
     162            }
     163
     164            // Blurring.
     165            for (int x = 0; x < effectWidth; ++x) {
     166                unsigned pixelByteOffset = line + x * stride;
     167                unsigned char* dstPtr = dstData + pixelByteOffset;
     168
     169                *dstPtr++ = static_cast<unsigned char>(sumR / dx);
     170                *dstPtr++ = static_cast<unsigned char>(sumG / dx);
     171                *dstPtr++ = static_cast<unsigned char>(sumB / dx);
     172                *dstPtr = static_cast<unsigned char>(sumA / dx);
     173
     174                // Shift kernel.
     175                if (x >= dxLeft) {
     176                    unsigned leftOffset = pixelByteOffset - dxLeft * stride;
     177                    unsigned char* srcPtr = srcData + leftOffset;
     178                    sumR -= srcPtr[0];
     179                    sumG -= srcPtr[1];
     180                    sumB -= srcPtr[2];
     181                    sumA -= srcPtr[3];
     182                }
     183
     184                if (x + dxRight < effectWidth) {
     185                    unsigned rightOffset = pixelByteOffset + dxRight * stride;
     186                    unsigned char* srcPtr = srcData + rightOffset;
     187                    sumR += srcPtr[0];
     188                    sumG += srcPtr[1];
     189                    sumB += srcPtr[2];
     190                    sumA += srcPtr[3];
     191                }
     192            }
     193
     194        } else {
     195            // FIXME: Add support for 'wrap' here.
     196            // Get edge values for edgeMode 'duplicate'.
     197            unsigned char* edgeValueLeft = srcData + line;
     198            unsigned char* edgeValueRight  = srcData + (line + (effectWidth - 1) * stride);
     199
     200            // Fill the kernel.
     201            for (int i = dxLeft * -1; i < dxRight; ++i) {
     202                // Is this right for negative values of 'i'?
     203                unsigned offset = line + i * stride;
     204                unsigned char* srcPtr = srcData + offset;
     205
     206                if (i < 0) {
     207                    sumR += edgeValueLeft[0];
     208                    sumG += edgeValueLeft[1];
     209                    sumB += edgeValueLeft[2];
     210                    sumA += edgeValueLeft[3];
     211                } else if (i >= effectWidth) {
     212                    sumR += edgeValueRight[0];
     213                    sumG += edgeValueRight[1];
     214                    sumB += edgeValueRight[2];
     215                    sumA += edgeValueRight[3];
     216                } else {
     217                    sumR += *srcPtr++;
     218                    sumG += *srcPtr++;
     219                    sumB += *srcPtr++;
     220                    sumA += *srcPtr;
     221                }
     222            }
     223
     224            // Blurring.
     225            for (int x = 0; x < effectWidth; ++x) {
     226                unsigned pixelByteOffset = line + x * stride;
     227                unsigned char* dstPtr = dstData + pixelByteOffset;
     228
     229                *dstPtr++ = static_cast<unsigned char>(sumR / dx);
     230                *dstPtr++ = static_cast<unsigned char>(sumG / dx);
     231                *dstPtr++ = static_cast<unsigned char>(sumB / dx);
     232                *dstPtr = static_cast<unsigned char>(sumA / dx);
     233
     234                // Shift kernel.
     235                if (x < dxLeft) {
     236                    sumR -= edgeValueLeft[0];
     237                    sumG -= edgeValueLeft[1];
     238                    sumB -= edgeValueLeft[2];
     239                    sumA -= edgeValueLeft[3];
     240                } else {
     241                    unsigned leftOffset = pixelByteOffset - dxLeft * stride;
     242                    unsigned char* srcPtr = srcData + leftOffset;
     243                    sumR -= srcPtr[0];
     244                    sumG -= srcPtr[1];
     245                    sumB -= srcPtr[2];
     246                    sumA -= srcPtr[3];
     247                }
     248
     249                if (x + dxRight >= effectWidth) {
     250                    sumR += edgeValueRight[0];
     251                    sumG += edgeValueRight[1];
     252                    sumB += edgeValueRight[2];
     253                    sumA += edgeValueRight[3];
     254                } else {
     255                    unsigned rightOffset = pixelByteOffset + dxRight * stride;
     256                    unsigned char* srcPtr = srcData + rightOffset;
     257                    sumR += srcPtr[0];
     258                    sumG += srcPtr[1];
     259                    sumB += srcPtr[2];
     260                    sumA += srcPtr[3];
     261                }
     262            }
    149263        }
    150264    }
Note: See TracChangeset for help on using the changeset viewer.