sw_engine: fix invalid data sharing at multi-threading.
authorHermet Park <chuneon.park@samsung.com>
Fri, 7 May 2021 10:45:07 +0000 (19:45 +0900)
committerJunsuChoi <jsuya.choi@samsung.com>
Thu, 13 May 2021 08:22:11 +0000 (17:22 +0900)
We have encountered that multi-threading usage that user creates,
multiple canvases owned by multiple user threads.

Current sw_engine memory pool has been considered only for multi-threads,
spawned by tvg task scheduler.

In this case it's safe but when user threads introduced, it can occur race-condition.

Thus, Here is a renewal policy that non-threading tvg(initialized threads with zero),
takes care of multiple user threads bu changing its policy,
each of canvases should have individual memory pool to guarantee mutual-exclusion.

@API additions

enum MempoolPolicy
{
    Default = 0, ///< Default behavior that ThorVG is designed to.
    Shareable,   ///< Memory Pool is shared among the SwCanvases.
    Individual   ///< Allocate designated memory pool that is only used by current instance.
};

Result SwCanvas::mempool(MempoolPolicy policy) noexcept;

All in all, if user calls multiple threads, set memory pool policy to Individual.

inc/thorvg.h
src/lib/sw_engine/tvgSwCommon.h
src/lib/sw_engine/tvgSwImage.cpp
src/lib/sw_engine/tvgSwMemPool.cpp
src/lib/sw_engine/tvgSwRenderer.cpp
src/lib/sw_engine/tvgSwRenderer.h
src/lib/sw_engine/tvgSwShape.cpp
src/lib/sw_engine/tvgSwStroke.cpp
src/lib/tvgSwCanvas.cpp

index d391f6e..277c573 100644 (file)
@@ -1115,6 +1115,18 @@ public:
     };
 
     /**
+     * @brief Enumeration specifying the methods of Memory Pool behavior policy.
+     *
+     * @BETA_API
+     */
+    enum MempoolPolicy
+    {
+        Default = 0, ///< Default behavior that ThorVG is designed to.
+        Shareable,   ///< Memory Pool is shared among the SwCanvases.
+        Individual   ///< Allocate designated memory pool that is only used by current instance.
+    };
+
+    /**
      * @brief Sets the target buffer for the rasterization.
      *
      * The buffer of a desirable size should be allocated and owned by the caller.
@@ -1135,6 +1147,31 @@ public:
     Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, Colorspace cs) noexcept;
 
     /**
+     * @brief Set sw engine memory pool behavior policy.
+     *
+     * Basically ThorVG draws a lot of shapes, it allocates/deallocates a few chunk of memory
+     * while processing rendering. It internally uses one shared memory pool
+     * which can be reused among the canvases in order to avoid memory overhead.
+     *
+     * Thus ThorVG suggests memory pool policy to satisfy user demands,
+     * if it needs to guarantee the thread-safety of the internal data access.
+     *
+     * @param[in] policy Use the shared cache memory. The default value is @c true
+     *
+     * @retval Result::Success When succeed.
+     * @retval Result::InsufficientCondition If the canvas has any paints.
+     * @retval Result::NonSupport In case the software engine is not supported.
+     *
+     * @note When @c policy is set as @c MempoolPolicy::Individual, current instance of canvas uses its own individual
+     *       memory data that is not shared with others. This is necessary when the canvas is accessed on a worker-thread.
+     *
+     * @warning It's not allowed after pushing any paints.
+     *
+     * @BETA_API
+    */
+    Result mempool(MempoolPolicy policy) noexcept;
+
+    /**
      * @brief Creates a new SwCanvas object.
      * @return A new SwCanvas object when succeed, otherwise @c nullptr
      */
index 47d7d6d..7966b6d 100644 (file)
@@ -254,6 +254,13 @@ struct SwCompositor : Compositor
     bool valid;
 };
 
