2011-04-26 Gabor Loki <loki@webkit.org>
authorloki@webkit.org <loki@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 26 Apr 2011 14:40:47 +0000 (14:40 +0000)
committerloki@webkit.org <loki@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 26 Apr 2011 14:40:47 +0000 (14:40 +0000)
        Reviewed by Csaba Osztrogonác.

        Speeding up SVG filters with multicore (SMP) support
        https://bugs.webkit.org/show_bug.cgi?id=43903

        Some SVG filters execute a huge number of pixel manipulations, which
        cannot be sped up by graphics accelerators, since their algorithm is
        too complex. Using the power of Symmetric Multi Processing (SMP) we
        can split up a task to smaller (data independent) tasks, which can be
        executed independently.

        The ParallelJobs framework provides a simple way for distributed
        programming. The framework is based on WebKit's threading infrastructure,
        Open Multi-Processing's (OpenMP) API, and libdispatch API.

        * GNUmakefile.list.am:
        * JavaScriptCore.vcproj/WTF/WTF.vcproj:
        * JavaScriptCore.xcodeproj/project.pbxproj:
        * wtf/CMakeLists.txt:
        * wtf/ParallelJobs.h: Added.
        (WTF::ParallelJobs::ParallelJobs):
        (WTF::ParallelJobs::numberOfJobs):
        (WTF::ParallelJobs::parameterForJob):
        (WTF::ParallelJobs::executeJobs):
        * wtf/ParallelJobsGeneric.cpp: Added.
        (WTF::ParallelEnvironment::ThreadPrivate::tryLockFor):
        (WTF::ParallelEnvironment::ThreadPrivate::executeJob):
        (WTF::ParallelEnvironment::ThreadPrivate::waitForFinish):
        (WTF::ParallelEnvironment::ThreadPrivate::workerThread):
        * wtf/ParallelJobsGeneric.h: Added.
        (WTF::ParallelEnvironment::ParallelEnvironment):
        (WTF::ParallelEnvironment::numberOfJobs):
        (WTF::ParallelEnvironment::parameterForJob):
        (WTF::ParallelEnvironment::executeJobs):
        (WTF::ParallelEnvironment::ThreadPrivate::ThreadPrivate):
        (WTF::ParallelEnvironment::ThreadPrivate::create):
        * wtf/ParallelJobsLibdispatch.h: Added.
        (WTF::ParallelEnvironment::ParallelEnvironment):
        (WTF::ParallelEnvironment::numberOfJobs):
        (WTF::ParallelEnvironment::parameterForJob):
        (WTF::ParallelEnvironment::executeJobs):
        * wtf/ParallelJobsOpenMP.h: Added.
        (WTF::ParallelEnvironment::ParallelEnvironment):
        (WTF::ParallelEnvironment::numberOfJobs):
        (WTF::ParallelEnvironment::parameterForJob):
        (WTF::ParallelEnvironment::executeJobs):
        * wtf/Platform.h:
        * wtf/wtf.pri:
2011-04-26  Gabor Loki  <loki@webkit.org>

        Reviewed by Csaba Osztrogonác.

        Speeding up SVG filters with multicore (SMP) support
        https://bugs.webkit.org/show_bug.cgi?id=43903

        Some SVG filters execute a huge number of pixel manipulations, which
        cannot be sped up by graphics accelerators, since their algorithm is
        too complex. Using the power of Symmetric Multi Processing (SMP) we
        can split up a task to smaller (data independent) tasks, which can be
        executed independently.

        The ParallelJobs framework provides a simple way for distributed
        programming. The framework is based on WebKit's threading infrastructure,
        Open Multi-Processing's (OpenMP) API, and libdispatch API.

        * ForwardingHeaders/wtf/ParallelJobs.h: Added.
        * platform/graphics/filters/FETurbulence.cpp:
        (WebCore::FETurbulence::PaintingData::PaintingData):
        (WebCore::FETurbulence::noise2D):
        (WebCore::FETurbulence::calculateTurbulenceValueForPoint):
        (WebCore::FETurbulence::fillRegion):
        (WebCore::FETurbulence::fillRegionWorker):
        (WebCore::FETurbulence::apply):
        * platform/graphics/filters/FETurbulence.h:

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

16 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/GNUmakefile.list.am
Source/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTF.vcproj
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/wtf/CMakeLists.txt
Source/JavaScriptCore/wtf/ParallelJobs.h [new file with mode: 0644]
Source/JavaScriptCore/wtf/ParallelJobsGeneric.cpp [new file with mode: 0644]
Source/JavaScriptCore/wtf/ParallelJobsGeneric.h [new file with mode: 0644]
Source/JavaScriptCore/wtf/ParallelJobsLibdispatch.h [new file with mode: 0644]
Source/JavaScriptCore/wtf/ParallelJobsOpenMP.h [new file with mode: 0644]
Source/JavaScriptCore/wtf/Platform.h
Source/JavaScriptCore/wtf/wtf.pri
Source/WebCore/ChangeLog
Source/WebCore/ForwardingHeaders/wtf/ParallelJobs.h [new file with mode: 0644]
Source/WebCore/platform/graphics/filters/FETurbulence.cpp
Source/WebCore/platform/graphics/filters/FETurbulence.h

