Changeset 215069 in webkit


Ignore:
Timestamp:
Apr 6, 2017 5:01:29 PM (7 years ago)
Author:
Simon Fraser
Message:

Use the Accelerate framework to optimize FEColorMatrix operations
https://bugs.webkit.org/show_bug.cgi?id=170518

Reviewed by Tim Horton.

On macOS and iOS, we can use the Accelerate framework (vImage) to do color matrix
math to optimize color matrix, hue rotate, saturation and luminosity to alpha filters.

Change ImageBuffer::getUnmultipliedImageData() and getPremultipliedImageData() to
return the size of the returned Uint8ClampedArray in physical pixels, because we
need to pass that to vImage.

  • html/canvas/CanvasRenderingContext2D.cpp:

(WebCore::CanvasRenderingContext2D::getImageData):

  • platform/graphics/ImageBuffer.h:
  • platform/graphics/cairo/ImageBufferCairo.cpp:

(WebCore::ImageBuffer::getUnmultipliedImageData):
(WebCore::ImageBuffer::getPremultipliedImageData):

  • platform/graphics/cg/ImageBufferCG.cpp:

(WebCore::ImageBuffer::getUnmultipliedImageData):
(WebCore::ImageBuffer::getPremultipliedImageData):

  • platform/graphics/filters/FEColorMatrix.cpp:

(WebCore::effectApplyAccelerated):
(WebCore::effectType):
(WebCore::FEColorMatrix::platformApplySoftware):

  • platform/graphics/filters/FEDropShadow.cpp:

(WebCore::FEDropShadow::platformApplySoftware):

  • platform/graphics/win/ImageBufferDirect2D.cpp:

(WebCore::ImageBuffer::getUnmultipliedImageData):
(WebCore::ImageBuffer::getPremultipliedImageData):

