FETurbulence: compute all 4 channels at once
authorsimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 18 Nov 2017 02:32:00 +0000 (02:32 +0000)
committersimon.fraser@apple.com <simon.fraser@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 18 Nov 2017 02:32:00 +0000 (02:32 +0000)
https://bugs.webkit.org/show_bug.cgi?id=179833

Reviewed by Sam Weinig.

Introduce some new helper classes for storing float color components, and use
them in calculateTurbulenceValueForPoint() and noise2D() for all the channels in one
pass. This makes FETurbulence about twice as fast.

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* platform/graphics/ColorUtilities.cpp: Added.
(WebCore::ColorComponents::ColorComponents):
* platform/graphics/ColorUtilities.h: Added.
(WebCore::FloatComponents::FloatComponents):
(WebCore::FloatComponents::operator +=):
(WebCore::FloatComponents::operator + const):
(WebCore::FloatComponents::operator / const):
(WebCore::FloatComponents::operator * const):
(WebCore::FloatComponents::abs const):
(WebCore::clampedColorComponent):
* platform/graphics/filters/FETurbulence.cpp:
(WebCore::FETurbulence::noise2D):
(WebCore::FETurbulence::calculateTurbulenceValueForPoint):
(WebCore::FETurbulence::fillRegion):
(WebCore::FETurbulence::platformApplySoftware):
* platform/graphics/filters/FETurbulence.h:

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

Source/WebCore/ChangeLog
Source/WebCore/Sources.txt
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/platform/graphics/ColorUtilities.cpp [new file with mode: 0644]
Source/WebCore/platform/graphics/ColorUtilities.h [new file with mode: 0644]
Source/WebCore/platform/graphics/filters/FETurbulence.cpp
Source/WebCore/platform/graphics/filters/FETurbulence.h

index f1a94d7..88a97d4 100644 (file)
@@ -1,3 +1,33 @@
+2017-11-17  Simon Fraser  <simon.fraser@apple.com>
+
+        FETurbulence: compute all 4 channels at once
+        https://bugs.webkit.org/show_bug.cgi?id=179833
+
+        Reviewed by Sam Weinig.
+
+        Introduce some new helper classes for storing float color components, and use
+        them in calculateTurbulenceValueForPoint() and noise2D() for all the channels in one
+        pass. This makes FETurbulence about twice as fast.
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * platform/graphics/ColorUtilities.cpp: Added.
+        (WebCore::ColorComponents::ColorComponents):
+        * platform/graphics/ColorUtilities.h: Added.
+        (WebCore::FloatComponents::FloatComponents):
+        (WebCore::FloatComponents::operator +=):
+        (WebCore::FloatComponents::operator + const):
+        (WebCore::FloatComponents::operator / const):
+        (WebCore::FloatComponents::operator * const):
+        (WebCore::FloatComponents::abs const):
+        (WebCore::clampedColorComponent):
+        * platform/graphics/filters/FETurbulence.cpp:
+        (WebCore::FETurbulence::noise2D):
+        (WebCore::FETurbulence::calculateTurbulenceValueForPoint):
+        (WebCore::FETurbulence::fillRegion):
+        (WebCore::FETurbulence::platformApplySoftware):
+        * platform/graphics/filters/FETurbulence.h:
+
 2017-11-17  Chris Dumez  <cdumez@apple.com>
 
         Use a strongly typed identifier for SWServer::Connection
index 17ea608..b13ccc4 100644 (file)
@@ -1481,6 +1481,7 @@ platform/encryptedmedia/CDMFactory.cpp
 
 platform/graphics/BitmapImage.cpp
 platform/graphics/Color.cpp
+platform/graphics/ColorUtilities.cpp
 platform/graphics/ComplexTextController.cpp
 platform/graphics/CrossfadeGeneratedImage.cpp
 platform/graphics/DisplayRefreshMonitor.cpp
index b506775..7760c0c 100644 (file)
                0FE5FBCF1C3DD51E0007A2CA /* DisplayListRecorder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DisplayListRecorder.h; path = displaylists/DisplayListRecorder.h; sourceTree = "<group>"; };
                0FE5FBD01C3DD51E0007A2CA /* DisplayListReplayer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DisplayListReplayer.cpp; path = displaylists/DisplayListReplayer.cpp; sourceTree = "<group>"; };
                0FE5FBD11C3DD51E0007A2CA /* DisplayListReplayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DisplayListReplayer.h; path = displaylists/DisplayListReplayer.h; sourceTree = "<group>"; };
+               0FE6C76B1FBFB7A60025C053 /* ColorUtilities.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ColorUtilities.cpp; sourceTree = "<group>"; };
+               0FE6C76C1FBFB7A60025C053 /* ColorUtilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ColorUtilities.h; sourceTree = "<group>"; };
                0FE71403142170B800DB33BA /* ScrollbarThemeMock.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScrollbarThemeMock.cpp; sourceTree = "<group>"; };
                0FE71404142170B800DB33BA /* ScrollbarThemeMock.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScrollbarThemeMock.h; sourceTree = "<group>"; };
                0FE71415142189FC00DB33BA /* ScrollbarTheme.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScrollbarTheme.cpp; sourceTree = "<group>"; };
                                B27535390B053814002CE64F /* Color.h */,
                                3103B7DE1DB01556008BB890 /* ColorHash.h */,
                                9382DF5710A8D5C900925652 /* ColorSpace.h */,