index 83b6c8c667c1f59ddc668b5d3b4bbac225346714..8a7954c34fd3ab2e7978c9aa44fd76daafbdf848 100644 (file)
@@ -1,3 +1,54 @@
+2011-04-26  Gabor Loki  <loki@webkit.org>
+
+        Reviewed by Csaba Osztrogonác.
+
+        Speeding up SVG filters with multicore (SMP) support
+        https://bugs.webkit.org/show_bug.cgi?id=43903
+
+        Some SVG filters execute a huge number of pixel manipulations, which
+        cannot be sped up by graphics accelerators, since their algorithm is
+        too complex. Using the power of Symmetric Multi Processing (SMP) we
+        can split up a task to smaller (data independent) tasks, which can be
+        executed independently.
+
+        The ParallelJobs framework provides a simple way for distributed
+        programming. The framework is based on WebKit's threading infrastructure,
+        Open Multi-Processing's (OpenMP) API, and libdispatch API.
+
+        * GNUmakefile.list.am:
+        * JavaScriptCore.vcproj/WTF/WTF.vcproj:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * wtf/CMakeLists.txt:
+        * wtf/ParallelJobs.h: Added.
+        (WTF::ParallelJobs::ParallelJobs):
+        (WTF::ParallelJobs::numberOfJobs):
+        (WTF::ParallelJobs::parameterForJob):
+        (WTF::ParallelJobs::executeJobs):
+        * wtf/ParallelJobsGeneric.cpp: Added.
+        (WTF::ParallelEnvironment::ThreadPrivate::tryLockFor):
+        (WTF::ParallelEnvironment::ThreadPrivate::executeJob):
+        (WTF::ParallelEnvironment::ThreadPrivate::waitForFinish):
+        (WTF::ParallelEnvironment::ThreadPrivate::workerThread):
+        * wtf/ParallelJobsGeneric.h: Added.
+        (WTF::ParallelEnvironment::ParallelEnvironment):
+        (WTF::ParallelEnvironment::numberOfJobs):
+        (WTF::ParallelEnvironment::parameterForJob):
+        (WTF::ParallelEnvironment::executeJobs):
+        (WTF::ParallelEnvironment::ThreadPrivate::ThreadPrivate):
+        (WTF::ParallelEnvironment::ThreadPrivate::create):
+        * wtf/ParallelJobsLibdispatch.h: Added.
+        (WTF::ParallelEnvironment::ParallelEnvironment):
+        (WTF::ParallelEnvironment::numberOfJobs):
+        (WTF::ParallelEnvironment::parameterForJob):
+        (WTF::ParallelEnvironment::executeJobs):
+        * wtf/ParallelJobsOpenMP.h: Added.
+        (WTF::ParallelEnvironment::ParallelEnvironment):
+        (WTF::ParallelEnvironment::numberOfJobs):
+        (WTF::ParallelEnvironment::parameterForJob):
+        (WTF::ParallelEnvironment::executeJobs):
+        * wtf/Platform.h:
+        * wtf/wtf.pri:
+
 2011-04-26  Mihai Parparita  <mihaip@chromium.org>
 
         Reviewed by Adam Barth.
index ade4691c5aa6fd48c553f853af3dab1350a8399b..2a38bb809f065a526e7b48d39de14adfaddd160b 100644 (file)
@@ -478,6 +478,11 @@ javascriptcore_sources += \
        Source/JavaScriptCore/wtf/PassOwnArrayPtr.h \
        Source/JavaScriptCore/wtf/PassOwnPtr.h \
        Source/JavaScriptCore/wtf/PassRefPtr.h \
+       Source/JavaScriptCore/wtf/ParallelJobs.h \
+       Source/JavaScriptCore/wtf/ParallelJobsGeneric.cpp \
+       Source/JavaScriptCore/wtf/ParallelJobsGeneric.h \
+       Source/JavaScriptCore/wtf/ParallelJobsLibdispatch.h \
+       Source/JavaScriptCore/wtf/ParallelJobsOpenMP.h \
        Source/JavaScriptCore/wtf/Platform.h \
        Source/JavaScriptCore/wtf/PossiblyNull.h \
        Source/JavaScriptCore/wtf/RandomNumber.cpp \
index 7c8333905ef57e4d87576ace39e2ccdd64f9b55a..5a9629963461ce77fd2a80d96439fa5e13c28efa 100644 (file)
                        RelativePath="..\..\wtf\PassRefPtr.h"
                        >
                </File>
+               <File
+                       RelativePath="..\..\wtf\ParallelJobs.h"
+                       >
+               </File>
+               <File
+                       RelativePath="..\..\wtf\ParallelJobsGeneric.cpp"
+                       >
+               </File>
+               <File
+                       RelativePath="..\..\wtf\ParallelJobsGeneric.h"
+                       >
+               </File>
+               <File
+                       RelativePath="..\..\wtf\ParallelJobsLibdispatch.h"
+                       >
+               </File>
+               <File
+                       RelativePath="..\..\wtf\ParallelJobsOpenMP.h"
+                       >
+               </File>
                <File
                        RelativePath="..\..\wtf\Platform.h"
                        >
index 63ffa69303057c0e9a264f8fb3a6cc0b42688557..f82242f76b4ff87c7f4fa6d61ba4b74b5b0b8e70 100644 (file)
                7186A6EC13100BA5004479E1 /* HexNumber.h in Headers */ = {isa = PBXBuildFile; fileRef = 7186A6E813100B57004479E1 /* HexNumber.h */; settings = {ATTRIBUTES = (Private, ); }; };
                76FB9F0F12E851860051A2EB /* SHA1.h in Headers */ = {isa = PBXBuildFile; fileRef = 76FB9F0E12E851860051A2EB /* SHA1.h */; settings = {ATTRIBUTES = (Private, ); }; };
                76FB9F1112E851960051A2EB /* SHA1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 76FB9F1012E851960051A2EB /* SHA1.cpp */; };
