Title: [90091] trunk/Source/WebCore
Revision
90091
Author
[email protected]
Date
2011-06-30 00:20:50 -0700 (Thu, 30 Jun 2011)

Log Message

2011-06-30  Piroska András  <[email protected]>

        Reviewed by Dirk Schulze.

        Apply the ParallelJobs support to FEMorphology
        https://bugs.webkit.org/show_bug.cgi?id=63064

        The FEMorphology filter of SVG can consume lots of resources if it is
        applied to a large area. The computation can be distributed to multiple
        cores if the architecture supports.
        The average performance progression is 20-25% on dual-core machines.

        * platform/graphics/filters/FEMorphology.cpp:
        (WebCore::FEMorphology::platformApplyGeneric): Apply the filter between yStart and yEnd interval
        (WebCore::FEMorphology::platformApplyWorker): Call the generic apply from a parallel worker
        (WebCore::FEMorphology::platformApply):
        (WebCore::FEMorphology::apply): Move the functionality into platformApply
        (WebCore::FEMorphology::externalRepresentation): Remove whitespaces
        * platform/graphics/filters/FEMorphology.h:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (90090 => 90091)


--- trunk/Source/WebCore/ChangeLog	2011-06-30 07:14:45 UTC (rev 90090)
+++ trunk/Source/WebCore/ChangeLog	2011-06-30 07:20:50 UTC (rev 90091)
@@ -1,3 +1,23 @@
+2011-06-30  Piroska András  <[email protected]>
+
+        Reviewed by Dirk Schulze.
+
+        Apply the ParallelJobs support to FEMorphology
+        https://bugs.webkit.org/show_bug.cgi?id=63064
+
+        The FEMorphology filter of SVG can consume lots of resources if it is
+        applied to a large area. The computation can be distributed to multiple
+        cores if the architecture supports.
+        The average performance progression is 20-25% on dual-core machines.
+
+        * platform/graphics/filters/FEMorphology.cpp:
+        (WebCore::FEMorphology::platformApplyGeneric): Apply the filter between yStart and yEnd interval
+        (WebCore::FEMorphology::platformApplyWorker): Call the generic apply from a parallel worker
+        (WebCore::FEMorphology::platformApply):
+        (WebCore::FEMorphology::apply): Move the functionality into platformApply
+        (WebCore::FEMorphology::externalRepresentation): Remove whitespaces
+        * platform/graphics/filters/FEMorphology.h:
+
 2011-06-29  Kent Tamura  <[email protected]>
 
         Reviewed by Dimitri Glazkov.

Modified: trunk/Source/WebCore/platform/graphics/filters/FEMorphology.cpp (90090 => 90091)


--- trunk/Source/WebCore/platform/graphics/filters/FEMorphology.cpp	2011-06-30 07:14:45 UTC (rev 90090)
+++ trunk/Source/WebCore/platform/graphics/filters/FEMorphology.cpp	2011-06-30 07:20:50 UTC (rev 90091)
@@ -31,6 +31,7 @@
 #include "TextStream.h"
 
 #include <wtf/ByteArray.h>
+#include <wtf/ParallelJobs.h>
 #include <wtf/Vector.h>
 
 using std::min;
@@ -100,6 +101,98 @@
     return true;
 }
 
