include/vcl/BitmapFilter.hxx                 |   28 ++++++++++++
 vcl/qa/cppunit/BitmapFilterTest.cxx          |   63 +++++++++++++++++++++++++++
 vcl/source/bitmap/BitmapFilterStackBlur.cxx  |   49 ++++++++++++---------
 vcl/source/bitmap/BitmapScaleSuperFilter.cxx |   24 ++++------
 4 files changed, 130 insertions(+), 34 deletions(-)

New commits:
commit 8166f340511f49c91deba161f27d9ded11a14e14
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Wed Jul 1 15:57:15 2020 +0200
Commit:     Tomaž Vajngerl <qui...@gmail.com>
CommitDate: Sun Jul 5 23:17:16 2020 +0200

    add generateStripRanges and use that in StackBlur and ScaleSuper
    
    generateStripRanges divides a range into equally long stripes that
    is useful for defining scanlines for a thread. This is used in
    the BitmapFilterStackBlur and BitmapScaleSuperFilter as they are
    running using a thread pool.
    
    Change-Id: Ifb9f70dea3b0233e6aa30ccf20187a2ff58fd5a2
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/97725
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>

diff --git a/include/vcl/BitmapFilter.hxx b/include/vcl/BitmapFilter.hxx
index 19599d06316f..0521ded42357 100644
--- a/include/vcl/BitmapFilter.hxx
+++ b/include/vcl/BitmapFilter.hxx
@@ -12,8 +12,36 @@
 #define INCLUDED_VCL_BITMAPFILTER_HXX
 
 #include <vcl/bitmapex.hxx>
+#include <functional>
+
 class Animation;
 
+namespace vcl::bitmap
+{
+// Generates strip ranges and run the input function with the start and
+// end as parameters. The additional parameter bLast denotes if the
+// iteration is teh last one.
+//
+// Example:
+// first = 0, last = 100, STRIP_SIZE = 32
+// this will generate:
+// [0, 31, false], [32, 63, false], [64, 95, false], [96, 100, true]
+template <int STRIP_SIZE>
+void generateStripRanges(
+    long nFirst, long nLast,
+    std::function<void(long const nStart, long const nEnd, bool const bLast)> 
aFunction)
+{
+    long nStart = nFirst;
+    for (; nStart < nLast - STRIP_SIZE; nStart += STRIP_SIZE)
+    {
+        long nEnd = nStart + STRIP_SIZE - 1;
+        aFunction(nStart, nEnd, false);
+    }
+    aFunction(nStart, nLast, true);
+}
+
+} // end vcl::bitmap
+
 class VCL_DLLPUBLIC BitmapFilter
 {
 public:
diff --git a/vcl/qa/cppunit/BitmapFilterTest.cxx 
b/vcl/qa/cppunit/BitmapFilterTest.cxx
index dddfaf571dd4..a519da24ed9b 100644
--- a/vcl/qa/cppunit/BitmapFilterTest.cxx
+++ b/vcl/qa/cppunit/BitmapFilterTest.cxx
@@ -38,11 +38,13 @@ public:
     void testBlurCorrectness();
     void testBasicMorphology();
     void testPerformance();
+    void testGenerateStripRanges();
 
     CPPUNIT_TEST_SUITE(BitmapFilterTest);
     CPPUNIT_TEST(testBlurCorrectness);
     CPPUNIT_TEST(testBasicMorphology);
     CPPUNIT_TEST(testPerformance);
+    CPPUNIT_TEST(testGenerateStripRanges);
     CPPUNIT_TEST_SUITE_END();
 
 private:
@@ -209,6 +211,67 @@ void BitmapFilterTest::testPerformance()
     }
 }
 