+               7934BB7B1361979300CB99A1 /* ParallelJobs.h in Headers */ = {isa = PBXBuildFile; fileRef = 7934BB761361979300CB99A1 /* ParallelJobs.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               7934BB7C1361979400CB99A1 /* ParallelJobsGeneric.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7934BB771361979300CB99A1 /* ParallelJobsGeneric.cpp */; };
+               7934BB7D1361979400CB99A1 /* ParallelJobsGeneric.h in Headers */ = {isa = PBXBuildFile; fileRef = 7934BB781361979300CB99A1 /* ParallelJobsGeneric.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               7934BB7E1361979400CB99A1 /* ParallelJobsLibdispatch.h in Headers */ = {isa = PBXBuildFile; fileRef = 7934BB791361979300CB99A1 /* ParallelJobsLibdispatch.h */; settings = {ATTRIBUTES = (Private, ); }; };
+               7934BB7F1361979400CB99A1 /* ParallelJobsOpenMP.h in Headers */ = {isa = PBXBuildFile; fileRef = 7934BB7A1361979300CB99A1 /* ParallelJobsOpenMP.h */; settings = {ATTRIBUTES = (Private, ); }; };
                7E4EE7090EBB7963005934AA /* StructureChain.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E4EE7080EBB7963005934AA /* StructureChain.h */; settings = {ATTRIBUTES = (Private, ); }; };
                7E4EE70F0EBB7A5B005934AA /* StructureChain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7E4EE70E0EBB7A5B005934AA /* StructureChain.cpp */; };
                7EFF00640EC05A9A00AA7C93 /* NodeInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 7EFF00630EC05A9A00AA7C93 /* NodeInfo.h */; };
                7186A6E813100B57004479E1 /* HexNumber.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HexNumber.h; sourceTree = "<group>"; };
                76FB9F0E12E851860051A2EB /* SHA1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SHA1.h; sourceTree = "<group>"; };
                76FB9F1012E851960051A2EB /* SHA1.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SHA1.cpp; sourceTree = "<group>"; };
+               7934BB761361979300CB99A1 /* ParallelJobs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParallelJobs.h; sourceTree = "<group>"; };
+               7934BB771361979300CB99A1 /* ParallelJobsGeneric.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParallelJobsGeneric.cpp; sourceTree = "<group>"; };
+               7934BB781361979300CB99A1 /* ParallelJobsGeneric.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParallelJobsGeneric.h; sourceTree = "<group>"; };
+               7934BB791361979300CB99A1 /* ParallelJobsLibdispatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParallelJobsLibdispatch.h; sourceTree = "<group>"; };
+               7934BB7A1361979300CB99A1 /* ParallelJobsOpenMP.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParallelJobsOpenMP.h; sourceTree = "<group>"; };
                7E2C6C980D31C6B6002D44E2 /* ScopeChainMark.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScopeChainMark.h; sourceTree = "<group>"; };
                7E4EE7080EBB7963005934AA /* StructureChain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StructureChain.h; sourceTree = "<group>"; };
                7E4EE70E0EBB7A5B005934AA /* StructureChain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StructureChain.cpp; sourceTree = "<group>"; };
                                BCFBE695122560E800309E9D /* PassOwnArrayPtr.h */,
                                44DD48520FAEA85000D6B4EB /* PassOwnPtr.h */,
                                6580F795094070560082C219 /* PassRefPtr.h */,
+                               7934BB761361979300CB99A1 /* ParallelJobs.h */,
+                               7934BB771361979300CB99A1 /* ParallelJobsGeneric.cpp */,
+                               7934BB781361979300CB99A1 /* ParallelJobsGeneric.h */,
+                               7934BB791361979300CB99A1 /* ParallelJobsLibdispatch.h */,
+                               7934BB7A1361979300CB99A1 /* ParallelJobsOpenMP.h */,
                                65D6D87E09B5A32E0002E4D7 /* Platform.h */,
                                A7D649A91015224E009B2E1B /* PossiblyNull.h */,
                                E4D8CE9B12FC42E100BC9F5A /* BloomFilter.h */,
                                A1D764521354448B00C5C7C0 /* Alignment.h in Headers */,
                                86AE64A9135E5E1C00963012 /* MacroAssemblerSH4.h in Headers */,
                                86AE64AA135E5E1C00963012 /* SH4Assembler.h in Headers */,
+                               7934BB7B1361979300CB99A1 /* ParallelJobs.h in Headers */,
+                               7934BB7D1361979400CB99A1 /* ParallelJobsGeneric.h in Headers */,
+                               7934BB7E1361979400CB99A1 /* ParallelJobsLibdispatch.h in Headers */,
+                               7934BB7F1361979400CB99A1 /* ParallelJobsOpenMP.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
                                142D6F1113539A4100B02E86 /* MarkStack.cpp in Sources */,
                                142D6F1313539A4100B02E86 /* MarkStackPosix.cpp in Sources */,
                                86AE64A8135E5E1C00963012 /* MacroAssemblerSH4.cpp in Sources */,
