FELighting cleanup and optimization
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 23 Nov 2017 22:20:09 +0000 (22:20 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 23 Nov 2017 22:20:09 +0000 (22:20 +0000)
https://bugs.webkit.org/show_bug.cgi?id=179933

Reviewed by Darin Adler.

Make FELighting about 25% faster by maintaining an "alpha" window of the alpha
values of the 9 pixels surrounding the current pixel, and sliding this window over
when moving to the next pixel. This avoids reading the same alpha values from the original
buffer multiple times.

Clean up LightSource and subclasses, adding SPECIALIZE_TYPE_TRAITS macros,
and turning updatePaintingData() into a function with no side effects that returns
the required data.

Remove explicit 'inline' keywords, allowing the compiler to make inlining decisions.

* platform/graphics/cpu/arm/filters/FELightingNEON.h:
(WebCore::FELighting::platformApplyNeon):
* platform/graphics/filters/DistantLightSource.cpp:
(WebCore::DistantLightSource::initPaintingData):
(WebCore::DistantLightSource::computePixelLightingData const):
(WebCore::DistantLightSource::updatePaintingData): Deleted.
* platform/graphics/filters/DistantLightSource.h:
* platform/graphics/filters/FELighting.cpp:
(WebCore::FELighting::LightingData::interiorNormal const):
(WebCore::FELighting::setPixel):
(WebCore::FELighting::setPixelInternal):
(WebCore::FELighting::platformApplyGenericPaint):
(WebCore::FELighting::platformApplyGeneric):
(WebCore::FELighting::platformApply):
(WebCore::FELighting::drawLighting):
(WebCore::FELighting::inlineSetPixel): Deleted.
* platform/graphics/filters/FELighting.h:
(WebCore::FELighting::AlphaWindow::topLeft const):
(WebCore::FELighting::AlphaWindow::left const):
(WebCore::FELighting::AlphaWindow::bottomLeft const):
(WebCore::FELighting::AlphaWindow::top const):
(WebCore::FELighting::AlphaWindow::center const):
(WebCore::FELighting::AlphaWindow::bottom const):
(WebCore::FELighting::AlphaWindow::setTop):
(WebCore::FELighting::AlphaWindow::setCenter):
(WebCore::FELighting::AlphaWindow::setBottom):
(WebCore::FELighting::AlphaWindow::setTopRight):
(WebCore::FELighting::AlphaWindow::setRight):
(WebCore::FELighting::AlphaWindow::setBottomRight):
(WebCore::FELighting::AlphaWindow::shiftRow):
(WebCore::FELighting::AlphaWindow::shift):
* platform/graphics/filters/LightSource.h:
* platform/graphics/filters/PointLightSource.cpp:
(WebCore::PointLightSource::computePixelLightingData const):
(WebCore::PointLightSource::updatePaintingData): Deleted.
* platform/graphics/filters/PointLightSource.h:
* platform/graphics/filters/SpotLightSource.cpp:
(WebCore::SpotLightSource::initPaintingData):
(WebCore::SpotLightSource::computePixelLightingData const):
(WebCore::SpotLightSource::updatePaintingData): Deleted.
* platform/graphics/filters/SpotLightSource.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@225122 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/cpu/arm/filters/FELightingNEON.h
Source/WebCore/platform/graphics/filters/DistantLightSource.cpp
Source/WebCore/platform/graphics/filters/DistantLightSource.h
Source/WebCore/platform/graphics/filters/FELighting.cpp
Source/WebCore/platform/graphics/filters/FELighting.h
Source/WebCore/platform/graphics/filters/LightSource.h
Source/WebCore/platform/graphics/filters/PointLightSource.cpp
Source/WebCore/platform/graphics/filters/PointLightSource.h
Source/WebCore/platform/graphics/filters/SpotLightSource.cpp
Source/WebCore/platform/graphics/filters/SpotLightSource.h

index fc9c6e4..8bbf4fb 100644 (file)
@@ -1,5 +1,65 @@
 2017-11-23  Simon Fraser  <simon.fraser@apple.com>
 
+        FELighting cleanup and optimization
+        https://bugs.webkit.org/show_bug.cgi?id=179933
+
+        Reviewed by Darin Adler.
+
+        Make FELighting about 25% faster by maintaining an "alpha" window of the alpha
+        values of the 9 pixels surrounding the current pixel, and sliding this window over
+        when moving to the next pixel. This avoids reading the same alpha values from the original
+        buffer multiple times.
+
+        Clean up LightSource and subclasses, adding SPECIALIZE_TYPE_TRAITS macros,
+        and turning updatePaintingData() into a function with no side effects that returns
+        the required data.
+
+        Remove explicit 'inline' keywords, allowing the compiler to make inlining decisions.
+
+        * platform/graphics/cpu/arm/filters/FELightingNEON.h:
+        (WebCore::FELighting::platformApplyNeon):
+        * platform/graphics/filters/DistantLightSource.cpp:
+        (WebCore::DistantLightSource::initPaintingData):
+        (WebCore::DistantLightSource::computePixelLightingData const):
+        (WebCore::DistantLightSource::updatePaintingData): Deleted.
+        * platform/graphics/filters/DistantLightSource.h:
+        * platform/graphics/filters/FELighting.cpp:
+        (WebCore::FELighting::LightingData::interiorNormal const):
+        (WebCore::FELighting::setPixel):
+        (WebCore::FELighting::setPixelInternal):
+        (WebCore::FELighting::platformApplyGenericPaint):
+        (WebCore::FELighting::platformApplyGeneric):
+        (WebCore::FELighting::platformApply):
+        (WebCore::FELighting::drawLighting):
+        (WebCore::FELighting::inlineSetPixel): Deleted.
+        * platform/graphics/filters/FELighting.h:
+        (WebCore::FELighting::AlphaWindow::topLeft const):
+        (WebCore::FELighting::AlphaWindow::left const):
+        (WebCore::FELighting::AlphaWindow::bottomLeft const):
+        (WebCore::FELighting::AlphaWindow::top const):
+        (WebCore::FELighting::AlphaWindow::center const):
+        (WebCore::FELighting::AlphaWindow::bottom const):
+        (WebCore::FELighting::AlphaWindow::setTop):
+        (WebCore::FELighting::AlphaWindow::setCenter):
+        (WebCore::FELighting::AlphaWindow::setBottom):
+        (WebCore::FELighting::AlphaWindow::setTopRight):
+        (WebCore::FELighting::AlphaWindow::setRight):
+        (WebCore::FELighting::AlphaWindow::setBottomRight):
+        (WebCore::FELighting::AlphaWindow::shiftRow):
+        (WebCore::FELighting::AlphaWindow::shift):
+        * platform/graphics/filters/LightSource.h:
+        * platform/graphics/filters/PointLightSource.cpp:
+        (WebCore::PointLightSource::computePixelLightingData const):
+        (WebCore::PointLightSource::updatePaintingData): Deleted.
+        * platform/graphics/filters/PointLightSource.h:
+        * platform/graphics/filters/SpotLightSource.cpp:
+        (WebCore::SpotLightSource::initPaintingData):
+        (WebCore::SpotLightSource::computePixelLightingData const):
+        (WebCore::SpotLightSource::updatePaintingData): Deleted.
+        * platform/graphics/filters/SpotLightSource.h:
+
+2017-11-23  Simon Fraser  <simon.fraser@apple.com>
+
         Add support for CanvasPattern.setTransform()
         https://bugs.webkit.org/show_bug.cgi?id=179935
 
index 51dda17..abb32e5 100644 (file)
@@ -93,7 +93,7 @@ extern "C" {
 void neonDrawLighting(FELightingPaintingDataForNeon*);
 }
 
-inline void FELighting::platformApplyNeon(LightingData& data, LightSource::PaintingData& paintingData)
+inline void FELighting::platformApplyNeon(const LightingData& data, const LightSource::PaintingData& paintingData)
 {
     FELightingFloatArgumentsForNeon floatArguments __attribute__((__aligned__(16)));
     FELightingPaintingDataForNeon neonData = {
index b2e5531..8c7a4ba 100644 (file)
@@ -39,14 +39,17 @@ void DistantLightSource::initPaintingData(PaintingData& paintingData)
 {
     float azimuth = deg2rad(m_azimuth);
     float elevation = deg2rad(m_elevation);
-    paintingData.lightVector.setX(cosf(azimuth) * cosf(elevation));
-    paintingData.lightVector.setY(sinf(azimuth) * cosf(elevation));
-    paintingData.lightVector.setZ(sinf(elevation));
-    paintingData.lightVectorLength = 1;
+    paintingData.intialLightingData.lightVector = {
+        std::cos(azimuth) * std::cos(elevation),
+        std::sin(azimuth) * std::cos(elevation),
+        std::sin(elevation)
+    };
+    paintingData.intialLightingData.lightVectorLength = 1;
 }
 
-void DistantLightSource::updatePaintingData(PaintingData&, int, int, float)
+LightSource::ComputedLightingData DistantLightSource::computePixelLightingData(const PaintingData& paintingData, int, int, float) const
 {
+    return paintingData.intialLightingData;
 }
 
 bool DistantLightSource::setAzimuth(float azimuth)
index 6dba6d4..c00e524 100644 (file)
@@ -20,8 +20,7 @@
  * Boston, MA 02110-1301, USA.
  */
 
-#ifndef DistantLightSource_h
-#define DistantLightSource_h
+#pragma once
 
 #include "LightSource.h"
 #include <wtf/Ref.h>
@@ -35,6 +34,7 @@ public:
         return adoptRef(*new DistantLightSource(azimuth, elevation));
     }
 
+    // These are in degrees.
     float azimuth() const { return m_azimuth; }
     float elevation() const { return m_elevation; }
 
@@ -42,7 +42,7 @@ public:
     bool setElevation(float) override;
 
     void initPaintingData(PaintingData&) override;
-    void updatePaintingData(PaintingData&, int x, int y, float z) override;
+    ComputedLightingData computePixelLightingData(const PaintingData&, int x, int y, float z) const final;
 
     WTF::TextStream& externalRepresentation(WTF::TextStream&) const override;
 
@@ -60,4 +60,4 @@ private:
 
 } // namespace WebCore
 
-#endif // DistantLightSource_h
+SPECIALIZE_TYPE_TRAITS_LIGHTSOURCE(DistantLightSource, LS_DISTANT)
index 0e15090..6e14064 100644 (file)
@@ -84,7 +84,7 @@ bool FELighting::setKernelUnitLengthY(float kernelUnitLengthY)
 
 const static int cPixelSize = 4;
 const static int cAlphaChannelOffset = 3;
-const static unsigned char cOpaqueAlpha = static_cast<unsigned char>(0xff);
+const static uint8_t cOpaqueAlpha = static_cast<uint8_t>(0xFF);
 
 // These factors and the normal coefficients come from the table under https://www.w3.org/TR/SVG/filters.html#feDiffuseLightingElement.
 const static float cFactor1div2 = -1 / 2.f;
@@ -149,18 +149,30 @@ inline IntSize FELighting::LightingData::leftColumnNormal(int offset) const
     };
 }
 
