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. 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. * @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; 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. * @brief Creates a new SwCanvas object.
* @return A new SwCanvas object when succeed, otherwise @c nullptr * @return A new SwCanvas object when succeed, otherwise @c nullptr

View file

@ -254,6 +254,13 @@ struct SwCompositor : Compositor
bool valid; bool valid;
}; };
struct SwMpool
{
SwOutline* outline = nullptr;
SwOutline* strokeOutline = nullptr;
unsigned allocSize = 0;
};
static inline SwCoord TO_SWCOORD(float val) static inline SwCoord TO_SWCOORD(float val)
{ {
return SwCoord(val * 64); 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); bool mathUpdateOutlineBBox(const SwOutline* outline, const SwBBox& clipRegion, SwBBox& renderRegion);
void shapeReset(SwShape* shape); void shapeReset(SwShape* shape);
bool shapeGenOutline(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform); bool shapePrepare(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion, SwMpool* mpool, unsigned tid);
bool shapePrepare(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwBBox& clipRegion, SwBBox& renderRegion);
bool shapePrepared(const SwShape* shape); bool shapePrepared(const SwShape* shape);
bool shapeGenRle(SwShape* shape, const Shape* sdata, bool antiAlias, bool hasComposite); 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); 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 shapeFree(SwShape* shape);
void shapeDelStroke(SwShape* shape); void shapeDelStroke(SwShape* shape);
bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, uint32_t opacity, bool ctable); 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); void strokeReset(SwStroke* stroke, const Shape* shape, const Matrix* transform);
bool strokeParseOutline(SwStroke* stroke, const SwOutline& outline); 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); 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 imagePrepared(const SwImage* image);
bool imageGenRle(SwImage* image, TVG_UNUSED const Picture* pdata, const SwBBox& renderRegion, bool antiAlias); 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); void imageReset(SwImage* image);
bool imageGenOutline(SwImage* image, const Picture* pdata, unsigned tid, const Matrix* transform);
void imageFree(SwImage* image); void imageFree(SwImage* image);
bool fillGenColorTable(SwFill* fill, const Fill* fdata, const Matrix* transform, SwSurface* surface, uint32_t opacity, bool ctable); 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 rleClipRect(SwRleData *rle, const SwBBox* clip);
void rleAlphaMask(SwRleData *rle, const SwRleData *clip); void rleAlphaMask(SwRleData *rle, const SwRleData *clip);
bool mpoolInit(uint32_t threads); SwMpool* mpoolInit(uint32_t threads);
bool mpoolTerm(); bool mpoolTerm(SwMpool* mpool);
bool mpoolClear(); bool mpoolClear(SwMpool* mpool);
SwOutline* mpoolReqOutline(unsigned idx); SwOutline* mpoolReqOutline(SwMpool* mpool, unsigned idx);
void mpoolRetOutline(unsigned idx); void mpoolRetOutline(SwMpool* mpool, unsigned idx);
SwOutline* mpoolReqStrokeOutline(unsigned idx); SwOutline* mpoolReqStrokeOutline(SwMpool* mpool, unsigned idx);
void mpoolRetStrokeOutline(unsigned idx); void mpoolRetStrokeOutline(SwMpool* mpool, unsigned idx);
bool rasterCompositor(SwSurface* surface); bool rasterCompositor(SwSurface* surface);
bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id); bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id);

View file

