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.
This commit is contained in:
Hermet Park 2021-05-07 19:45:07 +09:00 committed by Hermet Park
parent f676d6a25c
commit 6dd414ee3b
9 changed files with 280 additions and 180 deletions

View file

@ -1114,6 +1114,18 @@ public:
ARGB8888 ///< The channels are joined in the order: alpha, red, green, blue.
};
/**
* @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.
*
@ -1134,6 +1146,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

View 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);

View file

@ -26,55 +26,13 @@
/* Internal Class Implementation */
/************************************************************************/
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
bool imagePrepare(SwImage* image, const Picture* pdata, unsigned tid, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion)
{
if (!imageGenOutline(image, pdata, tid, transform)) return false;
return mathUpdateOutlineBBox(image->outline, clipRegion, renderRegion);
}
bool imagePrepared(const SwImage* image)
{
return image->rle ? true : false;
}
bool imageGenRle(SwImage* image, TVG_UNUSED const Picture* pdata, const SwBBox& renderRegion, bool antiAlias)
{
if ((image->rle = rleRender(image->rle, image->outline, renderRegion, antiAlias))) return true;
return false;
}
void imageDelOutline(SwImage* image, uint32_t tid)
{
mpoolRetOutline(tid);
image->outline = nullptr;
}
void imageReset(SwImage* image)
{
rleReset(image->rle);
image->rle = nullptr;
}
bool imageGenOutline(SwImage* image, const Picture* pdata, unsigned tid, const Matrix* transform)
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(tid);
image->outline = mpoolReqOutline(mpool, tid);
auto outline = image->outline;
outline->reservedPtsCnt = 5;
@ -107,6 +65,47 @@ bool imageGenOutline(SwImage* image, const Picture* pdata, unsigned tid, const M
return true;
}
/************************************************************************/
/* External Class Implementation */
/************************************************************************/
bool imagePrepare(SwImage* image, const Picture* pdata, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid)
{
if (!_genOutline(image, pdata, transform, mpool, tid)) return false;
return mathUpdateOutlineBBox(image->outline, clipRegion, renderRegion);
}
bool imagePrepared(const SwImage* image)
{
return image->rle ? true : false;
}
bool imageGenRle(SwImage* image, TVG_UNUSED const Picture* pdata, const SwBBox& renderRegion, bool antiAlias)
{
if ((image->rle = rleRender(image->rle, image->outline, renderRegion, antiAlias))) return true;
return false;
}
void imageDelOutline(SwImage* image, SwMpool* mpool, uint32_t tid)
{
mpoolRetOutline(mpool, tid);
image->outline = nullptr;
}
void imageReset(SwImage* image)
{
rleReset(image->rle);
image->rle = nullptr;
}
void imageFree(SwImage* image)
{
rleFree(image->rle);

View file

@ -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<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;
if (outline) {
free(outline);
outline = nullptr;
mpoolClear(mpool);
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;
}

View file

@ -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<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;
}

View 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);

View 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;
}

View 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));

View 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