+void FEMorphology::platformApplyGeneric(PaintingData* paintingData, int yStart, int yEnd)
+{
+    ByteArray* srcPixelArray = paintingData->srcPixelArray;
+    ByteArray* dstPixelArray = paintingData->dstPixelArray;
+    const int width = paintingData->width;
+    const int height = paintingData->height;
+    const int effectWidth  = width * 4;
+    const int radiusX = paintingData->radiusX;
+    const int radiusY = paintingData->radiusY;
+
+    Vector<unsigned char> extrema;
+    for (int y = yStart; y < yEnd; ++y) {
+        int extremaStartY = max(0, y - radiusY);
+        int extremaEndY = min(height - 1, y + radiusY);
+        for (unsigned int clrChannel = 0; clrChannel < 4; ++clrChannel) {
+            extrema.clear();
+            // Compute extremas for each columns
+            for (int x = 0; x <= radiusX; ++x) {
+                unsigned char columnExtrema = srcPixelArray->get(yStart * effectWidth  + 4 * x + clrChannel);
+                for (int eY = extremaStartY + 1; eY < extremaEndY; ++eY) {
+                    unsigned char pixel = srcPixelArray->get(eY * effectWidth  + 4 * x + clrChannel);
+                    if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && pixel <= columnExtrema)
+                        || (m_type == FEMORPHOLOGY_OPERATOR_DILATE && pixel >= columnExtrema)) {
+                        columnExtrema = pixel;
+                    }
+                }
+
+                extrema.append(columnExtrema);
+            }
+
+            // Kernel is filled, get extrema of next column
+            for (int x = 0; x < width; ++x) {
+                const int endX = min(x + radiusX, width - 1);
+                unsigned char columnExtrema = srcPixelArray->get(extremaStartY * effectWidth  + endX * 4 + clrChannel);
+                for (int i = extremaStartY + 1; i <= extremaEndY; ++i) {
+                    unsigned char pixel = srcPixelArray->get(i * effectWidth  + endX * 4 + clrChannel);
+                    if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && pixel <= columnExtrema)
+                        || (m_type == FEMORPHOLOGY_OPERATOR_DILATE && pixel >= columnExtrema))
+                        columnExtrema = pixel;
+                }
+                if (x - radiusX >= 0)
+                    extrema.remove(0);
+                if (x + radiusX <= width)
+                    extrema.append(columnExtrema);
+
+                unsigned char entireExtrema = extrema[0];
+                for (unsigned kernelIndex = 1; kernelIndex < extrema.size(); ++kernelIndex) {
+                    if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && extrema[kernelIndex] <= entireExtrema)
+                        || (m_type == FEMORPHOLOGY_OPERATOR_DILATE && extrema[kernelIndex] >= entireExtrema))
+                        entireExtrema = extrema[kernelIndex];
+                }
+                dstPixelArray->set(y * effectWidth + 4 * x + clrChannel, entireExtrema);
+            }
+        }
+    }
+}
+
+#if ENABLE(PARALLEL_JOBS)
+void FEMorphology::platformApplyWorker(PlatformApplyParameters* param)
+{
+    param->filter->platformApplyGeneric(param->paintingData, param->startY, param->endY);
+}
+#endif
+
+void FEMorphology::platformApply(PaintingData* paintingData)
+{
+#if ENABLE(PARALLEL_JOBS)
+    int optimalThreadNumber = (paintingData->width * paintingData->height) / s_minimalArea;
+    if (optimalThreadNumber > 1) {
+        ParallelJobs<PlatformApplyParameters> parallelJobs(&WebCore::FEMorphology::platformApplyWorker, optimalThreadNumber);
+        int numOfThreads = parallelJobs.numberOfJobs();
+        if (numOfThreads > 1) {
+            const int deltaY = 1 + paintingData->height / numOfThreads;
+            int currentY = 0;
+            for (int job = numOfThreads - 1; job >= 0; --job) {
+                PlatformApplyParameters& param = parallelJobs.parameter(job);
+                param.filter = this;
+                param.startY = currentY;
+                currentY += deltaY;
+                param.endY = job ? currentY : paintingData->height;
+                param.paintingData = paintingData;
+            }
+            parallelJobs.execute();
+            return;
+        }
+        // Fallback to single thread model
+    }
+#endif
+    platformApplyGeneric(paintingData, 0, paintingData->height);
+}
+
+
 void FEMorphology::apply()
 {
     if (hasResult())
@@ -124,54 +217,15 @@
     IntRect effectDrawingRect = requestedRegionOfInputImageData(in->absolutePaintRect());
     RefPtr<ByteArray> srcPixelArray = in->asPremultipliedImage(effectDrawingRect);
 
-    int effectWidth = effectDrawingRect.width() * 4;
-    
-    // Limit the radius size to effect dimensions
-    radiusX = min(effectDrawingRect.width() - 1, radiusX);
-    radiusY = min(effectDrawingRect.height() - 1, radiusY);
-    
-    Vector<unsigned char> extrema;
-    for (int y = 0; y < effectDrawingRect.height(); ++y) {
-        int startY = max(0, y - radiusY);
-        int endY = min(effectDrawingRect.height() - 1, y + radiusY);
-        for (unsigned channel = 0; channel < 4; ++channel) {
-            // Fill the kernel
-            extrema.clear();
-            for (int j = 0; j <= radiusX; ++j) {
-                unsigned char columnExtrema = srcPixelArray->get(startY * effectWidth + 4 * j + channel);
-                for (int i = startY; i <= endY; ++i) {
-                    unsigned char pixel = srcPixelArray->get(i * effectWidth + 4 * j + channel);
-                    if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && pixel <= columnExtrema) ||
-                        (m_type == FEMORPHOLOGY_OPERATOR_DILATE && pixel >= columnExtrema))
-                        columnExtrema = pixel;
-                }
-                extrema.append(columnExtrema);
-            }
-            
-            // Kernel is filled, get extrema of next column 
-            for (int x = 0; x < effectDrawingRect.width(); ++x) {
-                unsigned endX = min(x + radiusX, effectDrawingRect.width() - 1);
-                unsigned char columnExtrema = srcPixelArray->get(startY * effectWidth + endX * 4 + channel);
-                for (int i = startY; i <= endY; ++i) {
-                    unsigned char pixel = srcPixelArray->get(i * effectWidth + endX * 4 + channel);
-                    if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && pixel <= columnExtrema) ||
-                        (m_type == FEMORPHOLOGY_OPERATOR_DILATE && pixel >= columnExtrema))
-                        columnExtrema = pixel;
-                }
-                if (x - radiusX >= 0)
-                    extrema.remove(0);
-                if (x + radiusX <= effectDrawingRect.width())
-                    extrema.append(columnExtrema);
-                unsigned char entireExtrema = extrema[0];
-                for (unsigned kernelIndex = 0; kernelIndex < extrema.size(); ++kernelIndex) {
-                    if ((m_type == FEMORPHOLOGY_OPERATOR_ERODE && extrema[kernelIndex] <= entireExtrema) ||
-                        (m_type == FEMORPHOLOGY_OPERATOR_DILATE && extrema[kernelIndex] >= entireExtrema))
-                        entireExtrema = extrema[kernelIndex];
-                }
-                dstPixelArray->set(y * effectWidth + 4 * x + channel, entireExtrema);
-            }
-        }
-    }
+    PaintingData paintingData;
+    paintingData.srcPixelArray = srcPixelArray.get();
+    paintingData.dstPixelArray = dstPixelArray;
+    paintingData.width = effectDrawingRect.width();
+    paintingData.height = effectDrawingRect.height();
+    paintingData.radiusX = min(effectDrawingRect.width() - 1, radiusX);
+    paintingData.radiusY = min(effectDrawingRect.height() - 1, radiusY);
+
+    platformApply(&paintingData);
 }
 
 void FEMorphology::dump()