+struct SwMpool
+{
+    SwOutline* outline = nullptr;
+    SwOutline* strokeOutline = nullptr;
+    unsigned allocSize = 0;
+};
+
 static inline SwCoord TO_SWCOORD(float val)
 {
     return SwCoord(val * 64);
@@ -299,13 +306,12 @@ SwPoint mathTransform(const Point* to, const Matrix* transform);
 bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, SwBBox& renderRegion);
 
 void shapeReset(SwShape* shape);
-bool shapeGenOutline(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform);
-bool shapePrepare(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion);
+bool shapePrepare(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid);
 bool shapePrepared(const SwShape* shape);
 bool shapeGenRle(SwShape* shape, const Shape* sdata, bool antiAlias, bool hasComposite);
-void shapeDelOutline(SwShape* shape, uint32_t tid);
+void shapeDelOutline(SwShape* shape, SwMpool* mpool, uint32_t tid);
 void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transform);
-bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion);
+bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid);
 void shapeFree(SwShape* shape);
 void shapeDelStroke(SwShape* shape);
 bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, uint32_t opacity, bool ctable);
@@ -317,15 +323,14 @@ void shapeDelStrokeFill(SwShape* shape);
 
 void strokeReset(SwStroke* stroke, const Shape* shape, const Matrix* transform);
 bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline);
-SwOutline* strokeExportOutline(SwStroke* stroke, unsigned tid);
+SwOutline* strokeExportOutline(SwStroke* stroke, SwMpool* mpool, unsigned tid);
 void strokeFree(SwStroke* stroke);
 
-bool imagePrepare(SwImage* image, const Picture* pdata, unsigned tid, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion);
+bool imagePrepare(SwImage* image, const Picture* pdata, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid);
 bool imagePrepared(const SwImage* image);
 bool imageGenRle(SwImage* image, TVG_UNUSED const Picture* pdata, const SwBBox& renderRegion, bool antiAlias);
-void imageDelOutline(SwImage* image, uint32_t tid);
+void imageDelOutline(SwImage* image, SwMpool* mpool, uint32_t tid);
 void imageReset(SwImage* image);
-bool imageGenOutline(SwImage* image, const Picture* pdata, unsigned tid, const Matrix* transform);
 void imageFree(SwImage* image);
 
 bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, SwSurface* surface, uint32_t opacity, bool ctable);
@@ -341,13 +346,13 @@ void rleClipPath(SwRleData *rle, const SwRleData *clip);
 void rleClipRect(SwRleData *rle, const SwBBox* clip);
 void rleAlphaMask(SwRleData *rle, const SwRleData *clip);
 
-bool mpoolInit(uint32_t threads);
-bool mpoolTerm();
-bool mpoolClear();
-SwOutline* mpoolReqOutline(unsigned idx);
-void mpoolRetOutline(unsigned idx);
-SwOutline* mpoolReqStrokeOutline(unsigned idx);
-void mpoolRetStrokeOutline(unsigned idx);
+SwMpool* mpoolInit(uint32_t threads);
+bool mpoolTerm(SwMpool* mpool);
+bool mpoolClear(SwMpool* mpool);
+SwOutline* mpoolReqOutline(SwMpool* mpool, unsigned idx);
+void mpoolRetOutline(SwMpool* mpool, unsigned idx);
+SwOutline* mpoolReqStrokeOutline(SwMpool* mpool, unsigned idx);
+void mpoolRetStrokeOutline(SwMpool* mpool, unsigned idx);
 
 bool rasterCompositor(SwSurface* surface);
 bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id);
index 03bf174..48b1e6c 100644 (file)
 /* Internal Class Implementation                                        */
 /************************************************************************/
 
