From: Hermet Park Date: Fri, 7 May 2021 10:45:07 +0000 (+0900) Subject: sw_engine: fix invalid data sharing at multi-threading. X-Git-Tag: accepted/tizen/unified/20210602.122549~30 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=7c8d026dd226f00151ee1062be6bf57efbaf08b5;p=platform%2Fcore%2Fgraphics%2Ftizenvg.git sw_engine: fix invalid data sharing at multi-threading. 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. --- diff --git a/inc/thorvg.h b/inc/thorvg.h index d391f6e..277c573 100644 --- a/inc/thorvg.h +++ b/inc/thorvg.h @@ -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 */ diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 47d7d6d..7966b6d 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -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); diff --git a/src/lib/sw_engine/tvgSwImage.cpp b/src/lib/sw_engine/tvgSwImage.cpp index 03bf174..48b1e6c 100644 --- a/src/lib/sw_engine/tvgSwImage.cpp +++ b/src/lib/sw_engine/tvgSwImage.cpp @@ -26,6 +26,44 @@ /* 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(realloc(outline->pts, outline->reservedPtsCnt * sizeof(SwPoint))); + outline->types = static_cast(realloc(outline->types, outline->reservedPtsCnt * sizeof(uint8_t))); + + outline->reservedCntrsCnt = 1; + outline->cntrs = static_cast(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(realloc(outline->pts, outline->reservedPtsCnt * sizeof(SwPoint))); - outline->types = static_cast(realloc(outline->types, outline->reservedPtsCnt * sizeof(uint8_t))); - - outline->reservedCntrsCnt = 1; - outline->cntrs = static_cast(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); diff --git a/src/lib/sw_engine/tvgSwMemPool.cpp b/src/lib/sw_engine/tvgSwMemPool.cpp index 6975d23..1b61fd2 100644 --- a/src/lib/sw_engine/tvgSwMemPool.cpp +++ b/src/lib/sw_engine/tvgSwMemPool.cpp @@ -26,77 +26,76 @@ /* 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(calloc(1, sizeof(SwOutline) * threads)); - if (!outline) goto err; + mpool->outline = static_cast(calloc(1, sizeof(SwOutline) * threads)); + if (!mpool->outline) goto err; - strokeOutline = static_cast(calloc(1, sizeof(SwOutline) * threads)); - if (!strokeOutline) goto err; + mpool->strokeOutline = static_cast(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 diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index ca4a1f0..34428df 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -29,12 +29,14 @@ /************************************************************************/ 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 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(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(0), static_cast(vport.x)); task->bbox.min.y = max(static_cast(0), static_cast(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 diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index ef8b558..c61984b 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -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 tasks; //async task list Array 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& clips, RenderUpdateFlag flags); diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index 7756e7d..4dcaa95 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -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; } diff --git a/src/lib/sw_engine/tvgSwStroke.cpp b/src/lib/sw_engine/tvgSwStroke.cpp index 354067f..046c17d 100644 --- a/src/lib/sw_engine/tvgSwStroke.cpp +++ b/src/lib/sw_engine/tvgSwStroke.cpp @@ -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(realloc(outline->pts, sizeof(SwPoint) * ptsCnt)); outline->types = static_cast(realloc(outline->types, sizeof(uint8_t) * ptsCnt)); diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index 2718178..a0e06ca 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -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(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