+                               7934BB7C1361979400CB99A1 /* ParallelJobsGeneric.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index 97aad2d730f4fd3ac956bf52b435c23555f32685..d0d53638e9c092e406e184a06e3d70eb0272397c 100644 (file)
@@ -58,6 +58,10 @@ SET(WTF_HEADERS
     PassOwnArrayPtr.h
     PassOwnPtr.h
     PassRefPtr.h
+    ParallelJobs.h
+    ParallelJobsGeneric.h
+    ParallelJobsLibdispatch.h
+    ParallelJobsOpenMP.h
     Platform.h
     PossiblyNull.h
     RandomNumber.h
@@ -119,6 +123,7 @@ SET(WTF_SOURCES
     MainThread.cpp
     MD5.cpp
     OSRandomSource.cpp
+    ParallelJobsGeneric.cpp
     RandomNumber.cpp
     RefCountedLeakCounter.cpp
     SHA1.cpp
diff --git a/Source/JavaScriptCore/wtf/ParallelJobs.h b/Source/JavaScriptCore/wtf/ParallelJobs.h
new file mode 100644 (file)
index 0000000..2e0524d
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2011 University of Szeged
+ * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
+ * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED OR
+ * 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.
+ */
+
+#ifndef ParallelJobs_h
+#define ParallelJobs_h
+
+#include "Assertions.h"
+#include "Noncopyable.h"
+#include "RefPtr.h"
+#include <wtf/Vector.h>
+
+#if ENABLE(PARALLEL_JOBS)
+
+// Usage:
+//
+// #if ENABLE(PARALLEL_JOBS)
+//
+//     // Initialize parallel jobs
+//     ParallelJobs<TypeOfParameter> parallelJobs(&worker [, requestedNumberOfJobs]);
+//
+//     // Fill the parameter array
+//     for(i = 0; i < parallelJobs.numberOfJobs(); ++i) {
+//       TypeOfParameter& params = parallelJobs.parameter(i);
+//       params.attr1 = localVars ...
+//       ...
+//     }
+//
+//     // Execute parallel jobs
+//     parallelJobs.execute();
+//
+// #else
+//
+//     inlineFunction(args...);
+//
+// #endif // ENABLE(PARALLEL_JOBS)
+
+#if ENABLE(THREADING_GENERIC)
+#include "ParallelJobsGeneric.h"
+
+#elif ENABLE(THREADING_OPENMP)
+#include "ParallelJobsOpenMP.h"
+
+#elif ENABLE(THREADING_LIBDISPATCH)
+#include "ParallelJobsLibdispatch.h"
+
+#else
+#error "No parallel processing API for ParallelJobs"
+
+#endif
+
+namespace WTF {
+
+template<typename Type>
+class ParallelJobs {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    typedef void (*WorkerFunction)(Type*);
+
+    ParallelJobs(WorkerFunction func, int requestedJobNumber = 0) :
+        m_parallelEnvironment(reinterpret_cast<ParallelEnvironment::ThreadFunction>(func), sizeof(Type), requestedJobNumber)
+    {
+        m_parameters.grow(m_parallelEnvironment.numberOfJobs());
+        ASSERT(numberOfJobs() == m_parameters.size());
+    }
+
+    size_t numberOfJobs()
+    {
+        return m_parameters.size();
+    }
+
+    Type& parameter(size_t i)
+    {
+        return m_parameters[i];
+    }
+
+    void execute()
+    {
+        m_parallelEnvironment.execute(reinterpret_cast<unsigned char*>(m_parameters.data()));
+    }
+
+private:
+    ParallelEnvironment m_parallelEnvironment;
+    Vector<Type> m_parameters;
+};
+
+} // namespace WTF
+
+using WTF::ParallelJobs;
+
+#endif // ENABLE(PARALLEL_JOBS)
+
+#endif // ParallelJobs_h
diff --git a/Source/JavaScriptCore/wtf/ParallelJobsGeneric.cpp b/Source/JavaScriptCore/wtf/ParallelJobsGeneric.cpp
new file mode 100644 (file)
index 0000000..e241b83
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2011 University of Szeged
+ * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
+ * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED OR
+ * 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"
+
+#if ENABLE(PARALLEL_JOBS) && ENABLE(THREADING_GENERIC)
+
+#include "ParallelJobs.h"
+
+namespace WTF {
+
+Vector< RefPtr<ParallelEnvironment::ThreadPrivate> >* ParallelEnvironment::s_threadPool = 0;
+
+bool ParallelEnvironment::ThreadPrivate::tryLockFor(ParallelEnvironment* parent)
+{
+    bool locked = m_mutex.tryLock();
+
+    if (!locked)
+        return false;
+
+    if (m_parent) {
+        m_mutex.unlock();
+        return false;
+    }
+
+    if (!m_threadID)
+        m_threadID = createThread(&ParallelEnvironment::ThreadPrivate::workerThread, this, "Parallel worker");
+
+    if (m_threadID)
+        m_parent = parent;
+
+    m_mutex.unlock();
+    return m_threadID;
+}
+
+void ParallelEnvironment::ThreadPrivate::execute(ThreadFunction threadFunction, void* parameters)
+{
+    MutexLocker lock(m_mutex);
+
+    m_threadFunction = threadFunction;
+    m_parameters = parameters;
+    m_running = true;
+    m_threadCondition.signal();
+}
+
+void ParallelEnvironment::ThreadPrivate::waitForFinish()
+{
+    MutexLocker lock(m_mutex);
+
+    while (m_running)
+        m_threadCondition.wait(m_mutex);
+}
+
+void* ParallelEnvironment::ThreadPrivate::workerThread(void* threadData)
+{
+    ThreadPrivate* sharedThread = reinterpret_cast<ThreadPrivate*>(threadData);
+    MutexLocker lock(sharedThread->m_mutex);
+
+    while (sharedThread->m_threadID) {
+        if (sharedThread->m_running) {
+            (*sharedThread->m_threadFunction)(sharedThread->m_parameters);
+            sharedThread->m_running = false;
+            sharedThread->m_parent = 0;
+            sharedThread->m_threadCondition.signal();
+        }
+
+        sharedThread->m_threadCondition.wait(sharedThread->m_mutex);
+    }
+    return 0;
+}
+
+} // namespace WTF
+
+#endif // ENABLE(PARALLEL_JOBS) && ENABLE(THREADING_GENERIC)
diff --git a/Source/JavaScriptCore/wtf/ParallelJobsGeneric.h b/Source/JavaScriptCore/wtf/ParallelJobsGeneric.h
new file mode 100644 (file)
index 0000000..2aa44d5
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2011 University of Szeged
+ * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
+ * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED OR
+ * 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.
+ */
+
+#ifndef ParallelJobsGeneric_h
+#define ParallelJobsGeneric_h
+
+#if ENABLE(THREADING_GENERIC)
+
+#include <wtf/RefCounted.h>
+#include <wtf/Threading.h>
+
+namespace WTF {
+
+static const unsigned int maxParallelThreads = 2;
+
+class ParallelEnvironment {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    typedef void (*ThreadFunction)(void*);
+
+    ParallelEnvironment(ThreadFunction threadFunction, size_t sizeOfParameter, unsigned int requestedJobNumber) :
+        m_threadFunction(threadFunction),
+        m_sizeOfParameter(sizeOfParameter)
+    {
+        if (!requestedJobNumber || requestedJobNumber > maxParallelThreads)
+            requestedJobNumber = maxParallelThreads;
+
+        if (!s_threadPool)
+            s_threadPool = new Vector< RefPtr<ThreadPrivate> >();
+
+        // The main thread should be also a worker.
+        unsigned int maxNewThreads = requestedJobNumber - 1;
+
+        for (unsigned int i = 0; i < maxParallelThreads && m_threads.size() < maxNewThreads; ++i) {
+            if (s_threadPool->size() < i + 1)
+                s_threadPool->append(ThreadPrivate::create());
+
+            if ((*s_threadPool)[i]->tryLockFor(this))
+                m_threads.append((*s_threadPool)[i]);
+        }
+
+        m_numberOfJobs = m_threads.size() + 1;
+    }
+
+    int numberOfJobs()
+    {
+        return m_numberOfJobs;
+    }
+
+    void execute(unsigned char* parameters)
+    {
+        size_t i;
+        for (i = 0; i < m_threads.size(); ++i) {
+            m_threads[i]->execute(m_threadFunction, parameters);
+            parameters += m_sizeOfParameter;
+        }
+
+        // The work for the main thread
+        (*m_threadFunction)(parameters);
+
+        // Wait until all jobs are done.
+        for (i = 0; i < m_threads.size(); ++i)
+            m_threads[i]->waitForFinish();
+    }
+
+    class ThreadPrivate : public RefCounted<ThreadPrivate> {
+    public:
+        ThreadPrivate()
+            : m_threadID(0)
+            , m_running(false)
+            , m_parent(0)
+        {
+        }
+
+        bool tryLockFor(ParallelEnvironment*);
+
+        void execute(ThreadFunction, void*);
+
+        void waitForFinish();
+
+        static PassRefPtr<ThreadPrivate> create()
+        {
+            return adoptRef(new ThreadPrivate());
+        }
+
+        static void* workerThread(void*);
+
+    private:
+        ThreadIdentifier m_threadID;
+        bool m_running;
+        ParallelEnvironment* m_parent;
+
+        mutable Mutex m_mutex;
+        ThreadCondition m_threadCondition;
+
+        ThreadFunction m_threadFunction;
+        void* m_parameters;
+    };
+
+private:
+    ThreadFunction m_threadFunction;
+    size_t m_sizeOfParameter;
+    int m_numberOfJobs;
+
+    Vector< RefPtr<ThreadPrivate> > m_threads;
+    static Vector< RefPtr<ThreadPrivate> >* s_threadPool;
+};
+
+} // namespace WTF
+
+#endif // ENABLE(THREADING_GENERIC)
+
+
+#endif // ParallelJobsGeneric_h
diff --git a/Source/JavaScriptCore/wtf/ParallelJobsLibdispatch.h b/Source/JavaScriptCore/wtf/ParallelJobsLibdispatch.h
new file mode 100644 (file)
index 0000000..687c771
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2011 University of Szeged
+ * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
+ * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED OR
+ * 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.
+ */
+
+#ifndef ParallelJobsLibdispatch_h
+#define ParallelJobsLibdispatch_h
+
+#if ENABLE(THREADING_LIBDISPATCH)
+
+#include <dispatch/dispatch.h>
+
+namespace WTF {
+
+static const int maxParallelThreads = 2;
+
+class ParallelEnvironment {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    typedef void (*ThreadFunction)(void*);
+
+    ParallelEnvironment(ThreadFunction threadFunction, size_t sizeOfParameter, int requestedJobNumber) :
+        m_threadFunction(threadFunction),
+        m_sizeOfParameter(sizeOfParameter)
+    {
+        if (!requestedJobNumber || requestedJobNumber > maxParallelThreads)
+            requestedJobNumber = maxParallelThreads;
+
+        ASSERT(requestedJobNumber > 0);
+
+        m_numberOfJobs = requestedJobNumber;
+    }
+
+    int numberOfJobs()
+    {
+        return m_numberOfJobs;
+    }
+
+    void execute(unsigned char* parameters)
+    {
+        // libdispatch is NOT supported inside a template
+        dispatch_queue_t parallelJobsQueue = dispatch_queue_create("ParallelJobs", 0);
+
+        for (int i = 0; i < m_numberOfJobs - 1; ++i) {
+            dispatch_async(parallelJobsQueue, ^{(*m_threadFunction)(parameters);});
+            parameters += m_sizeOfParameter;
+        }
+
+        // The work for the main thread. Wait until all jobs are done.
+        dispatch_sync(parallelJobsQueue, ^{(*m_threadFunction)(parameters);});
+    }
+
+private:
+    ThreadFunction m_threadFunction;
+    size_t m_sizeOfParameter;
+    int m_numberOfJobs;
+};
+
+} // namespace WTF
+
+#endif // ENABLE(THREADING_LIBDISPATCH)
+
+#endif // ParallelJobsLibdispatch_h
diff --git a/Source/JavaScriptCore/wtf/ParallelJobsOpenMP.h b/Source/JavaScriptCore/wtf/ParallelJobsOpenMP.h
new file mode 100644 (file)
index 0000000..706bd80
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2011 University of Szeged
+ * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
+ * 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 UNIVERSITY OF SZEGED ``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 UNIVERSITY OF SZEGED OR
+ * 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.
+ */
+
+#ifndef ParallelJobsOpenMP_h
+#define ParallelJobsOpenMP_h
+
+#if ENABLE(THREADING_OPENMP)
+
+#include <omp.h>
+
+namespace WTF {
+
+class ParallelEnvironment {
+    WTF_MAKE_NONCOPYABLE(ParallelEnvironment);
+public:
+    typedef void (*ThreadFunction)(void*);
+
+    ParallelEnvironment(ThreadFunction threadFunction, size_t sizeOfParameter, int requestedJobNumber) :
+        m_threadFunction(threadFunction),
+        m_sizeOfParameter(sizeOfParameter)
+    {
+        int maxNumberOfThreads = omp_get_max_threads();
+
+        if (!requestedJobNumber || requestedJobNumber > maxNumberOfThreads)
+            requestedJobNumber = maxNumberOfThreads;
+
+        ASSERT(requestedJobNumber > 0);
+
+        m_numberOfJobs = requestedJobNumber;
+
+    }
+
+    int numberOfJobs()
+    {
+        return m_numberOfJobs;
+    }
+
+    void execute(unsigned char* parameters)
+    {
+        omp_set_num_threads(m_numberOfJobs);
+
+#pragma omp parallel for
+        for (int i = 0; i < m_numberOfJobs; ++i)
+            (*m_threadFunction)(parameters + i * m_sizeOfParameter);
+    }
+
+private:
+    ThreadFunction m_threadFunction;
+    size_t m_sizeOfParameter;
+    int m_numberOfJobs;
+};
+
+} // namespace WTF
+
+#endif // ENABLE(THREADING_OPENMP)
+
+#endif // ParallelJobsOpenMP_h
index d154034ce2e7ce856dae0c66686378d22d34bbe4..7639b156185e80027df2fb85ce0256209930eba4 100644 (file)
 #define ENABLE_BRANCH_COMPACTION 1
 #endif
 