@@ -200,7 +254,7 @@
     ts << "[feMorphology";
     FilterEffect::externalRepresentation(ts);
     ts << " operator=\"" << morphologyOperator() << "\" "
-       << "radius=\"" << radiusX() << ", " << radiusY() << "\"]\n";    
+       << "radius=\"" << radiusX() << ", " << radiusY() << "\"]\n";
     inputEffect(0)->externalRepresentation(ts, indent + 1);
     return ts;
 }

Modified: trunk/Source/WebCore/platform/graphics/filters/FEMorphology.h (90090 => 90091)


--- trunk/Source/WebCore/platform/graphics/filters/FEMorphology.h	2011-06-30 07:14:45 UTC (rev 90090)
+++ trunk/Source/WebCore/platform/graphics/filters/FEMorphology.h	2011-06-30 07:20:50 UTC (rev 90091)
@@ -53,6 +53,30 @@
 
     virtual TextStream& externalRepresentation(TextStream&, int indention) const;
 
+    struct PaintingData {
+        ByteArray* srcPixelArray;
+        ByteArray* dstPixelArray;
+        int width;
+        int height;
+        int radiusX;
+        int radiusY;
+    };
+
+#if ENABLE(PARALLEL_JOBS)
+    static const int s_minimalArea = (300 * 300); // Empirical data limit for parallel jobs
+
+    struct PlatformApplyParameters {
+        FEMorphology* filter;
+        int startY;
+        int endY;
+        PaintingData* paintingData;
+    };
+
+    static void platformApplyWorker(PlatformApplyParameters*);
+#endif
+
+    void platformApply(PaintingData*);
+    inline void platformApplyGeneric(PaintingData*, const int yStart, const int yEnd);
 private:
     FEMorphology(Filter*, MorphologyOperatorType, float radiusX, float radiusY);
     
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to