@ -26,55 +26,13 @@
/* Internal Class Implementation */ /* Internal Class Implementation */
/************************************************************************/ /************************************************************************/
static bool _genOutline(SwImage* image, const Picture* pdata, const Matrix* transform, SwMpool* mpool, unsigned tid)
/************************************************************************/
/* 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)
{ {
float w, h; float w, h;
pdata->viewbox(nullptr, nullptr, &w, &h); pdata->viewbox(nullptr, nullptr, &w, &h);
if (w == 0 || h == 0) return false; if (w == 0 || h == 0) return false;
image->outline = mpoolReqOutline(tid); image->outline = mpoolReqOutline(mpool, tid);
auto outline = image->outline; auto outline = image->outline;
outline->reservedPtsCnt = 5; outline->reservedPtsCnt = 5;
@ -107,6 +65,47 @@ bool imageGenOutline(SwImage* image, const Picture* pdata, unsigned tid, const M
return true; 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) void imageFree(SwImage* image)
{ {
rleFree(image->rle); rleFree(image->rle);

View file

@ -26,77 +26,76 @@
/* Internal Class Implementation */ /* Internal Class Implementation */
/************************************************************************/ /************************************************************************/
static SwOutline* outline = nullptr;
static SwOutline* strokeOutline = nullptr;
static unsigned allocSize = 0;
/************************************************************************/ /************************************************************************/
/* External Class Implementation */ /* 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; mpool->outline[idx].cntrsCnt = 0;
outline[idx].ptsCnt = 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; mpool->strokeOutline[idx].cntrsCnt = 0;
strokeOutline[idx].ptsCnt = 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; if (threads == 0) threads = 1;
outline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline) * threads)); mpool->outline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline) * threads));
if (!outline) goto err; if (!mpool->outline) goto err;
strokeOutline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline) * threads)); mpool->strokeOutline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline) * threads));
if (!strokeOutline) goto err; if (!mpool->strokeOutline) goto err;
allocSize = threads; mpool->allocSize = threads;
return true; return mpool;
err: err:
if (outline) { if (mpool->outline) {
free(outline); free(mpool->outline);
outline = nullptr; mpool->outline = nullptr;
} }
if (strokeOutline) { if (mpool->strokeOutline) {
free(strokeOutline); free(mpool->strokeOutline);
strokeOutline = nullptr; mpool->strokeOutline = nullptr;
} }
return false; delete(mpool);
return nullptr;
} }
bool mpoolClear() bool mpoolClear(SwMpool* mpool)
{ {
SwOutline* p; 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) { if (p->cntrs) {
free(p->cntrs); free(p->cntrs);
@ -113,7 +112,7 @@ bool mpoolClear()
p->cntrsCnt = p->reservedCntrsCnt = 0; p->cntrsCnt = p->reservedCntrsCnt = 0;
p->ptsCnt = p->reservedPtsCnt = 0; p->ptsCnt = p->reservedPtsCnt = 0;
p = &strokeOutline[i]; p = &mpool->strokeOutline[i];
if (p->cntrs) { if (p->cntrs) {
free(p->cntrs); free(p->cntrs);
@ -135,21 +134,23 @@ bool mpoolClear()
} }
bool mpoolTerm() bool mpoolTerm(SwMpool* mpool)
{ {
mpoolClear(); if (!mpool) return false;
if (outline) { mpoolClear(mpool);
free(outline);
outline = nullptr; if (mpool->outline) {
free(mpool->outline);
mpool->outline = nullptr;
} }
if (strokeOutline) { if (mpool->strokeOutline) {
free(strokeOutline); free(mpool->strokeOutline);
strokeOutline = nullptr; mpool->strokeOutline = nullptr;
} }
allocSize = 0; delete(mpool);
return true; return true;
} }

View file

@ -29,12 +29,14 @@
/************************************************************************/ /************************************************************************/
static int32_t initEngineCnt = false; static int32_t initEngineCnt = false;
static int32_t rendererCnt = 0; static int32_t rendererCnt = 0;
static SwMpool* globalMpool = nullptr;
static uint32_t threadsCnt = 0;
struct SwTask : Task struct SwTask : Task
{ {
Matrix* transform = nullptr; Matrix* transform = nullptr;
SwSurface* surface = nullptr; SwSurface* surface = nullptr;
SwMpool* mpool = nullptr;
RenderUpdateFlag flags = RenderUpdateFlag::None; RenderUpdateFlag flags = RenderUpdateFlag::None;
Array<RenderData> clips; Array<RenderData> clips;
uint32_t opacity; uint32_t opacity;
@ -92,7 +94,7 @@ struct SwShapeTask : SwTask
bool renderShape = (alpha > 0 || sdata->fill()); bool renderShape = (alpha > 0 || sdata->fill());
if (renderShape || validStroke) { if (renderShape || validStroke) {
shapeReset(&shape); 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) { if (renderShape) {
/* We assume that if stroke width is bigger than 2, /* We assume that if stroke width is bigger than 2,
shape outline below stroke could be full covered by stroke drawing. 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 (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) {
if (validStroke) { if (validStroke) {
shapeResetStroke(&shape, sdata, transform); 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; ++addStroking;
if (auto fill = sdata->strokeFill()) { if (auto fill = sdata->strokeFill()) {
@ -155,7 +157,7 @@ struct SwShapeTask : SwTask
err: err:
shapeReset(&shape); shapeReset(&shape);
end: end:
shapeDelOutline(&shape, tid); shapeDelOutline(&shape, mpool, tid);
if (addStroking > 1 && opacity < 255) cmpStroking = true; if (addStroking > 1 && opacity < 255) cmpStroking = true;
else cmpStroking = false; else cmpStroking = false;
} }
@ -183,7 +185,7 @@ struct SwImageTask : SwTask
if (prepareImage) { if (prepareImage) {
imageReset(&image); 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? //Clip Path?
if (clips.count > 0) { if (clips.count > 0) {
@ -199,7 +201,7 @@ struct SwImageTask : SwTask
} }
image.data = const_cast<uint32_t*>(pdata->data()); image.data = const_cast<uint32_t*>(pdata->data());
end: end:
imageDelOutline(&image, tid); imageDelOutline(&image, mpool, tid);
} }
bool dispose() override bool dispose() override
@ -214,7 +216,8 @@ static void _termEngine()
{ {
if (rendererCnt > 0) return; if (rendererCnt > 0) return;
mpoolTerm(); mpoolTerm(globalMpool);
globalMpool = nullptr;
} }
@ -228,6 +231,8 @@ SwRenderer::~SwRenderer()
if (surface) delete(surface); if (surface) delete(surface);
if (!sharedMpool) mpoolTerm(mpool);
--rendererCnt; --rendererCnt;
if (rendererCnt == 0 && initEngineCnt == 0) _termEngine(); 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) Compositor* SwRenderer::target(const RenderRegion& region)
{ {
auto x = region.x; auto x = region.x;
@ -539,6 +562,7 @@ void* SwRenderer::prepareCommon(SwTask* task, const RenderTransform* transform,
task->opacity = opacity; task->opacity = opacity;
task->surface = surface; task->surface = surface;
task->mpool = mpool;
task->flags = flags; task->flags = flags;
task->bbox.min.x = max(static_cast<SwCoord>(0), static_cast<SwCoord>(vport.x)); 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)); 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) bool SwRenderer::init(uint32_t threads)
{ {
if ((initEngineCnt++) > 0) return true; 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; return true;
} }

View file

@ -27,6 +27,7 @@
struct SwSurface; struct SwSurface;
struct SwTask; struct SwTask;
struct SwCompositor; struct SwCompositor;
struct SwMpool;
namespace tvg namespace tvg
{ {
@ -48,6 +49,7 @@ public:
bool clear() override; bool clear() override;
bool sync() override; bool sync() override;
bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, uint32_t cs); 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; Compositor* target(const RenderRegion& region) override;
bool beginComposite(Compositor* cmp, CompositeMethod method, uint32_t opacity) override; bool beginComposite(Compositor* cmp, CompositeMethod method, uint32_t opacity) override;
@ -61,9 +63,12 @@ private:
SwSurface* surface = nullptr; //active surface SwSurface* surface = nullptr; //active surface
Array<SwTask*> tasks; //async task list Array<SwTask*> tasks; //async task list
Array<SwSurface*> compositors; //render targets cache list Array<SwSurface*> compositors; //render targets cache list
SwMpool* mpool; //private memory pool
RenderRegion vport; //viewport RenderRegion vport; //viewport
SwRenderer(){}; bool sharedMpool = true; //memory-pool behavior policy
SwRenderer();
~SwRenderer(); ~SwRenderer();
RenderData prepareCommon(SwTask* task, const RenderTransform* transform, uint32_t opacity, const Array<RenderData>& clips, RenderUpdateFlag flags); 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; const PathCommand* cmds = nullptr;
auto cmdCnt = sdata->pathCommands(&cmds); 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? //Fast Track: Othogonal rectangle?
if (outline->ptsCnt != 5) return false; 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) static bool _genOutline(SwShape* shape, const Shape* sdata, const Matrix* transform, SwMpool* mpool, unsigned tid)
{
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)
{ {
const PathCommand* cmds = nullptr; const PathCommand* cmds = nullptr;
auto cmdCnt = sdata->pathCommands(&cmds); auto cmdCnt = sdata->pathCommands(&cmds);
@ -463,7 +404,7 @@ bool shapeGenOutline(SwShape* shape, const Shape* sdata, unsigned tid, const Mat
++outlinePtsCnt; //for close ++outlinePtsCnt; //for close
++outlineCntrsCnt; //for end ++outlineCntrsCnt; //for end
shape->outline = mpoolReqOutline(tid); shape->outline = mpoolReqOutline(mpool, tid);
auto outline = shape->outline; auto outline = shape->outline;
outline->opened = true; 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) void shapeFree(SwShape* shape)
{ {
rleFree(shape->rle); 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* shapeOutline = nullptr;
SwOutline* strokeOutline = nullptr; SwOutline* strokeOutline = nullptr;
@ -558,7 +559,7 @@ bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const M
//Normal Style stroke //Normal Style stroke
} else { } else {
if (!shape->outline) { if (!shape->outline) {
if (!shapeGenOutline(shape, sdata, tid, transform)) return false; if (!_genOutline(shape, sdata, transform, mpool, tid)) return false;
} }
shapeOutline = shape->outline; shapeOutline = shape->outline;
} }
@ -568,7 +569,7 @@ bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const M
goto fail; goto fail;
} }
strokeOutline = strokeExportOutline(shape->stroke, tid); strokeOutline = strokeExportOutline(shape->stroke, mpool, tid);
if (!strokeOutline) { if (!strokeOutline) {
ret = false; ret = false;
goto fail; goto fail;
@ -588,7 +589,7 @@ fail:
if (shapeOutline->types) free(shapeOutline->types); if (shapeOutline->types) free(shapeOutline->types);
free(shapeOutline); free(shapeOutline);
} }
mpoolRetStrokeOutline(tid); mpoolRetStrokeOutline(mpool, tid);
return ret; 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; uint32_t count1, count2, count3, count4;
@ -917,7 +917,7 @@ SwOutline* strokeExportOutline(SwStroke* stroke, unsigned tid)
auto ptsCnt = count1 + count3; auto ptsCnt = count1 + count3;
auto cntrsCnt = count2 + count4; auto cntrsCnt = count2 + count4;
auto outline = mpoolReqStrokeOutline(tid); auto outline = mpoolReqStrokeOutline(mpool, tid);
if (outline->reservedPtsCnt < ptsCnt) { if (outline->reservedPtsCnt < ptsCnt) {
outline->pts = static_cast<SwPoint*>(realloc(outline->pts, sizeof(SwPoint) * 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)); 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 Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h, Colorspace cs) noexcept
{ {
#ifdef THORVG_SW_RASTER_SUPPORT #ifdef THORVG_SW_RASTER_SUPPORT