-inline IntSize FELighting::LightingData::interiorNormal(int offset) const
+inline IntSize FELighting::LightingData::interiorNormal(int offset, AlphaWindow& alphaWindow) const
 {
-    int left = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset));
-    int right = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset));
-    offset -= widthMultipliedByPixelSize;
-    int topLeft = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset));
-    int top = static_cast<int>(pixels->item(offset + cAlphaChannelOffset));
-    int topRight = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset));
-    offset += 2 * widthMultipliedByPixelSize;
-    int bottomLeft = static_cast<int>(pixels->item(offset - cPixelSize + cAlphaChannelOffset));
-    int bottom = static_cast<int>(pixels->item(offset + cAlphaChannelOffset));
-    int bottomRight = static_cast<int>(pixels->item(offset + cPixelSize + cAlphaChannelOffset));
+    int rightAlphaOffset = offset + cPixelSize + cAlphaChannelOffset;
+    
+    int right = static_cast<int>(pixels->item(rightAlphaOffset));
+    int topRight = static_cast<int>(pixels->item(rightAlphaOffset - widthMultipliedByPixelSize));
+    int bottomRight = static_cast<int>(pixels->item(rightAlphaOffset + widthMultipliedByPixelSize));
+
+    int left = alphaWindow.left();
+    int topLeft = alphaWindow.topLeft();
+    int top = alphaWindow.top();
+
+    int bottomLeft = alphaWindow.bottomLeft();
+    int bottom = alphaWindow.bottom();
+
+    // The alphaWindow has been shifted, and here we fill in the right column.
+    alphaWindow.alpha[0][2] = topRight;
+    alphaWindow.alpha[1][2] = right;
+    alphaWindow.alpha[2][2] = bottomRight;
+    
+    // Check that the alphaWindow is working with some spot-checks.
+    ASSERT(alphaWindow.topLeft() == pixels->item(offset - cPixelSize - widthMultipliedByPixelSize + cAlphaChannelOffset)); // topLeft
+    ASSERT(alphaWindow.top() == pixels->item(offset - widthMultipliedByPixelSize + cAlphaChannelOffset)); // top
+
     return {
         -topLeft + topRight - 2 * left + 2 * right - bottomLeft + bottomRight,
         -topLeft - 2 * top - topRight + bottomLeft + 2 * bottom + bottomRight
@@ -224,18 +236,27 @@ inline IntSize FELighting::LightingData::bottomRightNormal(int offset) const
     };
 }
 