+                               0FE6C76B1FBFB7A60025C053 /* ColorUtilities.cpp */,
+                               0FE6C76C1FBFB7A60025C053 /* ColorUtilities.h */,
                                C2F4E7881E45AEDF006D7105 /* ComplexTextController.cpp */,
                                C2F4E7891E45AEDF006D7105 /* ComplexTextController.h */,
                                2D2FC0541460CD6F00263633 /* CrossfadeGeneratedImage.cpp */,
diff --git a/Source/WebCore/platform/graphics/ColorUtilities.cpp b/Source/WebCore/platform/graphics/ColorUtilities.cpp
new file mode 100644 (file)
index 0000000..12181d7
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ColorUtilities.h"
+
+namespace WebCore {
+
+ColorComponents::ColorComponents(const FloatComponents& floatComponents)
+{
+    components[0] = clampedColorComponent(floatComponents.components[0]);
+    components[1] = clampedColorComponent(floatComponents.components[1]);
+    components[2] = clampedColorComponent(floatComponents.components[2]);
+    components[3] = clampedColorComponent(floatComponents.components[3]);
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/platform/graphics/ColorUtilities.h b/Source/WebCore/platform/graphics/ColorUtilities.h
new file mode 100644 (file)
index 0000000..a976951
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2017 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <math.h>
+
+namespace WebCore {
+
+struct FloatComponents {
+    FloatComponents(float a = 0, float b = 0, float c = 0, float d = 0)
+    {
+        components[0] = a;
+        components[1] = b;
+        components[2] = c;
+        components[3] = d;
+    }
+
+    FloatComponents& operator+=(const FloatComponents& rhs)
+    {
+        components[0] += rhs.components[0];
+        components[1] += rhs.components[1];
+        components[2] += rhs.components[2];
+        components[3] += rhs.components[3];
+        return *this;
+    }
+
+    FloatComponents operator+(float rhs) const
+    {
+        FloatComponents result;
+        result.components[0] = components[0] + rhs;
+        result.components[1] = components[1] + rhs;
+        result.components[2] = components[2] + rhs;
+        result.components[3] = components[3] + rhs;
+        return result;
+    }
+
+    FloatComponents operator/(float denominator) const
+    {
+        FloatComponents result;
+        result.components[0] = components[0] / denominator;
+        result.components[1] = components[1] / denominator;
+        result.components[2] = components[2] / denominator;
+        result.components[3] = components[3] / denominator;
+        return result;
+    }
+
+    FloatComponents operator*(float factor) const
+    {
+        FloatComponents result;
+        result.components[0] = components[0] * factor;
+        result.components[1] = components[1] * factor;
+        result.components[2] = components[2] * factor;
+        result.components[3] = components[3] * factor;
+        return result;
+    }
+
+    FloatComponents abs() const
+    {
+        FloatComponents result;
+        result.components[0] = fabs(components[0]);
+        result.components[1] = fabs(components[1]);
+        result.components[2] = fabs(components[2]);
+        result.components[3] = fabs(components[3]);
+        return result;
+    }
+
+    float components[4];
+};
+
+struct ColorComponents {
+    ColorComponents() = default;
+    ColorComponents(const FloatComponents&);
+    uint8_t components[4] { };
+};
+
+inline uint8_t clampedColorComponent(float f)
+{
+    // See also colorFloatToRGBAByte().
+    return std::max(0, std::min(static_cast<int>(lroundf(255.0f * f)), 255));
+}
+
+} // namespace WebCore
+
index 0366539..a9cbabb 100644 (file)
@@ -5,6 +5,7 @@
  * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
  * Copyright (C) 2010 Renata Hodovan <reni@inf.u-szeged.hu>
  * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
+ * Copyright (C) 2017 Apple Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -186,7 +187,7 @@ inline void checkNoise(int& noiseValue, int limitValue, int newValue)
         noiseValue -= newValue - 1;
 }
 
-float FETurbulence::noise2D(int channel, const PaintingData& paintingData, StitchData& stitchData, const FloatPoint& noiseVector)
+FloatComponents FETurbulence::noise2D(const PaintingData& paintingData, StitchData& stitchData, const FloatPoint& noiseVector)
 {
     struct Noise {
         int noisePositionIntegerValue;
@@ -216,33 +217,44 @@ float FETurbulence::noise2D(int channel, const PaintingData& paintingData, Stitc
 
     float sx = smoothCurve(noiseX.noisePositionFractionValue);
     float sy = smoothCurve(noiseY.noisePositionFractionValue);
-    float a, b, u, v;
-
-    // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement.
-    int temp = paintingData.latticeSelector[latticeIndex + noiseY.noisePositionIntegerValue];
-    const float* q = paintingData.gradient[channel][temp];
-    u = noiseX.noisePositionFractionValue * q[0] + noiseY.noisePositionFractionValue * q[1];
-    temp = paintingData.latticeSelector[nextLatticeIndex + noiseY.noisePositionIntegerValue];
-    q = paintingData.gradient[channel][temp];
-    v = (noiseX.noisePositionFractionValue - 1) * q[0] + noiseY.noisePositionFractionValue * q[1];
-    a = linearInterpolation(sx, u, v);
-    temp = paintingData.latticeSelector[latticeIndex + noiseY.noisePositionIntegerValue + 1];
-    q = paintingData.gradient[channel][temp];
-    u = noiseX.noisePositionFractionValue * q[0] + (noiseY.noisePositionFractionValue - 1) * q[1];
-    temp = paintingData.latticeSelector[nextLatticeIndex + noiseY.noisePositionIntegerValue + 1];
-    q = paintingData.gradient[channel][temp];
-    v = (noiseX.noisePositionFractionValue - 1) * q[0] + (noiseY.noisePositionFractionValue - 1) * q[1];
-    b = linearInterpolation(sx, u, v);
-    return linearInterpolation(sy, a, b);
+
+    auto noiseForChannel = [&](int channel) {
+        // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement.
+        int temp = paintingData.latticeSelector[latticeIndex + noiseY.noisePositionIntegerValue];
+        const float* q = paintingData.gradient[channel][temp];
+
+        float u = noiseX.noisePositionFractionValue * q[0] + noiseY.noisePositionFractionValue * q[1];
+        temp = paintingData.latticeSelector[nextLatticeIndex + noiseY.noisePositionIntegerValue];
+        q = paintingData.gradient[channel][temp];
+        float v = (noiseX.noisePositionFractionValue - 1) * q[0] + noiseY.noisePositionFractionValue * q[1];
+        float a = linearInterpolation(sx, u, v);
+        temp = paintingData.latticeSelector[latticeIndex + noiseY.noisePositionIntegerValue + 1];
+        q = paintingData.gradient[channel][temp];
+        u = noiseX.noisePositionFractionValue * q[0] + (noiseY.noisePositionFractionValue - 1) * q[1];
+        temp = paintingData.latticeSelector[nextLatticeIndex + noiseY.noisePositionIntegerValue + 1];
+        q = paintingData.gradient[channel][temp];
+        v = (noiseX.noisePositionFractionValue - 1) * q[0] + (noiseY.noisePositionFractionValue - 1) * q[1];
+        float b = linearInterpolation(sx, u, v);
+
+        return linearInterpolation(sy, a, b);
+    };
+
+    return {
+        noiseForChannel(0),
+        noiseForChannel(1),
+        noiseForChannel(2),
+        noiseForChannel(3)
+    };
 }
 
-unsigned char FETurbulence::calculateTurbulenceValueForPoint(int channel, const PaintingData& paintingData, StitchData& stitchData, const FloatPoint& point)
+ColorComponents FETurbulence::calculateTurbulenceValueForPoint(const PaintingData& paintingData, StitchData& stitchData, const FloatPoint& point)
 {
     float tileWidth = paintingData.filterSize.width();
     float tileHeight = paintingData.filterSize.height();
     ASSERT(tileWidth > 0 && tileHeight > 0);
     float baseFrequencyX = m_baseFrequencyX;
     float baseFrequencyY = m_baseFrequencyY;
+
     // Adjust the base frequencies if necessary for stitching.
     if (m_stitchTiles) {
         // When stitching tiled turbulence, the frequencies must be adjusted
@@ -271,17 +283,19 @@ unsigned char FETurbulence::calculateTurbulenceValueForPoint(int channel, const
         stitchData.wrapY = s_perlinNoise + stitchData.height;
     }
 
-    float turbulenceFunctionResult = 0;
+    FloatComponents turbulenceFunctionResult;
     FloatPoint noiseVector(point.x() * baseFrequencyX, point.y() * baseFrequencyY);
     float ratio = 1;
     for (int octave = 0; octave < m_numOctaves; ++octave) {
         if (m_type == FETURBULENCE_TYPE_FRACTALNOISE)
-            turbulenceFunctionResult += noise2D(channel, paintingData, stitchData, noiseVector) / ratio;
+            turbulenceFunctionResult += noise2D(paintingData, stitchData, noiseVector) / ratio;
         else
-            turbulenceFunctionResult += fabsf(noise2D(channel, paintingData, stitchData, noiseVector)) / ratio;
+            turbulenceFunctionResult += noise2D(paintingData, stitchData, noiseVector).abs() / ratio;
+
         noiseVector.setX(noiseVector.x() * 2);
         noiseVector.setY(noiseVector.y() * 2);
         ratio *= 2;
+
         if (m_stitchTiles) {
             // Update stitch values. Subtracting s_perlinNoiseoise before the multiplication and
             // adding it afterward simplifies to subtracting it once.
@@ -296,9 +310,8 @@ unsigned char FETurbulence::calculateTurbulenceValueForPoint(int channel, const
     // and (turbulenceFunctionResult * 255) by turbulence.
     if (m_type == FETURBULENCE_TYPE_FRACTALNOISE)
         turbulenceFunctionResult = turbulenceFunctionResult * 0.5f + 0.5f;
-    // Clamp result
-    turbulenceFunctionResult = std::max(std::min(turbulenceFunctionResult, 1.f), 0.f);
-    return static_cast<unsigned char>(turbulenceFunctionResult * 255);
+
+    return turbulenceFunctionResult;
 }
 
 void FETurbulence::fillRegion(Uint8ClampedArray* pixelArray, const PaintingData& paintingData, int startY, int endY)
@@ -315,8 +328,11 @@ void FETurbulence::fillRegion(Uint8ClampedArray* pixelArray, const PaintingData&
         for (int x = 0; x < filterRegion.width(); ++x) {
             point.setX(point.x() + 1);
             FloatPoint localPoint = inverseTransfrom.mapPoint(point);
-            for (int channel = 0; channel < 4; ++channel, ++indexOfPixelChannel)
-                pixelArray->set(indexOfPixelChannel, calculateTurbulenceValueForPoint(channel, paintingData, stitchData, localPoint));
+            ColorComponents values = calculateTurbulenceValueForPoint(paintingData, stitchData, localPoint);
+            pixelArray->set(indexOfPixelChannel++, values.components[0]);
+            pixelArray->set(indexOfPixelChannel++, values.components[1]);
+            pixelArray->set(indexOfPixelChannel++, values.components[2]);
+            pixelArray->set(indexOfPixelChannel++, values.components[3]);
         }
     }
 }
@@ -355,7 +371,7 @@ void FETurbulence::platformApplySoftware()
 
             int startY = 0;
             for (; i > 0; --i) {
-                FillRegionParameters& params = parallelJobs.parameter(i-1);
+                FillRegionParameters& params = parallelJobs.parameter(i - 1);
                 params.filter = this;
                 params.pixelArray = pixelArray;
                 params.paintingData = &paintingData;
index d7cd3e0..4a5de3f 100644 (file)
@@ -4,6 +4,7 @@
  * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
  * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
  * Copyright (C) 2010 Renata Hodovan <reni@inf.u-szeged.hu>
+ * Copyright (C) 2017 Apple Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -21,9 +22,9 @@
  * Boston, MA 02110-1301, USA.
  */
 
-#ifndef FETurbulence_h
-#define FETurbulence_h
+#pragma once
 
+#include "ColorUtilities.h"
 #include "FilterEffect.h"
 #include "Filter.h"
 
@@ -118,8 +119,8 @@ private:
     FETurbulence(Filter&, TurbulenceType, float, float, int, float, bool);
 
     void initPaint(PaintingData&);
-    float noise2D(int channel, const PaintingData&, StitchData&, const FloatPoint&);
-    unsigned char calculateTurbulenceValueForPoint(int channel, const PaintingData&, StitchData&, const FloatPoint&);
+    FloatComponents noise2D(const PaintingData&, StitchData&, const FloatPoint&);
+    ColorComponents calculateTurbulenceValueForPoint(const PaintingData&, StitchData&, const FloatPoint&);
     void fillRegion(Uint8ClampedArray*, const PaintingData&, int, int);
 
     TurbulenceType m_type;
@@ -132,4 +133,3 @@ private:
 
 } // namespace WebCore
 
-#endif // FETurbulence_h