sw_engine shape: performance optimization.
authorHermet Park <hermetpark@gmail.com>
Wed, 4 Nov 2020 07:28:47 +0000 (16:28 +0900)
committerHermet Park <chuneon.park@samsung.com>
Thu, 5 Nov 2020 01:26:15 +0000 (10:26 +0900)
we introduced shared memory pool for avoiding reallocate memory
while it process the stroke outlines, It experimentally increase
the outline data if we use the allocated memory for multiples shape strokes,
we don't need to alloc/free memory during the process.

This shared outline memory is allocated for threads count
so that we don't interrupt memory access during the tasks.

@Issues: 75

Change-Id: I2794c4368e392fa774a5cf9a9fc771963427269a

13 files changed:
src/lib/gl_engine/tvgGlRenderer.cpp
src/lib/gl_engine/tvgGlRenderer.h
src/lib/sw_engine/meson.build
src/lib/sw_engine/tvgSwCommon.h
src/lib/sw_engine/tvgSwRenderer.cpp
src/lib/sw_engine/tvgSwRenderer.h
src/lib/sw_engine/tvgSwResMgr.cpp [new file with mode: 0644]
src/lib/sw_engine/tvgSwShape.cpp
src/lib/tvgInitializer.cpp
src/lib/tvgTaskScheduler.cpp
src/lib/tvgTaskScheduler.h
src/loaders/svg/tvgSvgLoader.cpp
src/loaders/svg/tvgSvgLoader.h

index 54df5d5..5ccb8bb 100644 (file)
@@ -180,7 +180,7 @@ void* GlRenderer::prepare(const Shape& shape, void* data, TVG_UNUSED const Rende
 }
 
 
-int GlRenderer::init()
+int GlRenderer::init(uint32_t threads)
 {
     if (rendererCnt > 0) return false;
     if (initEngine) return true;
index d7d80f3..f85a91a 100644 (file)
@@ -40,7 +40,7 @@ public:
     bool clear() override;
 
     static GlRenderer* gen();
-    static int init();
+    static int init(TVG_UNUSED uint32_t threads);
     static int term();
 
 private:
index 66b1e0d..5bde72f 100644 (file)
@@ -5,6 +5,7 @@ source_file = [
    'tvgSwRenderer.h',
    'tvgSwRaster.cpp',
    'tvgSwRenderer.cpp',
+   'tvgSwResMgr.cpp',
    'tvgSwRle.cpp',
    'tvgSwShape.cpp',
    'tvgSwStroke.cpp',
index ce54180..e724492 100644 (file)
@@ -266,13 +266,13 @@ bool mathSmallCubic(SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed&
 SwFixed mathMean(SwFixed angle1, SwFixed angle2);
 
 void shapeReset(SwShape* shape);
-bool shapeGenOutline(SwShape* shape, const Shape* sdata, const Matrix* transform);
-bool shapePrepare(SwShape* shape, const Shape* sdata, const SwSize& clip, const Matrix* transform);
+bool shapeGenOutline(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform);
+bool shapePrepare(SwShape* shape, const Shape* sdata, unsigned tid, const SwSize& clip, const Matrix* transform);
 bool shapePrepared(SwShape* shape);
 bool shapeGenRle(SwShape* shape, const Shape* sdata, const SwSize& clip, bool antiAlias, bool hasComposite);
-void shapeDelOutline(SwShape* shape);
+void shapeDelOutline(SwShape* shape, uint32_t tid);
 void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transform);
-bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwSize& clip);
+bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwSize& clip);
 void shapeFree(SwShape* shape);
 void shapeDelStroke(SwShape* shape);
 bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, bool ctable);
@@ -295,6 +295,11 @@ void rleFree(SwRleData* rle);
 void rleClipPath(SwRleData *rle, const SwRleData *clip);
 void rleClipRect(SwRleData *rle, const SwBBox* clip);
 