+void BitmapFilterTest::testGenerateStripRanges()
+{
+    {
+        constexpr long nFirstIndex = 0;
+        constexpr long nLastIndex = 100;
+        constexpr long nStripSize = 32;
+
+        std::vector<std::tuple<long, long, bool>> aRanges;
+
+        vcl::bitmap::generateStripRanges<nStripSize>(
+            nFirstIndex, nLastIndex, [&](long const nStart, long const nEnd, 
bool const bLast) {
+                aRanges.emplace_back(nStart, nEnd, bLast);
+            });
+
+        CPPUNIT_ASSERT_EQUAL(size_t(4), aRanges.size());
+
+        CPPUNIT_ASSERT_EQUAL(0L, std::get<0>(aRanges[0]));
+        CPPUNIT_ASSERT_EQUAL(31L, std::get<1>(aRanges[0]));
+        CPPUNIT_ASSERT_EQUAL(false, std::get<2>(aRanges[0]));
+
+        CPPUNIT_ASSERT_EQUAL(32L, std::get<0>(aRanges[1]));
+        CPPUNIT_ASSERT_EQUAL(63L, std::get<1>(aRanges[1]));
+        CPPUNIT_ASSERT_EQUAL(false, std::get<2>(aRanges[1]));
+
+        CPPUNIT_ASSERT_EQUAL(64L, std::get<0>(aRanges[2]));
+        CPPUNIT_ASSERT_EQUAL(95L, std::get<1>(aRanges[2]));
+        CPPUNIT_ASSERT_EQUAL(false, std::get<2>(aRanges[2]));
+
+        CPPUNIT_ASSERT_EQUAL(96L, std::get<0>(aRanges[3]));
+        CPPUNIT_ASSERT_EQUAL(100L, std::get<1>(aRanges[3]));
+        CPPUNIT_ASSERT_EQUAL(true, std::get<2>(aRanges[3]));
+    }
+
+    {
+        constexpr long nFirstIndex = 0;
+        constexpr long nLastIndex = 95;
+        constexpr long nStripSize = 32;
+
+        std::vector<std::tuple<long, long, bool>> aRanges;
+
+        vcl::bitmap::generateStripRanges<nStripSize>(
+            nFirstIndex, nLastIndex, [&](long const nStart, long const nEnd, 
bool const bLast) {
+                aRanges.emplace_back(nStart, nEnd, bLast);
+            });
+
+        CPPUNIT_ASSERT_EQUAL(size_t(3), aRanges.size());
+
+        CPPUNIT_ASSERT_EQUAL(0L, std::get<0>(aRanges[0]));
+        CPPUNIT_ASSERT_EQUAL(31L, std::get<1>(aRanges[0]));
+        CPPUNIT_ASSERT_EQUAL(false, std::get<2>(aRanges[0]));
+
+        CPPUNIT_ASSERT_EQUAL(32L, std::get<0>(aRanges[1]));
+        CPPUNIT_ASSERT_EQUAL(63L, std::get<1>(aRanges[1]));
+        CPPUNIT_ASSERT_EQUAL(false, std::get<2>(aRanges[1]));
+
+        CPPUNIT_ASSERT_EQUAL(64L, std::get<0>(aRanges[2]));
+        CPPUNIT_ASSERT_EQUAL(95L, std::get<1>(aRanges[2]));
+        CPPUNIT_ASSERT_EQUAL(true, std::get<2>(aRanges[2]));
+    }
+}
+
 } // namespace
 
 CPPUNIT_TEST_SUITE_REGISTRATION(BitmapFilterTest);