+static bool _genOutline(SwImage* image, const Picture* pdata, const Matrix* transform, SwMpool* mpool,  unsigned tid)
+{
+    float w, h;
+    pdata->viewbox(nullptr, nullptr, &w, &h);
+    if (w == 0 || h == 0) return false;
+
+    image->outline = mpoolReqOutline(mpool, tid);
+    auto outline = image->outline;
+
+    outline->reservedPtsCnt = 5;
+    outline->pts = static_cast<SwPoint*>(realloc(outline->pts, outline->reservedPtsCnt * sizeof(SwPoint)));
+    outline->types = static_cast<uint8_t*>(realloc(outline->types, outline->reservedPtsCnt * sizeof(uint8_t)));
+
+    outline->reservedCntrsCnt = 1;
+    outline->cntrs = static_cast<uint32_t*>(realloc(outline->cntrs, outline->reservedCntrsCnt * sizeof(uint32_t)));
+
+    Point to[4] = {{0 ,0}, {w, 0}, {w, h}, {0, h}};
+    for (int i = 0; i < 4; i++) {
+        outline->pts[outline->ptsCnt] = mathTransform(&to[i], transform);
+        outline->types[outline->ptsCnt] = SW_CURVE_TYPE_POINT;
+        ++outline->ptsCnt;
+    }
+
+    outline->pts[outline->ptsCnt] = outline->pts[0];
+    outline->types[outline->ptsCnt] = SW_CURVE_TYPE_POINT;
+    ++outline->ptsCnt;
+
+    outline->cntrs[outline->cntrsCnt] = outline->ptsCnt - 1;
+    ++outline->cntrsCnt;
+
+    outline->opened = false;
+
+    image->outline = outline;
+    image->w = w;
+    image->h = h;
+
+    return true;
+}
 
 
 /************************************************************************/
@@ -33,9 +71,9 @@
 /************************************************************************/
 
 
-bool imagePrepare(SwImage* image, const Picture* pdata, unsigned tid, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion)
+bool imagePrepare(SwImage* image, const Picture* pdata, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid)
 {
-    if (!imageGenOutline(image, pdata, tid, transform)) return false;
+    if (!_genOutline(image, pdata, transform, mpool, tid)) return false;
     return mathUpdateOutlineBBox(image->outline, clipRegion, renderRegion);
 }
 
@@ -54,9 +92,9 @@ bool imageGenRle(SwImage* image, TVG_UNUSED const Picture* pdata, const SwBBox&
 }
 
 
-void imageDelOutline(SwImage* image, uint32_t tid)
+void imageDelOutline(SwImage* image, SwMpool* mpool, uint32_t tid)
 {
-    mpoolRetOutline(tid);
+    mpoolRetOutline(mpool, tid);
     image->outline = nullptr;
 }
 
@@ -68,45 +106,6 @@ void imageReset(SwImage* image)
 }
 
 