+#if !defined(ENABLE_THREADING_OPENMP) && defined(_OPENMP)
+#define ENABLE_THREADING_OPENMP 1
+#endif
+
+#if !defined(ENABLE_PARALLEL_JOBS) && !ENABLE(SINGLE_THREADED) && (ENABLE(THREADING_GENERIC) || ENABLE(THREADING_LIBDISPATCH) || ENABLE(THREADING_OPENMP))
+#define ENABLE_PARALLEL_JOBS 1
+#endif
+
 #if ENABLE(GLIB_SUPPORT)
 #include "GTypedefs.h"
 #endif
index 5f15eb04c81a0c4e327a9ccc45ae1cf464fdde56..10b41e4def23976a5a7975f078c65e755045746a 100644 (file)
@@ -21,6 +21,7 @@ SOURCES += \
     wtf/qt/ThreadingQt.cpp \
     wtf/PageAllocationAligned.cpp \
     wtf/PageBlock.cpp \
+    wtf/ParallelJobsGeneric.cpp \
     wtf/RandomNumber.cpp \
     wtf/RefCountedLeakCounter.cpp \
     wtf/SHA1.cpp \
index 6d1f0cf87ee32c26e98a1b923c7f9fae8821af3a..074cc98e389be5e1839564c8d28e5ad67c530f53 100644 (file)
@@ -1,3 +1,30 @@
+2011-04-26  Gabor Loki  <loki@webkit.org>
+
+        Reviewed by Csaba Osztrogonác.
+
+        Speeding up SVG filters with multicore (SMP) support
+        https://bugs.webkit.org/show_bug.cgi?id=43903
+
+        Some SVG filters execute a huge number of pixel manipulations, which
+        cannot be sped up by graphics accelerators, since their algorithm is
+        too complex. Using the power of Symmetric Multi Processing (SMP) we
+        can split up a task to smaller (data independent) tasks, which can be
+        executed independently.
+
+        The ParallelJobs framework provides a simple way for distributed
+        programming. The framework is based on WebKit's threading infrastructure,
+        Open Multi-Processing's (OpenMP) API, and libdispatch API.
+
+        * ForwardingHeaders/wtf/ParallelJobs.h: Added.
+        * platform/graphics/filters/FETurbulence.cpp:
+        (WebCore::FETurbulence::PaintingData::PaintingData):
+        (WebCore::FETurbulence::noise2D):
+        (WebCore::FETurbulence::calculateTurbulenceValueForPoint):
+        (WebCore::FETurbulence::fillRegion):
+        (WebCore::FETurbulence::fillRegionWorker):
+        (WebCore::FETurbulence::apply):
+        * platform/graphics/filters/FETurbulence.h:
+
 2011-04-26  Pavel Feldman  <pfeldman@google.com>
 
         Reviewed by Yury Semikhatsky.