+bool resMgrInit(uint32_t threads);
+bool resMgrTerm();
+bool resMgrClear();
+SwOutline* resMgrRequestOutline(unsigned idx);
+void resMgrRetrieveOutline(unsigned idx);
 
 bool rasterCompositor(SwSurface* surface);
 bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id);
@@ -302,7 +307,6 @@ bool rasterSolidShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g,
 bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
 bool rasterClear(SwSurface* surface);
 
-
 static inline void rasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len)
 {
 #ifdef THORVG_AVX_VECTOR_SUPPORT
index efeb0f3..ec9b47c 100644 (file)
@@ -39,7 +39,7 @@ struct SwTask : Task
     vector<Composite> compList;
     uint32_t opacity;
 
-    void run() override
+    void run(unsigned tid) override
     {
         if (opacity == 0) return;  //Invisible
 
@@ -64,13 +64,13 @@ struct SwTask : Task
             bool renderShape = (alpha > 0 || sdata->fill());
             if (renderShape || strokeAlpha) {
                 shapeReset(&shape);
-                if (!shapePrepare(&shape, sdata, clip, transform)) return;
+                if (!shapePrepare(&shape, sdata, tid, clip, transform)) goto end;
                 if (renderShape) {
                     /* We assume that if stroke width is bigger than 2,
                        shape outline below stroke could be full covered by stroke drawing.
                        Thus it turns off antialising in that condition. */
                     auto antiAlias = (strokeAlpha > 0 && strokeWidth > 2) ? false : true;
-                    if (!shapeGenRle(&shape, sdata, clip, antiAlias, compList.size() > 0 ? true : false)) return;
+                    if (!shapeGenRle(&shape, sdata, clip, antiAlias, compList.size() > 0 ? true : false)) goto end;
                 }
             }
         }
@@ -81,7 +81,7 @@ struct SwTask : Task
             if (fill) {
                 auto ctable = (flags & RenderUpdateFlag::Gradient) ? true : false;
                 if (ctable) shapeResetFill(&shape);
-                if (!shapeGenFillColors(&shape, fill, transform, surface, ctable)) return;
+                if (!shapeGenFillColors(&shape, fill, transform, surface, ctable)) goto end;
             } else {
                 shapeDelFill(&shape);
             }
@@ -90,7 +90,7 @@ struct SwTask : Task
         if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) {
             if (strokeAlpha > 0) {
                 shapeResetStroke(&shape, sdata, transform);
-                if (!shapeGenStrokeRle(&shape, sdata, transform, clip)) return;
+                if (!shapeGenStrokeRle(&shape, sdata, tid, transform, clip)) goto end;
             } else {
                 shapeDelStroke(&shape);
             }
@@ -109,7 +109,8 @@ struct SwTask : Task
                   else if (shape.strokeRle && compShape->rle) rleClipPath(shape.strokeRle, compShape->rle);
              }
         }
-        shapeDelOutline(&shape);
+    end:
+        shapeDelOutline(&shape, tid);
     }
 };
 
@@ -117,7 +118,7 @@ static void _termEngine()
 {
     if (rendererCnt > 0) return;
 
-    //TODO: Clean up global resources
+    resMgrTerm();
 }
 
 
@@ -141,7 +142,7 @@ bool SwRenderer::clear()
     for (auto task : tasks) task->get();
     tasks.clear();
 
-    return true;
+    return resMgrClear();
 }
 
 
@@ -173,7 +174,6 @@ bool SwRenderer::preRender()
 bool SwRenderer::postRender()
 {
     tasks.clear();
-
     return true;
 }
 
@@ -255,12 +255,12 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform*
 }
 
 
-bool SwRenderer::init()
+bool SwRenderer::init(uint32_t threads)
 {
     if (rendererCnt > 0) return false;
     if (initEngine) return true;
 
-    //TODO:
+    if (!resMgrInit(threads)) return false;
 
     initEngine = true;
 
@@ -283,4 +283,4 @@ SwRenderer* SwRenderer::gen()
 {
     ++rendererCnt;
     return new SwRenderer();
-}
+}
\ No newline at end of file
index 9453ec3..06b2f0f 100644 (file)
@@ -43,7 +43,7 @@ public:
     bool render(const Shape& shape, void *data) override;
 
     static SwRenderer* gen();