-bool imageGenOutline(SwImage* image, const Picture* pdata, unsigned tid, const Matrix* transform)
-{
-    float w, h;
-    pdata->viewbox(nullptr, nullptr, &w, &h);
-    if (w == 0 || h == 0) return false;
-
-    image->outline = mpoolReqOutline(tid);
-    auto outline = image->outline;
-
-    outline->reservedPtsCnt = 5;
-    outline->pts = static_cast<SwPoint*>(realloc(outline->pts, outline->reservedPtsCnt * sizeof(SwPoint)));
-    outline->types = static_cast<uint8_t*>(realloc(outline->types, outline->reservedPtsCnt * sizeof(uint8_t)));
-
-    outline->reservedCntrsCnt = 1;
-    outline->cntrs = static_cast<uint32_t*>(realloc(outline->cntrs, outline->reservedCntrsCnt * sizeof(uint32_t)));
-
-    Point to[4] = {{0 ,0}, {w, 0}, {w, h}, {0, h}};
-    for (int i = 0; i < 4; i++) {
-        outline->pts[outline->ptsCnt] = mathTransform(&to[i], transform);
-        outline->types[outline->ptsCnt] = SW_CURVE_TYPE_POINT;
-        ++outline->ptsCnt;
-    }
-
-    outline->pts[outline->ptsCnt] = outline->pts[0];
-    outline->types[outline->ptsCnt] = SW_CURVE_TYPE_POINT;
-    ++outline->ptsCnt;
-
-    outline->cntrs[outline->cntrsCnt] = outline->ptsCnt - 1;
-    ++outline->cntrsCnt;
-
-    outline->opened = false;
-
-    image->outline = outline;
-    image->w = w;
-    image->h = h;
-
-    return true;
-}
-
 void imageFree(SwImage* image)
 {
     rleFree(image->rle);
index 6975d23..1b61fd2 100644 (file)
 /* Internal Class Implementation                                        */
 /************************************************************************/
 
-static SwOutline* outline = nullptr;
-static SwOutline* strokeOutline = nullptr;
-static unsigned allocSize = 0;
-
 
 /************************************************************************/
 /* External Class Implementation                                        */
 /************************************************************************/
 
-SwOutline* mpoolReqOutline(unsigned idx)
+SwOutline* mpoolReqOutline(SwMpool* mpool, unsigned idx)
 {
-    return &outline[idx];
+    return &mpool->outline[idx];
 }
 
 
-void mpoolRetOutline(unsigned idx)
+void mpoolRetOutline(SwMpool* mpool, unsigned idx)
 {
-    outline[idx].cntrsCnt = 0;
-    outline[idx].ptsCnt = 0;
+    mpool->outline[idx].cntrsCnt = 0;
+    mpool->outline[idx].ptsCnt = 0;
 }
 
 
-SwOutline* mpoolReqStrokeOutline(unsigned idx)
+SwOutline* mpoolReqStrokeOutline(SwMpool* mpool, unsigned idx)
 {
-    return &strokeOutline[idx];
+    return &mpool->strokeOutline[idx];
 }
 
 
-void mpoolRetStrokeOutline(unsigned idx)
+void mpoolRetStrokeOutline(SwMpool* mpool, unsigned idx)
 {
-    strokeOutline[idx].cntrsCnt = 0;
-    strokeOutline[idx].ptsCnt = 0;
+    mpool->strokeOutline[idx].cntrsCnt = 0;
+    mpool->strokeOutline[idx].ptsCnt = 0;
 }
 
 
-bool mpoolInit(unsigned threads)
+SwMpool* mpoolInit(unsigned threads)
 {
-    if (outline || strokeOutline) return false;
+    auto mpool = new SwMpool;
+    if (!mpool) return nullptr;
+
     if (threads == 0) threads = 1;
 
-    outline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline) * threads));
-    if (!outline) goto err;
+    mpool->outline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline) * threads));
+    if (!mpool->outline) goto err;
 
-    strokeOutline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline) * threads));
-    if (!strokeOutline) goto err;
+    mpool->strokeOutline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline) * threads));
+    if (!mpool->strokeOutline) goto err;
 
-    allocSize = threads;
+    mpool->allocSize = threads;
 
-    return true;
+    return mpool;
 
 err:
-    if (outline) {
-        free(outline);
-        outline = nullptr;
+    if (mpool->outline) {
+        free(mpool->outline);
+        mpool->outline = nullptr;
     }
 
-    if (strokeOutline) {
-        free(strokeOutline);
-        strokeOutline = nullptr;
+    if (mpool->strokeOutline) {
+        free(mpool->strokeOutline);
+        mpool->strokeOutline = nullptr;
     }
-    return false;
+    delete(mpool);
+    return nullptr;
 }
 
 
-bool mpoolClear()
+bool mpoolClear(SwMpool* mpool)
 {
     SwOutline* p;
 
-    for (unsigned i = 0; i < allocSize; ++i) {
+    for (unsigned i = 0; i < mpool->allocSize; ++i) {
 
-        p = &outline[i];
+        p = &mpool->outline[i];
 
         if (p->cntrs) {
             free(p->cntrs);
@@ -113,7 +112,7 @@ bool mpoolClear()
         p->cntrsCnt = p->reservedCntrsCnt = 0;
         p->ptsCnt = p->reservedPtsCnt = 0;
 
-        p = &strokeOutline[i];
+        p = &mpool->strokeOutline[i];
 
         if (p->cntrs) {
             free(p->cntrs);
@@ -135,21 +134,23 @@ bool mpoolClear()
 }
 
 
-bool mpoolTerm()
+bool mpoolTerm(SwMpool* mpool)
 {
-    mpoolClear();
+    if (!mpool) return false;
+
+    mpoolClear(mpool);
 
-    if (outline) {
-        free(outline);
-        outline = nullptr;
+    if (mpool->outline) {
+        free(mpool->outline);
+        mpool->outline = nullptr;
     }
 
-    if (strokeOutline) {
-        free(strokeOutline);
-        strokeOutline = nullptr;
+    if (mpool->strokeOutline) {
+        free(mpool->strokeOutline);
+        mpool->strokeOutline = nullptr;
     }
 
-    allocSize = 0;
+    delete(mpool);
 
     return true;
 }
\ No newline at end of file
index ca4a1f0..34428df 100644 (file)
 /************************************************************************/
 static int32_t initEngineCnt = false;
 static int32_t rendererCnt = 0;
-
+static SwMpool* globalMpool = nullptr;
+static uint32_t threadsCnt = 0;
 
 struct SwTask : Task
 {
     Matrix* transform = nullptr;
     SwSurface* surface = nullptr;
+    SwMpool* mpool = nullptr;
     RenderUpdateFlag flags = RenderUpdateFlag::None;
     Array<RenderData> clips;
     uint32_t opacity;
@@ -92,7 +94,7 @@ struct SwShapeTask : SwTask
             bool renderShape = (alpha > 0 || sdata->fill());
             if (renderShape || validStroke) {
                 shapeReset(&shape);
-                if (!shapePrepare(&shape, sdata, tid, transform, clipRegion, bbox)) goto err;
+                if (!shapePrepare(&shape, sdata, transform, clipRegion, bbox, mpool, tid)) goto err;
                 if (renderShape) {
                     /* We assume that if stroke width is bigger than 2,
                        shape outline below stroke could be full covered by stroke drawing.
@@ -121,7 +123,7 @@ struct SwShapeTask : SwTask
         if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) {
             if (validStroke) {
                 shapeResetStroke(&shape, sdata, transform);
-                if (!shapeGenStrokeRle(&shape, sdata, tid, transform, clipRegion, bbox)) goto err;
+                if (!shapeGenStrokeRle(&shape, sdata, transform, clipRegion, bbox, mpool, tid)) goto err;
                 ++addStroking;
 
                 if (auto fill = sdata->strokeFill()) {
@@ -155,7 +157,7 @@ struct SwShapeTask : SwTask
     err:
         shapeReset(&shape);
     end:
-        shapeDelOutline(&shape, tid);
+        shapeDelOutline(&shape, mpool, tid);
         if (addStroking > 1 && opacity < 255) cmpStroking = true;
         else cmpStroking = false;
     }
@@ -183,7 +185,7 @@ struct SwImageTask : SwTask
 
         if (prepareImage) {
             imageReset(&image);
-            if (!imagePrepare(&image, pdata, tid, transform, clipRegion, bbox)) goto end;
+            if (!imagePrepare(&image, pdata, transform, clipRegion, bbox, mpool, tid)) goto end;
 
             //Clip Path?
             if (clips.count > 0) {
@@ -199,7 +201,7 @@ struct SwImageTask : SwTask
         }
         image.data = const_cast<uint32_t*>(pdata->data());
     end:
-        imageDelOutline(&image, tid);
+        imageDelOutline(&image, mpool, tid);
     }
 
     bool dispose() override
@@ -214,7 +216,8 @@ static void _termEngine()
 {
     if (rendererCnt > 0) return;
 
-    mpoolTerm();
+    mpoolTerm(globalMpool);
+    globalMpool = nullptr;
 }
 
 
@@ -228,6 +231,8 @@ SwRenderer::~SwRenderer()
 
     if (surface) delete(surface);
 
+    if (!sharedMpool) mpoolTerm(mpool);
+
     --rendererCnt;
 
     if (rendererCnt == 0 && initEngineCnt == 0) _termEngine();
@@ -397,6 +402,24 @@ bool SwRenderer::beginComposite(Compositor* cmp, CompositeMethod method, uint32_
 }
 
 
+bool SwRenderer::mempool(bool shared)
+{
+    if (shared) {
+        if (!sharedMpool) {
+            if (!mpoolTerm(mpool)) return false;
+            mpool = globalMpool;
+        }
+    } else {
+        if (sharedMpool) mpool = mpoolInit(threadsCnt);
+    }
+
+    sharedMpool = shared;
+
+    if (mpool) return true;
+    return false;
+}
+
+
 Compositor* SwRenderer::target(const RenderRegion& region)
 {
     auto x = region.x;
@@ -539,6 +562,7 @@ void* SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform,
 
     task->opacity = opacity;
     task->surface = surface;
+    task->mpool = mpool;
     task->flags = flags;
     task->bbox.min.x = max(static_cast<SwCoord>(0), static_cast<SwCoord>(vport.x));
     task->bbox.min.y = max(static_cast<SwCoord>(0), static_cast<SwCoord>(vport.y));
@@ -578,11 +602,20 @@ RenderData SwRenderer::prepare(const Shape& sdata, RenderData data, const Render
 }
 
 
+SwRenderer::SwRenderer():mpool(globalMpool)
+{
+}
+
+
 bool SwRenderer::init(uint32_t threads)
 {
     if ((initEngineCnt++) > 0) return true;
 
-    if (!mpoolInit(threads)) return false;
+    threadsCnt = threads;
+
+    //Share the memory pool among the renderer
+    globalMpool = mpoolInit(threads);
+    if (!globalMpool) return false;
 
     return true;
 }
@@ -603,4 +636,4 @@ SwRenderer* SwRenderer::gen()
 {
     ++rendererCnt;
     return new SwRenderer();
-}
+}
\ No newline at end of file
index ef8b558..c61984b 100644 (file)
@@ -27,6 +27,7 @@
 struct SwSurface;
 struct SwTask;
 struct SwCompositor;
+struct SwMpool;
 
 namespace tvg
 {
@@ -48,6 +49,7 @@ public:
     bool clear() override;
     bool sync() override;
     bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs);
+    bool mempool(bool shared);
 
     Compositor* target(const RenderRegion& region) override;
     bool beginComposite(Compositor* cmp, CompositeMethod method, uint32_t opacity) override;
@@ -61,9 +63,12 @@ private:
     SwSurface*           surface = nullptr;           //active surface
     Array<SwTask*>       tasks;                       //async task list
     Array<SwSurface*>    compositors;                 //render targets cache list
+    SwMpool*             mpool;                       //private memory pool
     RenderRegion         vport;                       //viewport
 
-    SwRenderer(){};
+    bool                 sharedMpool = true;          //memory-pool behavior policy
+
+    SwRenderer();
     ~SwRenderer();
 
     RenderData prepareCommon(SwTask* task, const RenderTransform* transform, uint32_t opacity, const Array<RenderData>& clips, RenderUpdateFlag flags);
index 7756e7d..4dcaa95 100644 (file)
@@ -249,7 +249,7 @@ static void _dashCubicTo(SwDashStroke& dash, const Point* ctrl1, const Point* ct
 }
 
 
-SwOutline* _genDashOutline(const Shape* sdata, const Matrix* transform)
+static SwOutline* _genDashOutline(const Shape* sdata, const Matrix* transform)
 {
     const PathCommand* cmds = nullptr;
     auto cmdCnt = sdata->pathCommands(&cmds);
@@ -344,7 +344,7 @@ SwOutline* _genDashOutline(const Shape* sdata, const Matrix* transform)
 }
 
 
-bool _fastTrack(const SwOutline* outline)
+static bool _fastTrack(const SwOutline* outline)
 {
     //Fast Track: Othogonal rectangle?
     if (outline->ptsCnt != 5) return false;
@@ -363,67 +363,8 @@ bool _fastTrack(const SwOutline* outline)
 }
 
 
-/************************************************************************/
-/* External Class Implementation                                        */
-/************************************************************************/
-
-bool shapePrepare(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform,  const SwBBox& clipRegion, SwBBox& renderRegion)
-{
-    if (!shapeGenOutline(shape, sdata, tid, transform)) return false;
-    if (!mathUpdateOutlineBBox(shape->outline, clipRegion, renderRegion)) return false;
-
-    //Keep it for Rasterization Region
-    shape->bbox = renderRegion;
-
-    //Check valid region
-    if (renderRegion.max.x - renderRegion.min.x < 1 && renderRegion.max.y - renderRegion.min.y < 1) return false;
-
-    //Check boundary
-    if (renderRegion.min.x >= clipRegion.max.x || renderRegion.min.y >= clipRegion.max.y ||
-        renderRegion.max.x <= clipRegion.min.x || renderRegion.max.y <= clipRegion.min.y) return false;
-
-    return true;
-}
-
-
-bool shapePrepared(const SwShape* shape)
-{
-    return shape->rle ? true : false;
-}
-
-
-bool shapeGenRle(SwShape* shape, TVG_UNUSED const Shape* sdata, bool antiAlias, bool hasComposite)
-{
-    //FIXME: Should we draw it?
-    //Case: Stroke Line
-    //if (shape.outline->opened) return true;
-
-    //Case A: Fast Track Rectangle Drawing
-    if (!hasComposite && (shape->rect = _fastTrack(shape->outline))) return true;
-    //Case B: Normale Shape RLE Drawing
-    if ((shape->rle = rleRender(shape->rle, shape->outline, shape->bbox, antiAlias))) return true;
-
-    return false;
-}
-
-
-void shapeDelOutline(SwShape* shape, uint32_t tid)
-{
-    mpoolRetOutline(tid);
-    shape->outline = nullptr;
-}
-
-
-void shapeReset(SwShape* shape)
-{
-    rleReset(shape->rle);
-    rleReset(shape->strokeRle);
-    shape->rect = false;
-    shape->bbox.reset();
-}
-
 
-bool shapeGenOutline(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform)
+static bool _genOutline(SwShape* shape, const Shape* sdata, const Matrix* transform, SwMpool* mpool, unsigned tid)
 {
     const PathCommand* cmds = nullptr;
     auto cmdCnt = sdata->pathCommands(&cmds);
@@ -463,7 +404,7 @@ bool shapeGenOutline(SwShape* shape, const Shape* sdata, unsigned tid, const Mat
     ++outlinePtsCnt;    //for close
     ++outlineCntrsCnt;  //for end
 
-    shape->outline = mpoolReqOutline(tid);
+    shape->outline = mpoolReqOutline(mpool, tid);
     auto outline = shape->outline;
     outline->opened = true;
 
@@ -510,6 +451,66 @@ bool shapeGenOutline(SwShape* shape, const Shape* sdata, unsigned tid, const Mat
 }
 
 
+/************************************************************************/
+/* External Class Implementation                                        */
+/************************************************************************/
+
+bool shapePrepare(SwShape* shape, const Shape* sdata, const Matrix* transform,  const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid)
+{
+    if (!_genOutline(shape, sdata, transform, mpool, tid)) return false;
+    if (!mathUpdateOutlineBBox(shape->outline, clipRegion, renderRegion)) return false;
+
+    //Keep it for Rasterization Region
+    shape->bbox = renderRegion;
+
+    //Check valid region
+    if (renderRegion.max.x - renderRegion.min.x < 1 && renderRegion.max.y - renderRegion.min.y < 1) return false;
+
+    //Check boundary
+    if (renderRegion.min.x >= clipRegion.max.x || renderRegion.min.y >= clipRegion.max.y ||
+        renderRegion.max.x <= clipRegion.min.x || renderRegion.max.y <= clipRegion.min.y) return false;
+
+    return true;
+}
+
+
+bool shapePrepared(const SwShape* shape)
+{
+    return shape->rle ? true : false;
+}
+
+
+bool shapeGenRle(SwShape* shape, TVG_UNUSED const Shape* sdata, bool antiAlias, bool hasComposite)
+{
+    //FIXME: Should we draw it?
+    //Case: Stroke Line
+    //if (shape.outline->opened) return true;
+
+    //Case A: Fast Track Rectangle Drawing
+    if (!hasComposite && (shape->rect = _fastTrack(shape->outline))) return true;
+    //Case B: Normale Shape RLE Drawing
+    if ((shape->rle = rleRender(shape->rle, shape->outline, shape->bbox, antiAlias))) return true;
+
+    return false;
+}
+
+
+void shapeDelOutline(SwShape* shape, SwMpool* mpool, uint32_t tid)
+{
+    mpoolRetOutline(mpool, tid);
+    shape->outline = nullptr;
+}
+
+
+void shapeReset(SwShape* shape)
+{
+    rleReset(shape->rle);
+    rleReset(shape->strokeRle);
+    shape->rect = false;
+    shape->bbox.reset();
+}
+
+
 void shapeFree(SwShape* shape)
 {
     rleFree(shape->rle);
@@ -543,7 +544,7 @@ void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transfor
 }
 
 
-bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion)
+bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid)
 {
     SwOutline* shapeOutline = nullptr;
     SwOutline* strokeOutline = nullptr;
@@ -558,7 +559,7 @@ bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const M
     //Normal Style stroke
     } else {
         if (!shape->outline) {
-            if (!shapeGenOutline(shape, sdata, tid, transform)) return false;
+            if (!_genOutline(shape, sdata, transform, mpool, tid)) return false;
         }
         shapeOutline = shape->outline;
     }
@@ -568,7 +569,7 @@ bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const M
         goto fail;
     }
 
-    strokeOutline = strokeExportOutline(shape->stroke, tid);
+    strokeOutline = strokeExportOutline(shape->stroke, mpool, tid);
     if (!strokeOutline) {
         ret = false;
         goto fail;
@@ -588,7 +589,7 @@ fail:
         if (shapeOutline->types) free(shapeOutline->types);
         free(shapeOutline);
     }
-    mpoolRetStrokeOutline(tid);
+    mpoolRetStrokeOutline(mpool, tid);
 
     return ret;
 }
index 354067f..046c17d 100644 (file)
@@ -907,7 +907,7 @@ bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline)
 }
 
 
-SwOutline* strokeExportOutline(SwStroke* stroke, unsigned tid)
+SwOutline* strokeExportOutline(SwStroke* stroke, SwMpool* mpool, unsigned tid)
 {
     uint32_t count1, count2, count3, count4;
 
@@ -917,7 +917,7 @@ SwOutline* strokeExportOutline(SwStroke* stroke, unsigned tid)
     auto ptsCnt = count1 + count3;
     auto cntrsCnt = count2 + count4;
 
-    auto outline = mpoolReqStrokeOutline(tid);
+    auto outline = mpoolReqStrokeOutline(mpool, tid);
     if (outline->reservedPtsCnt < ptsCnt) {
         outline->pts = static_cast<SwPoint*>(realloc(outline->pts, sizeof(SwPoint) * ptsCnt));
         outline->types = static_cast<uint8_t*>(realloc(outline->types, sizeof(uint8_t) * ptsCnt));
index 2718178..a0e06ca 100644 (file)
@@ -58,6 +58,25 @@ SwCanvas::~SwCanvas()
 }
 
 
+Result SwCanvas::mempool(MempoolPolicy policy) noexcept
+{
+#ifdef THORVG_SW_RASTER_SUPPORT
+    //We know renderer type, avoid dynamic_cast for performance.
+    auto renderer = static_cast<SwRenderer*>(Canvas::pImpl->renderer);
+    if (!renderer) return Result::MemoryCorruption;
+
+    //It can't change the policy during the running.
+    if (Canvas::pImpl->paints.count > 0) return Result::InsufficientCondition;
+
+    if (policy == MempoolPolicy::Individual) renderer->mempool(false);
+    else renderer->mempool(true);
+
+    return Result::Success;
+#endif
+    return Result::NonSupport;
+}
+
+
 Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, Colorspace cs) noexcept
 {
 #ifdef THORVG_SW_RASTER_SUPPORT