mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 05:33:36 +00:00
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:
parent
f676d6a25c
commit
6dd414ee3b
9 changed files with 280 additions and 180 deletions
37
inc/thorvg.h
37
inc/thorvg.h
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Reference in a new issue