-    static bool init();
+    static bool init(uint32_t threads);
     static bool term();
 
 private:
diff --git a/src/lib/sw_engine/tvgSwResMgr.cpp b/src/lib/sw_engine/tvgSwResMgr.cpp
new file mode 100644 (file)
index 0000000..3a33e9f
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
+
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <vector>
+#include "tvgSwCommon.h"
+
+
+/************************************************************************/
+/* Internal Class Implementation                                        */
+/************************************************************************/
+
+static unsigned threadsCnt = 1;
+static vector<SwOutline> sharedOutline;
+
+
+/************************************************************************/
+/* External Class Implementation                                        */
+/************************************************************************/
+
+SwOutline* resMgrRequestOutline(unsigned idx)
+{
+    return &sharedOutline[idx];
+}
+
+
+void resMgrRetrieveOutline(unsigned idx)
+{
+    sharedOutline[idx].cntrsCnt = 0;
+    sharedOutline[idx].ptsCnt = 0;
+}
+
+
+bool resMgrInit(unsigned threads)
+{
+    sharedOutline.reserve(threads);
+    sharedOutline.resize(threads);
+    threadsCnt = threads;
+
+    for (auto& outline : sharedOutline) {
+        outline.cntrs = nullptr;
+        outline.pts = nullptr;
+        outline.types = nullptr;
+        outline.cntrsCnt = outline.reservedCntrsCnt = 0;
+        outline.ptsCnt = outline.reservedPtsCnt = 0;
+    }
+
+    return true;
+}
+
+
+bool resMgrClear()
+{
+    for (auto& outline : sharedOutline) {
+        if (outline.cntrs) {
+            free(outline.cntrs);
+            outline.cntrs = nullptr;
+        }
+        if (outline.pts) {
+            free(outline.pts);
+            outline.pts = nullptr;
+        }
+        if (outline.types) {
+            free(outline.types);
+            outline.types = nullptr;
+        }
+        outline.cntrsCnt = outline.reservedCntrsCnt = 0;
+        outline.ptsCnt = outline.reservedPtsCnt = 0;
+    }
+    return true;
+}
+
+
+bool resMgrTerm()
+{
+    return resMgrClear();
+}
\ No newline at end of file
index 5694da9..9fde750 100644 (file)
@@ -443,9 +443,9 @@ bool _fastTrack(const SwOutline* outline)
 /* External Class Implementation                                        */
 /************************************************************************/
 
-bool shapePrepare(SwShape* shape, const Shape* sdata, const SwSize& clip, const Matrix* transform)
+bool shapePrepare(SwShape* shape, const Shape* sdata, unsigned tid, const SwSize& clip, const Matrix* transform)
 {
-    if (!shapeGenOutline(shape, sdata, transform)) return false;
+    if (!shapeGenOutline(shape, sdata, tid, transform)) return false;
 
     if (!_updateBBox(shape->outline, shape->bbox)) return false;
 
@@ -476,17 +476,15 @@ bool shapeGenRle(SwShape* shape, TVG_UNUSED const Shape* sdata, const SwSize& cl
 }
 
 
-void shapeDelOutline(SwShape* shape)
+void shapeDelOutline(SwShape* shape, uint32_t tid)
 {
-    auto outline = shape->outline;
-    _delOutline(outline);
+    resMgrRetrieveOutline(tid);
     shape->outline = nullptr;
 }
 
 
 void shapeReset(SwShape* shape)
 {
-    shapeDelOutline(shape);
     rleFree(shape->rle);
     shape->rle = nullptr;
     shape->rect = false;
@@ -494,7 +492,7 @@ void shapeReset(SwShape* shape)
 }
 
 
-bool shapeGenOutline(SwShape* shape, const Shape* sdata, const Matrix* transform)
+bool shapeGenOutline(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform)
 {
     const PathCommand* cmds = nullptr;
     auto cmdCnt = sdata->pathCommands(&cmds);
@@ -534,8 +532,8 @@ bool shapeGenOutline(SwShape* shape, const Shape* sdata, const Matrix* transform
     ++outlinePtsCnt;    //for close
     ++outlineCntrsCnt;  //for end
 
+    shape->outline = resMgrRequestOutline(tid);
     auto outline = shape->outline;
-    if (!outline) outline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline)));
     outline->opened = true;
 
     _growOutlinePoint(*outline, outlinePtsCnt);