Location:
trunk/Source/WebCore
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r215068 r215069  
     12017-04-05  Simon Fraser  <simon.fraser@apple.com>
     2
     3        Use the Accelerate framework to optimize FEColorMatrix operations
     4        https://bugs.webkit.org/show_bug.cgi?id=170518
     5
     6        Reviewed by Tim Horton.
     7
     8        On macOS and iOS, we can use the Accelerate framework (vImage) to do color matrix
     9        math to optimize color matrix, hue rotate, saturation and luminosity to alpha filters.
     10       
     11        Change ImageBuffer::getUnmultipliedImageData() and getPremultipliedImageData() to
     12        return the size of the returned Uint8ClampedArray in physical pixels, because we
     13        need to pass that to vImage.
     14
     15        * html/canvas/CanvasRenderingContext2D.cpp:
     16        (WebCore::CanvasRenderingContext2D::getImageData):
     17        * platform/graphics/ImageBuffer.h:
     18        * platform/graphics/cairo/ImageBufferCairo.cpp:
     19        (WebCore::ImageBuffer::getUnmultipliedImageData):
     20        (WebCore::ImageBuffer::getPremultipliedImageData):
     21        * platform/graphics/cg/ImageBufferCG.cpp:
     22        (WebCore::ImageBuffer::getUnmultipliedImageData):
     23        (WebCore::ImageBuffer::getPremultipliedImageData):
     24        * platform/graphics/filters/FEColorMatrix.cpp:
     25        (WebCore::effectApplyAccelerated):
     26        (WebCore::effectType):
     27        (WebCore::FEColorMatrix::platformApplySoftware):
     28        * platform/graphics/filters/FEDropShadow.cpp:
     29        (WebCore::FEDropShadow::platformApplySoftware):
     30        * platform/graphics/win/ImageBufferDirect2D.cpp:
     31        (WebCore::ImageBuffer::getUnmultipliedImageData):
     32        (WebCore::ImageBuffer::getPremultipliedImageData):
     33
    1342017-04-04  Simon Fraser  <simon.fraser@apple.com>
    235
  • trunk/Source/WebCore/html/canvas/CanvasRenderingContext2D.cpp

    r210828 r215069  
    20092009        return createEmptyImageData(imageDataRect.size());
    20102010
    2011     auto byteArray = buffer->getUnmultipliedImageData(imageDataRect, coordinateSystem);
     2011    auto byteArray = buffer->getUnmultipliedImageData(imageDataRect, nullptr, coordinateSystem);
    20122012    if (!byteArray) {
    20132013        StringBuilder consoleMessage;
  • trunk/Source/WebCore/platform/graphics/ImageBuffer.h

    r213598 r215069  
    105105    enum CoordinateSystem { LogicalCoordinateSystem, BackingStoreCoordinateSystem };
    106106
    107     RefPtr<Uint8ClampedArray> getUnmultipliedImageData(const IntRect&, CoordinateSystem = LogicalCoordinateSystem) const;
    108     RefPtr<Uint8ClampedArray> getPremultipliedImageData(const IntRect&, CoordinateSystem = LogicalCoordinateSystem) const;
     107    RefPtr<Uint8ClampedArray> getUnmultipliedImageData(const IntRect&, IntSize* pixelArrayDimensions = nullptr, CoordinateSystem = LogicalCoordinateSystem) const;
     108    RefPtr<Uint8ClampedArray> getPremultipliedImageData(const IntRect&, IntSize* pixelArrayDimensions = nullptr, CoordinateSystem = LogicalCoordinateSystem) const;
    109109
    110110    void putByteArray(Multiply multiplied, Uint8ClampedArray*, const IntSize& sourceSize, const IntRect& sourceRect, const IntPoint& destPoint, CoordinateSystem = LogicalCoordinateSystem);
  • trunk/Source/WebCore/platform/graphics/cairo/ImageBufferCairo.cpp

    r214450 r215069  
    434434}
    435435
    436 RefPtr<Uint8ClampedArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect, CoordinateSystem coordinateSystem) const
     436RefPtr<Uint8ClampedArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect, IntSize* pixelArrayDimensions, CoordinateSystem coordinateSystem) const
    437437{
    438438    IntRect logicalRect = logicalUnit(rect, coordinateSystem, m_resolutionScale);
    439439    IntRect backingStoreRect = backingStoreUnit(rect, coordinateSystem, m_resolutionScale);
     440    if (pixelArrayDimensions)
     441        *pixelArrayDimensions = backingStoreRect.size();
    440442    return getImageData<Unmultiplied>(backingStoreRect, logicalRect, m_data, m_size, m_logicalSize, m_resolutionScale);
    441443}
    442444
    443 RefPtr<Uint8ClampedArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect, CoordinateSystem coordinateSystem) const
     445RefPtr<Uint8ClampedArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect, IntSize* pixelArrayDimensions, CoordinateSystem coordinateSystem) const
    444446{
    445447    IntRect logicalRect = logicalUnit(rect, coordinateSystem, m_resolutionScale);
    446448    IntRect backingStoreRect = backingStoreUnit(rect, coordinateSystem, m_resolutionScale);
     449    if (pixelArrayDimensions)
     450        *pixelArrayDimensions = backingStoreRect.size();
    447451    return getImageData<Premultiplied>(backingStoreRect, logicalRect, m_data, m_size, m_logicalSize, m_resolutionScale);
    448452}
  • trunk/Source/WebCore/platform/graphics/cg/ImageBufferCG.cpp

    r213508 r215069  
    383383}
    384384
    385 RefPtr<Uint8ClampedArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect, CoordinateSystem coordinateSystem) const
     385RefPtr<Uint8ClampedArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect, IntSize* pixelArrayDimensions, CoordinateSystem coordinateSystem) const
    386386{
    387387    if (context().isAcceleratedContext())
     
    392392        srcRect.scale(m_resolutionScale);
    393393
     394    if (pixelArrayDimensions)
     395        *pixelArrayDimensions = srcRect.size();
     396
    394397    return m_data.getData(srcRect, internalSize(), context().isAcceleratedContext(), true, 1);
    395398}
    396399
    397 RefPtr<Uint8ClampedArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect, CoordinateSystem coordinateSystem) const
     400RefPtr<Uint8ClampedArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect, IntSize* pixelArrayDimensions, CoordinateSystem coordinateSystem) const
    398401{
    399402    if (context().isAcceleratedContext())
     
    403406    if (coordinateSystem == LogicalCoordinateSystem)
    404407        srcRect.scale(m_resolutionScale);
     408
     409    if (pixelArrayDimensions)
     410        *pixelArrayDimensions = srcRect.size();
    405411
    406412    return m_data.getData(srcRect, internalSize(), context().isAcceleratedContext(), false, 1);
  • trunk/Source/WebCore/platform/graphics/filters/FEColorMatrix.cpp

    r214916 r215069  
    3131#include <wtf/MathExtras.h>
    3232
     33#if USE(ACCELERATE)
     34#include <Accelerate/Accelerate.h>
     35#endif
     36
    3337#define PRINT_FILTER_PERFORMANCE 0
    3438
     
    105109}
    106110
     111#if USE(ACCELERATE)
    107112template<ColorMatrixType filterType>
    108 void effectType(Uint8ClampedArray* pixelArray, const Vector<float>& values)
     113bool effectApplyAccelerated(Uint8ClampedArray* pixelArray, const Vector<float>& values, float components[9], IntSize bufferSize)
     114{
     115    ASSERT(pixelArray->length() == bufferSize.area().unsafeGet() * 4);
     116   
     117    if (filterType == FECOLORMATRIX_TYPE_MATRIX) {
     118        // vImageMatrixMultiply_ARGB8888 takes a 4x4 matrix, if any value in the last column of the FEColorMatrix 5x4 matrix
     119        // is not zero, fall back to non-vImage code.
     120        if (values[4] != 0 || values[9] != 0 || values[14] != 0 || values[19] != 0)
     121            return false;
     122    }
     123
     124    const int32_t divisor = 256;
     125    uint8_t* data = pixelArray->data();
     126
     127    vImage_Buffer src;
     128    src.width = bufferSize.width();
     129    src.height = bufferSize.height();
     130    src.rowBytes = bufferSize.width() * 4;
     131    src.data = data;
     132   
     133    vImage_Buffer dest;
     134    dest.width = bufferSize.width();
     135    dest.height = bufferSize.height();
     136    dest.rowBytes = bufferSize.width() * 4;
     137    dest.data = data;
     138
     139    switch (filterType) {
     140    case FECOLORMATRIX_TYPE_MATRIX: {
     141        const int16_t matrix[4 * 4] = {
     142            static_cast<int16_t>(roundf(values[ 0] * divisor)),
     143            static_cast<int16_t>(roundf(values[ 5] * divisor)),
     144            static_cast<int16_t>(roundf(values[10] * divisor)),
     145            static_cast<int16_t>(roundf(values[15] * divisor)),
     146
     147            static_cast<int16_t>(roundf(values[ 1] * divisor)),
     148            static_cast<int16_t>(roundf(values[ 6] * divisor)),
     149            static_cast<int16_t>(roundf(values[11] * divisor)),
     150            static_cast<int16_t>(roundf(values[16] * divisor)),
     151
     152            static_cast<int16_t>(roundf(values[ 2] * divisor)),
     153            static_cast<int16_t>(roundf(values[ 7] * divisor)),
     154            static_cast<int16_t>(roundf(values[12] * divisor)),
     155            static_cast<int16_t>(roundf(values[17] * divisor)),
     156
     157            static_cast<int16_t>(roundf(values[ 3] * divisor)),
     158            static_cast<int16_t>(roundf(values[ 8] * divisor)),
     159            static_cast<int16_t>(roundf(values[13] * divisor)),
     160            static_cast<int16_t>(roundf(values[18] * divisor)),
     161        };
     162        vImageMatrixMultiply_ARGB8888(&src, &dest, matrix, divisor, nullptr, nullptr, kvImageNoFlags);
     163        break;
     164    }
     165
     166    case FECOLORMATRIX_TYPE_SATURATE:
     167    case FECOLORMATRIX_TYPE_HUEROTATE: {
     168        const int16_t matrix[4 * 4] = {
     169            static_cast<int16_t>(roundf(components[0] * divisor)),
     170            static_cast<int16_t>(roundf(components[3] * divisor)),
     171            static_cast<int16_t>(roundf(components[6] * divisor)),
     172            0,
     173
     174            static_cast<int16_t>(roundf(components[1] * divisor)),
     175            static_cast<int16_t>(roundf(components[4] * divisor)),
     176            static_cast<int16_t>(roundf(components[7] * divisor)),
     177            0,
     178
     179            static_cast<int16_t>(roundf(components[2] * divisor)),
     180            static_cast<int16_t>(roundf(components[5] * divisor)),
     181            static_cast<int16_t>(roundf(components[8] * divisor)),
     182            0,
     183
     184            0,
     185            0,
     186            0,
     187            divisor,
     188        };
     189        vImageMatrixMultiply_ARGB8888(&src, &dest, matrix, divisor, nullptr, nullptr, kvImageNoFlags);
     190        break;
     191    }
     192    case FECOLORMATRIX_TYPE_LUMINANCETOALPHA: {
     193        const int16_t matrix[4 * 4] = {
     194            0,
     195            0,
     196            0,
     197            static_cast<int16_t>(roundf(0.2125 * divisor)),
     198
     199            0,
     200            0,
     201            0,
     202            static_cast<int16_t>(roundf(0.7154 * divisor)),
     203
     204            0,
     205            0,
     206            0,
     207            static_cast<int16_t>(roundf(0.0721 * divisor)),
     208
     209            0,
     210            0,
     211            0,
     212            0,
     213        };
     214        vImageMatrixMultiply_ARGB8888(&src, &dest, matrix, divisor, nullptr, nullptr, kvImageNoFlags);
     215        break;
     216    }
     217    }
     218   
     219    return true;
     220}
     221#endif
     222
     223template<ColorMatrixType filterType>
     224void effectType(Uint8ClampedArray* pixelArray, const Vector<float>& values, IntSize bufferSize)
    109225{
    110226    float components[9];
     
    116232
    117233    unsigned pixelArrayLength = pixelArray->length();
     234
     235#if USE(ACCELERATE)
     236    if (effectApplyAccelerated<filterType>(pixelArray, values, components, bufferSize))
     237        return;
     238#else
     239    UNUSED_PARAM(bufferSize);
     240#endif
    118241
    119242    switch (filterType) {
     
    180303
    181304    IntRect imageRect(IntPoint(), resultImage->logicalSize());
    182     RefPtr<Uint8ClampedArray> pixelArray = resultImage->getUnmultipliedImageData(imageRect);
     305    IntSize pixelArrayDimensions;
     306    RefPtr<Uint8ClampedArray> pixelArray = resultImage->getUnmultipliedImageData(imageRect, &pixelArrayDimensions);
    183307    Vector<float> values = normalizedFloats(m_values);
    184308
     
    187311        break;
    188312    case FECOLORMATRIX_TYPE_MATRIX:
    189         effectType<FECOLORMATRIX_TYPE_MATRIX>(pixelArray.get(), values);
     313        effectType<FECOLORMATRIX_TYPE_MATRIX>(pixelArray.get(), values, pixelArrayDimensions);
    190314        break;
    191315    case FECOLORMATRIX_TYPE_SATURATE:
    192         effectType<FECOLORMATRIX_TYPE_SATURATE>(pixelArray.get(), values);
     316        effectType<FECOLORMATRIX_TYPE_SATURATE>(pixelArray.get(), values, pixelArrayDimensions);
    193317        break;
    194318    case FECOLORMATRIX_TYPE_HUEROTATE:
    195         effectType<FECOLORMATRIX_TYPE_HUEROTATE>(pixelArray.get(), values);
     319        effectType<FECOLORMATRIX_TYPE_HUEROTATE>(pixelArray.get(), values, pixelArrayDimensions);
    196320        break;
    197321    case FECOLORMATRIX_TYPE_LUMINANCETOALPHA:
    198         effectType<FECOLORMATRIX_TYPE_LUMINANCETOALPHA>(pixelArray.get(), values);
     322        effectType<FECOLORMATRIX_TYPE_LUMINANCETOALPHA>(pixelArray.get(), values, pixelArrayDimensions);
    199323        setIsAlphaImage(true);
    200324        break;
  • trunk/Source/WebCore/platform/graphics/filters/FEDropShadow.cpp

    r208058 r215069  
    100100    // TODO: Direct pixel access to ImageBuffer would avoid copying the ImageData.
    101101    IntRect shadowArea(IntPoint(), resultImage->internalSize());
    102     RefPtr<Uint8ClampedArray> srcPixelArray = resultImage->getPremultipliedImageData(shadowArea, ImageBuffer::BackingStoreCoordinateSystem);
     102    RefPtr<Uint8ClampedArray> srcPixelArray = resultImage->getPremultipliedImageData(shadowArea, nullptr, ImageBuffer::BackingStoreCoordinateSystem);
    103103
    104104    contextShadow.blurLayerImage(srcPixelArray->data(), shadowArea.size(), 4 * shadowArea.size().width());
  • trunk/Source/WebCore/platform/graphics/win/ImageBufferDirect2D.cpp

    r213412 r215069  
    216216}
    217217
    218 RefPtr<Uint8ClampedArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect, CoordinateSystem coordinateSystem) const
     218RefPtr<Uint8ClampedArray> ImageBuffer::getUnmultipliedImageData(const IntRect& rect, IntSize* pixelArrayDimensions, CoordinateSystem coordinateSystem) const
    219219{
    220220    if (context().isAcceleratedContext())
     
    225225        srcRect.scale(m_resolutionScale);
    226226
     227    if (pixelArrayDimensions)
     228        *pixelArrayDimensions = srcRect.size();
     229
    227230    return m_data.getData(srcRect, internalSize(), context().isAcceleratedContext(), true, 1);
    228231}
    229232
    230 RefPtr<Uint8ClampedArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect, CoordinateSystem coordinateSystem) const
     233RefPtr<Uint8ClampedArray> ImageBuffer::getPremultipliedImageData(const IntRect& rect, IntSize* pixelArrayDimensions, CoordinateSystem coordinateSystem) const
    231234{
    232235    if (context().isAcceleratedContext())
     
    236239    if (coordinateSystem == LogicalCoordinateSystem)
    237240        srcRect.scale(m_resolutionScale);
     241
     242    if (pixelArrayDimensions)
     243        *pixelArrayDimensions = srcRect.size();
    238244
    239245    return m_data.getData(srcRect, internalSize(), context().isAcceleratedContext(), false, 1);
Note: See TracChangeset for help on using the changeset viewer.