diff --git a/vcl/source/bitmap/BitmapFilterStackBlur.cxx 
b/vcl/source/bitmap/BitmapFilterStackBlur.cxx
index 69e7c8b2e3ec..a9e17eee2cd2 100644
--- a/vcl/source/bitmap/BitmapFilterStackBlur.cxx
+++ b/vcl/source/bitmap/BitmapFilterStackBlur.cxx
@@ -469,17 +469,21 @@ void runStackBlur(Bitmap& rBitmap, const long nRadius, 
const long nComponentWidt
                 BlurSharedData aSharedData(pReadAccess.get(), 
pWriteAccess.get(), nRadius,
                                            nComponentWidth, nColorChannels);
 
+                const long nFirstIndex = 0;
                 const long nLastIndex = pReadAccess->Height() - 1;
-                long nStripStart = 0;
-                for (; nStripStart < nLastIndex - nThreadStrip; nStripStart += 
nThreadStrip)
-                {
-                    long nStripEnd = nStripStart + nThreadStrip - 1;
-                    auto pTask(std::make_unique<BlurTask>(pTag, 
pBlurHorizontalFn, aSharedData,
-                                                          nStripStart, 
nStripEnd));
-                    rShared.pushTask(std::move(pTask));
-                }
-                // Do the last (or the only) strip in main thread without 
threading overhead
-                pBlurHorizontalFn(aSharedData, nStripStart, nLastIndex);
+
+                vcl::bitmap::generateStripRanges<nThreadStrip>(
+                    nFirstIndex, nLastIndex,
+                    [&](long const nStart, long const nEnd, bool const bLast) {
+                        if (!bLast)
+                        {
+                            auto pTask(std::make_unique<BlurTask>(pTag, 
pBlurHorizontalFn,
+                                                                  aSharedData, 
nStart, nEnd));
+                            rShared.pushTask(std::move(pTask));
+                        }
+                        else
+                            pBlurHorizontalFn(aSharedData, nStart, nEnd);
+                    });
                 rShared.waitUntilDone(pTag);
             }
             {
@@ -488,17 +492,22 @@ void runStackBlur(Bitmap& rBitmap, const long nRadius, 
const long nComponentWidt
                 BlurSharedData aSharedData(pReadAccess.get(), 
pWriteAccess.get(), nRadius,
                                            nComponentWidth, nColorChannels);
 
+                const long nFirstIndex = 0;
                 const long nLastIndex = pReadAccess->Width() - 1;
-                long nStripStart = 0;
-                for (; nStripStart < nLastIndex - nThreadStrip; nStripStart += 
nThreadStrip)
-                {
-                    long nStripEnd = nStripStart + nThreadStrip - 1;
-                    auto pTask(std::make_unique<BlurTask>(pTag, 
pBlurVerticalFn, aSharedData,
-                                                          nStripStart, 
nStripEnd));
-                    rShared.pushTask(std::move(pTask));
-                }
-                // Do the last (or the only) strip in main thread without 
threading overhead
-                pBlurVerticalFn(aSharedData, nStripStart, nLastIndex);
+
+                vcl::bitmap::generateStripRanges<nThreadStrip>(
+                    nFirstIndex, nLastIndex,
+                    [&](long const nStart, long const nEnd, bool const bLast) {
+                        if (!bLast)
+                        {
+                            auto pTask(std::make_unique<BlurTask>(pTag, 
pBlurVerticalFn,
+                                                                  aSharedData, 
nStart, nEnd));
+                            rShared.pushTask(std::move(pTask));
+                        }
+                        else
+                            pBlurVerticalFn(aSharedData, nStart, nEnd);
+                    });
+
                 rShared.waitUntilDone(pTag);
             }
         }
diff --git a/vcl/source/bitmap/BitmapScaleSuperFilter.cxx 
b/vcl/source/bitmap/BitmapScaleSuperFilter.cxx
index 4b6d8ede851b..42d2897143f0 100644
--- a/vcl/source/bitmap/BitmapScaleSuperFilter.cxx
+++ b/vcl/source/bitmap/BitmapScaleSuperFilter.cxx
@@ -983,21 +983,17 @@ BitmapEx BitmapScaleSuperFilter::execute(BitmapEx const& 
rBitmap) const
                     comphelper::ThreadPool &rShared = 
comphelper::ThreadPool::getSharedOptimalPool();
                     std::shared_ptr<comphelper::ThreadTaskTag> pTag = 
comphelper::ThreadPool::createThreadTaskTag();
 
-                    long nStripYStart = nStartY;
-                    long nStripYEnd = nStripYStart + constScaleThreadStrip - 1;
-
-                    while (nStripYEnd < nEndY)
-                    {
-                        std::unique_ptr<ScaleTask> pTask(new ScaleTask(pTag, 
pScaleRangeFn, aContext, nStripYStart, nStripYEnd));
-                        rShared.pushTask(std::move(pTask));
-                        nStripYStart += constScaleThreadStrip;
-                        nStripYEnd += constScaleThreadStrip;
-                    }
-                    if (nStripYStart <= nEndY)
+                    
vcl::bitmap::generateStripRanges<constScaleThreadStrip>(nStartY, nEndY,
+                    [&] (long const nStart, long const nEnd, bool const bLast)
                     {
-                        std::unique_ptr<ScaleTask> pTask(new ScaleTask(pTag, 
pScaleRangeFn, aContext, nStripYStart, nEndY));
-                        rShared.pushTask(std::move(pTask));
-                    }
+                        if (!bLast)
+                        {
+                            auto pTask(std::make_unique<ScaleTask>(pTag, 
pScaleRangeFn, aContext, nStart, nEnd));
+                            rShared.pushTask(std::move(pTask));
+                        }
+                        else
+                            pScaleRangeFn(aContext, nStart, nEnd);
+                    });
                     rShared.waitUntilDone(pTag);
                     SAL_INFO("vcl.gdi", "All threaded scaling tasks complete");
                 }
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to