@@ -583,7 +581,6 @@ bool shapeGenOutline(SwShape* shape, const Shape* sdata, const Matrix* transform
 
 void shapeFree(SwShape* shape)
 {
-    shapeDelOutline(shape);
     rleFree(shape->rle);
     shapeDelFill(shape);
 
@@ -617,7 +614,7 @@ void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transfor
 }
 
 
-bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwSize& clip)
+bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwSize& clip)
 {
     SwOutline* shapeOutline = nullptr;
     SwOutline* strokeOutline = nullptr;
@@ -632,7 +629,7 @@ bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transfo
     //Normal Style stroke
     } else {
         if (!shape->outline) {
-            if (!shapeGenOutline(shape, sdata, transform)) return false;
+            if (!shapeGenOutline(shape, sdata, tid, transform)) return false;
         }
         shapeOutline = shape->outline;
     }
index bc0a65f..a32cb5d 100644 (file)
@@ -49,12 +49,12 @@ Result Initializer::init(CanvasEngine engine, uint32_t threads) noexcept
 
     if (static_cast<uint32_t>(engine) & static_cast<uint32_t>(CanvasEngine::Sw)) {
         #ifdef THORVG_SW_RASTER_SUPPORT
-            if (!SwRenderer::init()) return Result::InsufficientCondition;
+            if (!SwRenderer::init(threads)) return Result::InsufficientCondition;
             nonSupport = false;
         #endif
     } else if (static_cast<uint32_t>(engine) & static_cast<uint32_t>(CanvasEngine::Gl)) {
         #ifdef THORVG_GL_RASTER_SUPPORT
-            if (!GlRenderer::init()) return Result::InsufficientCondition;
+            if (!GlRenderer::init(threads)) return Result::InsufficientCondition;
             nonSupport = false;
         #endif
     } else {
index d4c21f1..2ad4ca6 100644 (file)
@@ -133,7 +133,7 @@ public:
             }
 
             if (!success && !taskQueues[i].pop(&task)) break;
-            (*task)();
+            (*task)(i);
         }
     }
 
@@ -149,7 +149,7 @@ public:
             taskQueues[i % threadCnt].push(task);
         //Sync
         } else {
-            task->run();
+            task->run(0);
         }
     }
 };
index d94a318..1db434a 100644 (file)
@@ -50,12 +50,12 @@ public:
     }
 
 protected:
-    virtual void run() = 0;
+    virtual void run(unsigned tid) = 0;
 
 private:
-    void operator()()
+    void operator()(unsigned tid)
     {
-        run();
+        run(tid);
         sender.set_value();
     }
 
index 27a6b91..9aeca5c 100644 (file)
@@ -2431,7 +2431,7 @@ SvgLoader::~SvgLoader()
 }
 
 
-void SvgLoader::run()
+void SvgLoader::run(unsigned tid)
 {
     if (!simpleXmlParse(content, size, true, _svgLoaderParser, &(loaderData))) return;
 
index cd04d7d..11f8f4e 100644 (file)
@@ -44,7 +44,7 @@ public:
     bool header();
     bool read() override;
     bool close() override;
-    void run() override;
+    void run(unsigned tid) override;
 
     unique_ptr<Scene> data() override;
 };