-inline void FELighting::inlineSetPixel(int offset, LightingData& data, LightSource::PaintingData& paintingData, int lightX, int lightY, float factorX, float factorY, IntSize normal2DVector)
+void FELighting::setPixel(int offset, const LightingData& data, const LightSource::PaintingData& paintingData, int x, int y, float factorX, float factorY, IntSize normal2DVector)
 {
-    m_lightSource->updatePaintingData(paintingData, lightX, lightY, static_cast<float>(data.pixels->item(offset + cAlphaChannelOffset)) * data.surfaceScale);
+    setPixelInternal(offset, data, paintingData, x, y, factorX, factorY, normal2DVector, data.pixels->item(offset + cAlphaChannelOffset));
+}
+
+void FELighting::setPixelInternal(int offset, const LightingData& data, const LightSource::PaintingData& paintingData, int x, int y, float factorX, float factorY, IntSize normal2DVector, float alpha)
+{
+    float z = alpha * data.surfaceScale;
+    LightSource::ComputedLightingData lightingData = m_lightSource->computePixelLightingData(paintingData, x, y, z);
 
     float lightStrength;
     if (normal2DVector.isZero()) {
         // Normal vector is (0, 0, 1). This is a quite frequent case.
         if (m_lightingType == FELighting::DiffuseLighting)
-            lightStrength = m_diffuseConstant * paintingData.lightVector.z() / paintingData.lightVectorLength;
+            lightStrength = m_diffuseConstant * lightingData.lightVector.z() / lightingData.lightVectorLength;
         else {
-            FloatPoint3D halfwayVector = paintingData.lightVector;
-            halfwayVector.setZ(halfwayVector.z() + paintingData.lightVectorLength);
+            FloatPoint3D halfwayVector = {
+                lightingData.lightVector.x(),
+                lightingData.lightVector.y(),
+                lightingData.lightVector.z() + lightingData.lightVectorLength
+            };
             float halfwayVectorLength = halfwayVector.length();
             if (m_specularExponent == 1)
                 lightStrength = m_specularConstant * halfwayVector.z() / halfwayVectorLength;
@@ -243,17 +264,21 @@ inline void FELighting::inlineSetPixel(int offset, LightingData& data, LightSour
                 lightStrength = m_specularConstant * powf(halfwayVector.z() / halfwayVectorLength, m_specularExponent);
         }
     } else {
-        FloatPoint3D normalVector;
-        normalVector.setX(factorX * static_cast<float>(normal2DVector.width()) * data.surfaceScale);
-        normalVector.setY(factorY * static_cast<float>(normal2DVector.height()) * data.surfaceScale);
-        normalVector.setZ(1);
+        FloatPoint3D normalVector = {
+            factorX * normal2DVector.width() * data.surfaceScale,
+            factorY * normal2DVector.height() * data.surfaceScale,
+            1.0f
+        };
         float normalVectorLength = normalVector.length();
 
         if (m_lightingType == FELighting::DiffuseLighting)
-            lightStrength = m_diffuseConstant * (normalVector * paintingData.lightVector) / (normalVectorLength * paintingData.lightVectorLength);
+            lightStrength = m_diffuseConstant * (normalVector * lightingData.lightVector) / (normalVectorLength * lightingData.lightVectorLength);
         else {
-            FloatPoint3D halfwayVector = paintingData.lightVector;
-            halfwayVector.setZ(halfwayVector.z() + paintingData.lightVectorLength);
+            FloatPoint3D halfwayVector = {
+                lightingData.lightVector.x(),
+                lightingData.lightVector.y(),
+                lightingData.lightVector.z() + lightingData.lightVectorLength
+            };
             float halfwayVectorLength = halfwayVector.length();
             if (m_specularExponent == 1)
                 lightStrength = m_specularConstant * (normalVector * halfwayVector) / (normalVectorLength * halfwayVectorLength);
@@ -267,22 +292,43 @@ inline void FELighting::inlineSetPixel(int offset, LightingData& data, LightSour
     if (lightStrength < 0)
         lightStrength = 0;
 
-    data.pixels->set(offset, static_cast<unsigned char>(lightStrength * paintingData.colorVector.x()));
-    data.pixels->set(offset + 1, static_cast<unsigned char>(lightStrength * paintingData.colorVector.y()));
-    data.pixels->set(offset + 2, static_cast<unsigned char>(lightStrength * paintingData.colorVector.z()));
+    uint8_t pixelValue[3] = {
+        static_cast<uint8_t>(lightStrength * lightingData.colorVector.x()),
+        static_cast<uint8_t>(lightStrength * lightingData.colorVector.y()),
+        static_cast<uint8_t>(lightStrength * lightingData.colorVector.z())
+    };
+    
+    data.pixels->setRange(pixelValue, 3, offset);
 }
 
-void FELighting::setPixel(int offset, LightingData& data, LightSource::PaintingData& paintingData, int lightX, int lightY, float factorX, float factorY, IntSize normalVector)
+// This appears to read from and write to the same pixel buffer, but it only reads the alpha channel, and writes the non-alpha channels.
+void FELighting::platformApplyGenericPaint(const LightingData& data, const LightSource::PaintingData& paintingData, int startY, int endY)
 {
-    inlineSetPixel(offset, data, paintingData, lightX, lightY, factorX, factorY, normalVector);
-}
+    // Make sure startY is > 0 since we read from the previous row in the loop.
+    ASSERT(startY);
 
-inline void FELighting::platformApplyGenericPaint(LightingData& data, LightSource::PaintingData& paintingData, int startY, int endY)
-{
     for (int y = startY; y < endY; ++y) {
-        int offset = y * data.widthMultipliedByPixelSize + cPixelSize;
+        int rowStartOffset = y * data.widthMultipliedByPixelSize;
+        int previousRowStart = rowStartOffset - data.widthMultipliedByPixelSize;
+        int nextRowStart = rowStartOffset + data.widthMultipliedByPixelSize;
+
+        // alphaWindow is a local cache of alpha values.
+        // Fill the two right columns putting the left edge value in the center column.
+        // For each pixel, we shift each row left then fill the right column.
+        AlphaWindow alphaWindow;
+        alphaWindow.setTop(data.pixels->item(previousRowStart + cAlphaChannelOffset));
+        alphaWindow.setTopRight(data.pixels->item(previousRowStart + cPixelSize + cAlphaChannelOffset));
+
+        alphaWindow.setCenter(data.pixels->item(rowStartOffset + cAlphaChannelOffset));
+        alphaWindow.setRight(data.pixels->item(rowStartOffset + cPixelSize + cAlphaChannelOffset));
+
+        alphaWindow.setBottom(data.pixels->item(nextRowStart + cAlphaChannelOffset));
+        alphaWindow.setBottomRight(data.pixels->item(nextRowStart + cPixelSize + cAlphaChannelOffset));
+
+        int offset = rowStartOffset + cPixelSize;
         for (int x = 1; x < data.widthDecreasedByOne; ++x, offset += cPixelSize) {
-            inlineSetPixel(offset, data, paintingData, x, y, cFactor1div4, cFactor1div4, data.interiorNormal(offset));
+            alphaWindow.shift();
+            setPixelInternal(offset, data, paintingData, x, y, cFactor1div4, cFactor1div4, data.interiorNormal(offset, alphaWindow), alphaWindow.center());
         }
     }
 }
@@ -292,7 +338,7 @@ void FELighting::platformApplyGenericWorker(PlatformApplyGenericParameters* para
     parameters->filter->platformApplyGenericPaint(parameters->data, parameters->paintingData, parameters->yStart, parameters->yEnd);
 }
 
-inline void FELighting::platformApplyGeneric(LightingData& data, LightSource::PaintingData& paintingData)
+void FELighting::platformApplyGeneric(const LightingData& data, const LightSource::PaintingData& paintingData)
 {
     int optimalThreadNumber = ((data.widthDecreasedByOne - 1) * (data.heightDecreasedByOne - 1)) / s_minimalRectDimension;
     if (optimalThreadNumber > 1) {
@@ -326,7 +372,7 @@ inline void FELighting::platformApplyGeneric(LightingData& data, LightSource::Pa
     platformApplyGenericPaint(data, paintingData, 1, data.heightDecreasedByOne);
 }
 
-inline void FELighting::platformApply(LightingData& data, LightSource::PaintingData& paintingData)
+inline void FELighting::platformApply(const LightingData& data, const LightSource::PaintingData& paintingData)
 {
     // The selection here eventually should happen dynamically on some platforms.
 #if CPU(ARM_NEON) && CPU(ARM_TRADITIONAL) && COMPILER(GCC_OR_CLANG)
@@ -351,7 +397,7 @@ bool FELighting::drawLighting(Uint8ClampedArray* pixels, int width, int height)
     data.widthMultipliedByPixelSize = width * cPixelSize;
     data.widthDecreasedByOne = width - 1;
     data.heightDecreasedByOne = height - 1;
-    paintingData.colorVector = FloatPoint3D(m_lightingColor.red(), m_lightingColor.green(), m_lightingColor.blue());
+    paintingData.intialLightingData.colorVector = FloatPoint3D(m_lightingColor.red(), m_lightingColor.green(), m_lightingColor.blue());
     m_lightSource->initPaintingData(paintingData);
 
     // Top left.
@@ -374,24 +420,24 @@ bool FELighting::drawLighting(Uint8ClampedArray* pixels, int width, int height)
         // Top row.
         offset = cPixelSize;
         for (int x = 1; x < data.widthDecreasedByOne; ++x, offset += cPixelSize)
-            inlineSetPixel(offset, data, paintingData, x, 0, cFactor1div3, cFactor1div2, data.topRowNormal(offset));
+            setPixel(offset, data, paintingData, x, 0, cFactor1div3, cFactor1div2, data.topRowNormal(offset));
 
         // Bottom row.
         offset = data.heightDecreasedByOne * data.widthMultipliedByPixelSize + cPixelSize;
         for (int x = 1; x < data.widthDecreasedByOne; ++x, offset += cPixelSize)
-            inlineSetPixel(offset, data, paintingData, x, data.heightDecreasedByOne, cFactor1div3, cFactor1div2, data.bottomRowNormal(offset));
+            setPixel(offset, data, paintingData, x, data.heightDecreasedByOne, cFactor1div3, cFactor1div2, data.bottomRowNormal(offset));
     }
 
     if (height >= 3) {
         // Left column.
         offset = data.widthMultipliedByPixelSize;
         for (int y = 1; y < data.heightDecreasedByOne; ++y, offset += data.widthMultipliedByPixelSize)
-            inlineSetPixel(offset, data, paintingData, 0, y, cFactor1div2, cFactor1div3, data.leftColumnNormal(offset));
+            setPixel(offset, data, paintingData, 0, y, cFactor1div2, cFactor1div3, data.leftColumnNormal(offset));
 
         // Right column.
         offset = 2 * data.widthMultipliedByPixelSize - cPixelSize;
         for (int y = 1; y < data.heightDecreasedByOne; ++y, offset += data.widthMultipliedByPixelSize)
-            inlineSetPixel(offset, data, paintingData, data.widthDecreasedByOne, y, cFactor1div2, cFactor1div3, data.rightColumnNormal(offset));
+            setPixel(offset, data, paintingData, data.widthDecreasedByOne, y, cFactor1div2, cFactor1div3, data.rightColumnNormal(offset));
     }
 
     if (width >= 3 && height >= 3) {
@@ -405,9 +451,9 @@ bool FELighting::drawLighting(Uint8ClampedArray* pixels, int width, int height)
             data.pixels->set(i, cOpaqueAlpha);
     } else {
         for (int i = 0; i < lastPixel; i += cPixelSize) {
-            unsigned char a1 = data.pixels->item(i);
-            unsigned char a2 = data.pixels->item(i + 1);
-            unsigned char a3 = data.pixels->item(i + 2);
+            uint8_t a1 = data.pixels->item(i);
+            uint8_t a2 = data.pixels->item(i + 1);
+            uint8_t a3 = data.pixels->item(i + 2);
             // alpha set to set to max(a1, a2, a3)
             data.pixels->set(i + 3, a1 >= a2 ? (a1 >= a3 ? a1 : a3) : (a2 >= a3 ? a2 : a3));
         }
index b41a2e1..3e1ef0a 100644 (file)
@@ -63,6 +63,40 @@ protected:
         DiffuseLighting,
         SpecularLighting
     };
+    
+    struct AlphaWindow {
+        uint8_t alpha[3][3] { };
+        
+        // The implementations are lined up to make comparing indices easier.
+        uint8_t topLeft() const             { return alpha[0][0]; }
+        uint8_t left() const                { return alpha[1][0]; }
+        uint8_t bottomLeft() const          { return alpha[2][0]; }
+
+        uint8_t top() const                 { return alpha[0][1]; }
+        uint8_t center() const              { return alpha[1][1]; }
+        uint8_t bottom() const              { return alpha[2][1]; }
+
+        void setTop(uint8_t value)          { alpha[0][1] = value; }
+        void setCenter(uint8_t value)       { alpha[1][1] = value; }
+        void setBottom(uint8_t value)       { alpha[2][1] = value; }
+
+        void setTopRight(uint8_t value)     { alpha[0][2] = value; }
+        void setRight(uint8_t value)        { alpha[1][2] = value; }
+        void setBottomRight(uint8_t value)  { alpha[2][2] = value; }
+
+        static void shiftRow(uint8_t alpha[3])
+        {
+            alpha[0] = alpha[1];
+            alpha[1] = alpha[2];
+        }
+        
+        void shift()
+        {
+            shiftRow(alpha[0]);
+            shiftRow(alpha[1]);
+            shiftRow(alpha[2]);
+        }
+    };
 
     struct LightingData {
         // This structure contains only read-only (SMP safe) data
@@ -76,7 +110,7 @@ protected:
         inline IntSize topRowNormal(int offset) const;
         inline IntSize topRightNormal(int offset) const;
         inline IntSize leftColumnNormal(int offset) const;
-        inline IntSize interiorNormal(int offset) const;
+        inline IntSize interiorNormal(int offset, AlphaWindow&) const;
         inline IntSize rightColumnNormal(int offset) const;
         inline IntSize bottomLeftNormal(int offset) const;
         inline IntSize bottomRowNormal(int offset) const;
@@ -100,23 +134,20 @@ protected:
     FELighting(Filter&, LightingType, const Color&, float, float, float, float, float, float, Ref<LightSource>&&);
 
     bool drawLighting(Uint8ClampedArray*, int, int);
-    inline void inlineSetPixel(int offset, LightingData&, LightSource::PaintingData&,
-        int lightX, int lightY, float factorX, float factorY, IntSize normalVector);
 
-    // Not worth to inline every occurence of setPixel.
-    void setPixel(int offset, LightingData&, LightSource::PaintingData&,
-        int lightX, int lightY, float factorX, float factorY, IntSize normalVector);
+    void setPixel(int offset, const LightingData&, const LightSource::PaintingData&, int x, int y, float factorX, float factorY, IntSize normalVector);
+    void setPixelInternal(int offset, const LightingData&, const LightSource::PaintingData&, int x, int y, float factorX, float factorY, IntSize normalVector, float alpha);
 
     void platformApplySoftware() override;
 
-    inline void platformApply(LightingData&, LightSource::PaintingData&);
+    void platformApply(const LightingData&, const LightSource::PaintingData&);
 
-    inline void platformApplyGenericPaint(LightingData&, LightSource::PaintingData&, int startX, int startY);
-    inline void platformApplyGeneric(LightingData&, LightSource::PaintingData&);
+    void platformApplyGenericPaint(const LightingData&, const LightSource::PaintingData&, int startX, int startY);
+    void platformApplyGeneric(const LightingData&, const LightSource::PaintingData&);
 
 #if CPU(ARM_NEON) && CPU(ARM_TRADITIONAL) && COMPILER(GCC_OR_CLANG)
     static int getPowerCoefficients(float exponent);
-    inline void platformApplyNeon(LightingData&, LightSource::PaintingData&);
+    inline void platformApplyNeon(const LightingData&, const LightSource::PaintingData&);
 #endif
 
     LightingType m_lightingType;
index 1450290..c222ec1 100644 (file)
@@ -21,8 +21,7 @@
  * Boston, MA 02110-1301, USA.
  */
 
-#ifndef LightSource_h
-#define LightSource_h
+#pragma once
 
 #include "FloatPoint3D.h"
 #include <wtf/RefCounted.h>
@@ -41,20 +40,15 @@ enum LightType {
 
 class LightSource : public RefCounted<LightSource> {
 public:
-
-    // Light vectors must be calculated for every pixel during
-    // painting. It is expensive to pass all these arguments to
-    // a frequently called function, especially because not all
-    // light sources require all of them. Instead, we just pass
-    // a reference to the following structure
-    struct PaintingData {
-        // SVGFELighting also use them
+    struct ComputedLightingData {
         FloatPoint3D lightVector;
         FloatPoint3D colorVector;
         float lightVectorLength;
-        // Private members
+    };
+
+    struct PaintingData {
+        ComputedLightingData intialLightingData;
         FloatPoint3D directionVector;
-        FloatPoint3D privateColorVector;
         float coneCutOffLimit;
         float coneFullLight;
         int specularExponent;
@@ -72,7 +66,7 @@ public:
     virtual void initPaintingData(PaintingData&) = 0;
     // z is a float number, since it is the alpha value scaled by a user
     // specified "surfaceScale" constant, which type is <number> in the SVG standard
-    virtual void updatePaintingData(PaintingData&, int x, int y, float z) = 0;
+    virtual ComputedLightingData computePixelLightingData(const PaintingData&, int x, int y, float z) const = 0;
 
     virtual bool setAzimuth(float) { return false; }
     virtual bool setElevation(float) { return false; }
@@ -91,4 +85,7 @@ private:
 
 } // namespace WebCore
 
-#endif // LightSource_h
+#define SPECIALIZE_TYPE_TRAITS_LIGHTSOURCE(ClassName, Type) \
+SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ClassName) \
+    static bool isType(const WebCore::LightSource& source) { return source.type() == WebCore::Type; } \
+SPECIALIZE_TYPE_TRAITS_END()
index 7cc485c..4e18367 100644 (file)
@@ -39,12 +39,15 @@ void PointLightSource::initPaintingData(PaintingData&)
 {
 }
 
-void PointLightSource::updatePaintingData(PaintingData& paintingData, int x, int y, float z)
+LightSource::ComputedLightingData PointLightSource::computePixelLightingData(const PaintingData&, int x, int y, float z) const
 {
-    paintingData.lightVector.setX(m_position.x() - x);
-    paintingData.lightVector.setY(m_position.y() - y);
-    paintingData.lightVector.setZ(m_position.z() - z);
-    paintingData.lightVectorLength = paintingData.lightVector.length();
+    FloatPoint3D lightVector = {
+        m_position.x() - x,
+        m_position.y() - y,
+        m_position.z() - z
+    };
+
+    return { lightVector, { }, lightVector.length() };
 }
 
 bool PointLightSource::setX(float x)
index 5d43087..ee73dd6 100644 (file)
@@ -20,8 +20,7 @@
  * Boston, MA 02110-1301, USA.
  */
 
-#ifndef PointLightSource_h
-#define PointLightSource_h
+#pragma once
 
 #include "LightSource.h"
 #include <wtf/Ref.h>
@@ -41,7 +40,7 @@ public:
     bool setZ(float) override;
 
     void initPaintingData(PaintingData&) override;
-    void updatePaintingData(PaintingData&, int x, int y, float z) override;
+    ComputedLightingData computePixelLightingData(const PaintingData&, int x, int y, float z) const final;
 
     WTF::TextStream& externalRepresentation(WTF::TextStream&) const override;
 
@@ -57,4 +56,4 @@ private:
 
 } // namespace WebCore
 
-#endif // PointLightSource_h
+SPECIALIZE_TYPE_TRAITS_LIGHTSOURCE(PointLightSource, LS_POINT)
index 0f7fb56..6962d32 100644 (file)
@@ -42,10 +42,7 @@ static const float antiAliasTreshold = 0.016f;
 
 void SpotLightSource::initPaintingData(PaintingData& paintingData)
 {
-    paintingData.privateColorVector = paintingData.colorVector;
-    paintingData.directionVector.setX(m_direction.x() - m_position.x());
-    paintingData.directionVector.setY(m_direction.y() - m_position.y());
-    paintingData.directionVector.setZ(m_direction.z() - m_position.z());
+    paintingData.directionVector = m_direction - m_position;
     paintingData.directionVector.normalize();
 
     if (!m_limitingConeAngle) {
@@ -70,20 +67,19 @@ void SpotLightSource::initPaintingData(PaintingData& paintingData)
         paintingData.specularExponent = 2;
 }
 
-void SpotLightSource::updatePaintingData(PaintingData& paintingData, int x, int y, float z)
+LightSource::ComputedLightingData SpotLightSource::computePixelLightingData(const PaintingData& paintingData, int x, int y, float z) const
 {
-    paintingData.lightVector.setX(m_position.x() - x);
-    paintingData.lightVector.setY(m_position.y() - y);
-    paintingData.lightVector.setZ(m_position.z() - z);
-    paintingData.lightVectorLength = paintingData.lightVector.length();
-
-    float cosineOfAngle = (paintingData.lightVector * paintingData.directionVector) / paintingData.lightVectorLength;
+    FloatPoint3D lightVector = {
+        m_position.x() - x,
+        m_position.y() - y,
+        m_position.z() - z
+    };
+    float lightVectorLength = lightVector.length();
+
+    float cosineOfAngle = (lightVector * paintingData.directionVector) / lightVectorLength;
     if (cosineOfAngle > paintingData.coneCutOffLimit) {
         // No light is produced, scanlines are not updated
-        paintingData.colorVector.setX(0.0f);
-        paintingData.colorVector.setY(0.0f);
-        paintingData.colorVector.setZ(0.0f);
-        return;
+        return { lightVector, { }, lightVectorLength };
     }
 
     // Set the color of the pixel
@@ -106,9 +102,11 @@ void SpotLightSource::updatePaintingData(PaintingData& paintingData, int x, int
     if (lightStrength > 1.0f)
         lightStrength = 1.0f;
 
-    paintingData.colorVector.setX(paintingData.privateColorVector.x() * lightStrength);
-    paintingData.colorVector.setY(paintingData.privateColorVector.y() * lightStrength);
-    paintingData.colorVector.setZ(paintingData.privateColorVector.z() * lightStrength);
+    return {
+        lightVector,
+        paintingData.intialLightingData.colorVector * lightStrength,
+        lightVectorLength
+    };
 }
 
 bool SpotLightSource::setX(float x)
index 539ea06..41991af 100644 (file)
@@ -20,8 +20,7 @@
  * Boston, MA 02110-1301, USA.
  */
 
-#ifndef SpotLightSource_h
-#define SpotLightSource_h
+#pragma once
 
 #include "LightSource.h"
 #include <wtf/Ref.h>
@@ -52,7 +51,7 @@ public:
     bool setLimitingConeAngle(float) override;
 
     void initPaintingData(PaintingData&) override;
-    void updatePaintingData(PaintingData&, int x, int y, float z) override;
+    ComputedLightingData computePixelLightingData(const PaintingData&, int x, int y, float z) const final;
 
     WTF::TextStream& externalRepresentation(WTF::TextStream&) const override;
 
@@ -76,4 +75,4 @@ private:
 
 } // namespace WebCore
 
-#endif // SpotLightSource_h
+SPECIALIZE_TYPE_TRAITS_LIGHTSOURCE(SpotLightSource, LS_SPOT)