diff --git a/Source/WebCore/ForwardingHeaders/wtf/ParallelJobs.h b/Source/WebCore/ForwardingHeaders/wtf/ParallelJobs.h
new file mode 100644 (file)
index 0000000..b064e96
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef WebCore_FWD_ParallelJobs_h
+#define WebCore_FWD_ParallelJobs_h
+#include <JavaScriptCore/ParallelJobs.h>
+#endif
index 63060e1d64f672c3e69b8f8d5735e2674ab4ec19..0935dd195ab130ac4ef2763f8f224cbf13e83d0d 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) 2011 Gabor Loki <loki@webkit.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -32,6 +33,7 @@
 
 #include <wtf/ByteArray.h>
 #include <wtf/MathExtras.h>
+#include <wtf/ParallelJobs.h>
 
 namespace WebCore {
 
@@ -152,7 +154,6 @@ FETurbulence::PaintingData::PaintingData(long paintingSeed, const IntSize& paint
     , height(0)
     , wrapX(0)
     , wrapY(0)
-    , channel(0)
     , filterSize(paintingSize)
 {
 }
@@ -224,7 +225,7 @@ inline void checkNoise(int& noiseValue, int limitValue, int newValue)
         noiseValue -= newValue - 1;
 }
 
-float FETurbulence::noise2D(PaintingData& paintingData, const FloatPoint& noiseVector)
+float FETurbulence::noise2D(int channel, PaintingData& paintingData, const FloatPoint& noiseVector)
 {
     struct Noise {
         int noisePositionIntegerValue;
@@ -259,23 +260,23 @@ float FETurbulence::noise2D(PaintingData& paintingData, const FloatPoint& noiseV
 
     // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement.
     int temp = paintingData.latticeSelector[latticeIndex + noiseY.noisePositionIntegerValue];
-    q = paintingData.gradient[paintingData.channel][temp];
+    q = paintingData.gradient[channel][temp];
     u = noiseX.noisePositionFractionValue * q[0] + noiseY.noisePositionFractionValue * q[1];
     temp = paintingData.latticeSelector[nextLatticeIndex + noiseY.noisePositionIntegerValue];
-    q = paintingData.gradient[paintingData.channel][temp];
+    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[paintingData.channel][temp];
+    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[paintingData.channel][temp];
+    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);
 }
 
-unsigned char FETurbulence::calculateTurbulenceValueForPoint(PaintingData& paintingData, const FloatPoint& point)
+unsigned char FETurbulence::calculateTurbulenceValueForPoint(int channel, PaintingData& paintingData, const FloatPoint& point)
 {
     float tileWidth = paintingData.filterSize.width();
     ASSERT(tileWidth > 0);
@@ -313,9 +314,9 @@ unsigned char FETurbulence::calculateTurbulenceValueForPoint(PaintingData& paint
     float ratio = 1;
     for (int octave = 0; octave < m_numOctaves; ++octave) {
         if (m_type == FETURBULENCE_TYPE_FRACTALNOISE)
-            turbulenceFunctionResult += noise2D(paintingData, noiseVector) / ratio;
+            turbulenceFunctionResult += noise2D(channel, paintingData, noiseVector) / ratio;
         else
-            turbulenceFunctionResult += fabsf(noise2D(paintingData, noiseVector)) / ratio;
+            turbulenceFunctionResult += fabsf(noise2D(channel, paintingData, noiseVector)) / ratio;
         noiseVector.setX(noiseVector.x() * 2);
         noiseVector.setY(noiseVector.y() * 2);
         ratio *= 2;
@@ -338,6 +339,31 @@ unsigned char FETurbulence::calculateTurbulenceValueForPoint(PaintingData& paint
     return static_cast<unsigned char>(turbulenceFunctionResult * 255);
 }
 
+inline void FETurbulence::fillRegion(ByteArray* pixelArray, PaintingData& paintingData, int startY, int endY)
+{
+    IntRect filterRegion = absolutePaintRect();
+    IntPoint point(0, filterRegion.y() + startY);
+    int indexOfPixelChannel = startY * (filterRegion.width() << 2);
+    int channel;
+
+    for (int y = startY; y < endY; ++y) {
+        point.setY(point.y() + 1);
+        point.setX(filterRegion.x());
+        for (int x = 0; x < filterRegion.width(); ++x) {
+            point.setX(point.x() + 1);
+            for (channel = 0; channel < 4; ++channel, ++indexOfPixelChannel)
+                pixelArray->set(indexOfPixelChannel, calculateTurbulenceValueForPoint(channel, paintingData, filter()->mapAbsolutePointToLocalPoint(point)));
+        }
+    }
+}
+
+#if ENABLE(PARALLEL_JOBS)
+void FETurbulence::fillRegionWorker(FillRegionParameters* parameters)
+{
+    parameters->filter->fillRegion(parameters->pixelArray, *parameters->paintingData, parameters->startY, parameters->endY);
+}
+#endif // ENABLE(PARALLEL_JOBS)
+
 void FETurbulence::apply()
 {
     if (hasResult())
@@ -352,19 +378,42 @@ void FETurbulence::apply()
     PaintingData paintingData(m_seed, roundedIntSize(filterPrimitiveSubregion().size()));
     initPaint(paintingData);
 
-    FloatRect filterRegion = absolutePaintRect();
-    FloatPoint point;
-    point.setY(filterRegion.y());
-    int indexOfPixelChannel = 0;
-    for (int y = 0; y < absolutePaintRect().height(); ++y) {
-        point.setY(point.y() + 1);
-        point.setX(filterRegion.x());
-        for (int x = 0; x < absolutePaintRect().width(); ++x) {
-            point.setX(point.x() + 1);
-            for (paintingData.channel = 0; paintingData.channel < 4; ++paintingData.channel, ++indexOfPixelChannel)
-                pixelArray->set(indexOfPixelChannel, calculateTurbulenceValueForPoint(paintingData, filter()->mapAbsolutePointToLocalPoint(point)));
+#if ENABLE(PARALLEL_JOBS)
+
+    int optimalThreadNumber = (absolutePaintRect().width() * absolutePaintRect().height()) / s_minimalRectDimension;
+    if (optimalThreadNumber > 1) {
+        // Initialize parallel jobs
+        ParallelJobs<FillRegionParameters> parallelJobs(&WebCore::FETurbulence::fillRegionWorker, optimalThreadNumber);
+
+        // Fill the parameter array
+        int i = parallelJobs.numberOfJobs();
+        if (i > 1) {
+            int startY = 0;
+            int stepY = absolutePaintRect().height() / i;
+            for (; i > 0; --i) {
+                FillRegionParameters& params = parallelJobs.parameter(i-1);
+                params.filter = this;
+                params.pixelArray = pixelArray;
+                params.paintingData = &paintingData;
+                params.startY = startY;
+                if (i != 1) {
+                    params.endY = startY + stepY;
+                    startY = startY + stepY;
+                } else
+                    params.endY = absolutePaintRect().height();
+            }
+
+            // Execute parallel jobs
+            parallelJobs.execute();
+
+            return;
         }
     }
+    // Fallback to sequential mode if there is no room for a new thread or the paint area is too small
+
+#endif // ENABLE(PARALLEL_JOBS)
+
+    fillRegion(pixelArray, paintingData, 0, absolutePaintRect().height());
 }
 
 void FETurbulence::dump()
index dfeb22014802b21eb65bd534328f40594756f9a4..04662bf58ce6cb19fec798b3963bfcbe9fe0c309 100644 (file)
@@ -58,6 +58,10 @@ public:
     bool stitchTiles() const;
     bool setStitchTiles(bool);
 
+#if ENABLE(PARALLEL_JOBS)
+    static void fillRegionWorker(void*);
+#endif
+
     virtual void apply();
     virtual void dump();
     
@@ -68,6 +72,9 @@ public:
 private:
     static const int s_blockSize = 256;
     static const int s_blockMask = s_blockSize - 1;
+#if ENABLE(PARALLEL_JOBS)
+    static const int s_minimalRectDimension = (100 * 100); // Empirical data limit for parallel jobs
+#endif
 
     struct PaintingData {
         long seed;
@@ -77,18 +84,33 @@ private:
         int height;
         int wrapX; // Minimum value to wrap.
         int wrapY;
-        int channel;
         IntSize filterSize;
 
         PaintingData(long paintingSeed, const IntSize& paintingSize);
         inline long random();
     };
 
+#if ENABLE(PARALLEL_JOBS)
+    template<typename Type>
+    friend class ParallelJobs;
+
+    struct FillRegionParameters {
+        FETurbulence* filter;
+        ByteArray* pixelArray;
+        PaintingData* paintingData;
+        int startY;
+        int endY;
+    };
+
+    static void fillRegionWorker(FillRegionParameters*);
+#endif
+
     FETurbulence(Filter*, TurbulenceType, float, float, int, float, bool);
 
     inline void initPaint(PaintingData&);
-    float noise2D(PaintingData&, const FloatPoint&);
-    unsigned char calculateTurbulenceValueForPoint(PaintingData&, const FloatPoint&);
+    float noise2D(int channel, PaintingData&, const FloatPoint&);
+    unsigned char calculateTurbulenceValueForPoint(int channel, PaintingData&, const FloatPoint&);
+    inline void fillRegion(ByteArray*, PaintingData&, int, int);
 
     TurbulenceType m_type;
     float m_baseFrequencyX;