mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-13 19:44:28 +00:00
sw_engine shape: performance optimization.
we introduced shared memory pool for avoiding reallocate memory while it process the stroke outlines, It experimentally increase the outline data if we use the allocated memory for multiples shape strokes, we don't need to alloc/free memory during the process. This shared outline memory is allocated for threads count so that we don't interrupt memory access during the tasks. @Issues: 75
This commit is contained in:
parent
fbe5b87106
commit
1b8188ee67
13 changed files with 136 additions and 40 deletions
|
@ -180,7 +180,7 @@ void* GlRenderer::prepare(const Shape& shape, void* data, TVG_UNUSED const Rende
|
|||
}
|
||||
|
||||
|
||||
int GlRenderer::init()
|
||||
int GlRenderer::init(uint32_t threads)
|
||||
{
|
||||
if (rendererCnt > 0) return false;
|
||||
if (initEngine) return true;
|
||||
|
|
|
@ -40,7 +40,7 @@ public:
|
|||
bool clear() override;
|
||||
|
||||
static GlRenderer* gen();
|
||||
static int init();
|
||||
static int init(TVG_UNUSED uint32_t threads);
|
||||
static int term();
|
||||
|
||||
private:
|
||||
|
|
|
@ -5,6 +5,7 @@ source_file = [
|
|||
'tvgSwRenderer.h',
|
||||
'tvgSwRaster.cpp',
|
||||
'tvgSwRenderer.cpp',
|
||||
'tvgSwResMgr.cpp',
|
||||
'tvgSwRle.cpp',
|
||||
'tvgSwShape.cpp',
|
||||
'tvgSwStroke.cpp',
|
||||
|
|
|
@ -266,13 +266,13 @@ bool mathSmallCubic(SwPoint* base, SwFixed& angleIn, SwFixed& angleMid, SwFixed&
|
|||
SwFixed mathMean(SwFixed angle1, SwFixed angle2);
|
||||
|
||||
void shapeReset(SwShape* shape);
|
||||
bool shapeGenOutline(SwShape* shape, const Shape* sdata, const Matrix* transform);
|
||||
bool shapePrepare(SwShape* shape, const Shape* sdata, const SwSize& clip, const Matrix* transform);
|
||||
bool shapeGenOutline(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform);
|
||||
bool shapePrepare(SwShape* shape, const Shape* sdata, unsigned tid, const SwSize& clip, const Matrix* transform);
|
||||
bool shapePrepared(SwShape* shape);
|
||||
bool shapeGenRle(SwShape* shape, const Shape* sdata, const SwSize& clip, bool antiAlias, bool hasComposite);
|
||||
void shapeDelOutline(SwShape* shape);
|
||||
void shapeDelOutline(SwShape* shape, uint32_t tid);
|
||||
void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transform);
|
||||
bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwSize& clip);
|
||||
bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwSize& clip);
|
||||
void shapeFree(SwShape* shape);
|
||||
void shapeDelStroke(SwShape* shape);
|
||||
bool shapeGenFillColors(SwShape* shape, const Fill* fill, const Matrix* transform, SwSurface* surface, bool ctable);
|
||||
|
@ -295,6 +295,11 @@ void rleFree(SwRleData* rle);
|
|||
void rleClipPath(SwRleData *rle, const SwRleData *clip);
|
||||
void rleClipRect(SwRleData *rle, const SwBBox* clip);
|
||||
|
||||
bool resMgrInit(uint32_t threads);
|
||||
bool resMgrTerm();
|
||||
bool resMgrClear();
|
||||
SwOutline* resMgrRequestOutline(unsigned idx);
|
||||
void resMgrRetrieveOutline(unsigned idx);
|
||||
|
||||
bool rasterCompositor(SwSurface* surface);
|
||||
bool rasterGradientShape(SwSurface* surface, SwShape* shape, unsigned id);
|
||||
|
@ -302,7 +307,6 @@ bool rasterSolidShape(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g,
|
|||
bool rasterStroke(SwSurface* surface, SwShape* shape, uint8_t r, uint8_t g, uint8_t b, uint8_t a);
|
||||
bool rasterClear(SwSurface* surface);
|
||||
|
||||
|
||||
static inline void rasterRGBA32(uint32_t *dst, uint32_t val, uint32_t offset, int32_t len)
|
||||
{
|
||||
#ifdef THORVG_AVX_VECTOR_SUPPORT
|
||||
|
|
|
@ -39,7 +39,7 @@ struct SwTask : Task
|
|||
vector<Composite> compList;
|
||||
uint32_t opacity;
|
||||
|
||||
void run() override
|
||||
void run(unsigned tid) override
|
||||
{
|
||||
if (opacity == 0) return; //Invisible
|
||||
|
||||
|
@ -64,13 +64,13 @@ struct SwTask : Task
|
|||
bool renderShape = (alpha > 0 || sdata->fill());
|
||||
if (renderShape || strokeAlpha) {
|
||||
shapeReset(&shape);
|
||||
if (!shapePrepare(&shape, sdata, clip, transform)) return;
|
||||
if (!shapePrepare(&shape, sdata, tid, clip, transform)) goto end;
|
||||
if (renderShape) {
|
||||
/* We assume that if stroke width is bigger than 2,
|
||||
shape outline below stroke could be full covered by stroke drawing.
|
||||
Thus it turns off antialising in that condition. */
|
||||
auto antiAlias = (strokeAlpha > 0 && strokeWidth > 2) ? false : true;
|
||||
if (!shapeGenRle(&shape, sdata, clip, antiAlias, compList.size() > 0 ? true : false)) return;
|
||||
if (!shapeGenRle(&shape, sdata, clip, antiAlias, compList.size() > 0 ? true : false)) goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ struct SwTask : Task
|
|||
if (fill) {
|
||||
auto ctable = (flags & RenderUpdateFlag::Gradient) ? true : false;
|
||||
if (ctable) shapeResetFill(&shape);
|
||||
if (!shapeGenFillColors(&shape, fill, transform, surface, ctable)) return;
|
||||
if (!shapeGenFillColors(&shape, fill, transform, surface, ctable)) goto end;
|
||||
} else {
|
||||
shapeDelFill(&shape);
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ struct SwTask : Task
|
|||
if (flags & (RenderUpdateFlag::Stroke | RenderUpdateFlag::Transform)) {
|
||||
if (strokeAlpha > 0) {
|
||||
shapeResetStroke(&shape, sdata, transform);
|
||||
if (!shapeGenStrokeRle(&shape, sdata, transform, clip)) return;
|
||||
if (!shapeGenStrokeRle(&shape, sdata, tid, transform, clip)) goto end;
|
||||
} else {
|
||||
shapeDelStroke(&shape);
|
||||
}
|
||||
|
@ -109,7 +109,8 @@ struct SwTask : Task
|
|||
else if (shape.strokeRle && compShape->rle) rleClipPath(shape.strokeRle, compShape->rle);
|
||||
}
|
||||
}
|
||||
shapeDelOutline(&shape);
|
||||
end:
|
||||
shapeDelOutline(&shape, tid);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -117,7 +118,7 @@ static void _termEngine()
|
|||
{
|
||||
if (rendererCnt > 0) return;
|
||||
|
||||
//TODO: Clean up global resources
|
||||
resMgrTerm();
|
||||
}
|
||||
|
||||
|
||||
|
@ -141,7 +142,7 @@ bool SwRenderer::clear()
|
|||
for (auto task : tasks) task->get();
|
||||
tasks.clear();
|
||||
|
||||
return true;
|
||||
return resMgrClear();
|
||||
}
|
||||
|
||||
|
||||
|
@ -173,7 +174,6 @@ bool SwRenderer::preRender()
|
|||
bool SwRenderer::postRender()
|
||||
{
|
||||
tasks.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -255,12 +255,12 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform*
|
|||
}
|
||||
|
||||
|
||||
bool SwRenderer::init()
|
||||
bool SwRenderer::init(uint32_t threads)
|
||||
{
|
||||
if (rendererCnt > 0) return false;
|
||||
if (initEngine) return true;
|
||||
|
||||
//TODO:
|
||||
if (!resMgrInit(threads)) return false;
|
||||
|
||||
initEngine = true;
|
||||
|
||||
|
@ -283,4 +283,4 @@ SwRenderer* SwRenderer::gen()
|
|||
{
|
||||
++rendererCnt;
|
||||
return new SwRenderer();
|
||||
}
|
||||
}
|
|
@ -43,7 +43,7 @@ public:
|
|||
bool render(const Shape& shape, void *data) override;
|
||||
|
||||
static SwRenderer* gen();
|
||||
static bool init();
|
||||
static bool init(uint32_t threads);
|
||||
static bool term();
|
||||
|
||||
private:
|
||||
|
|
94
src/lib/sw_engine/tvgSwResMgr.cpp
Normal file
94
src/lib/sw_engine/tvgSwResMgr.cpp
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright (c) 2020 Samsung Electronics Co., Ltd. All rights reserved.
|
||||
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
#include <vector>
|
||||
#include "tvgSwCommon.h"
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* Internal Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
static unsigned threadsCnt = 1;
|
||||
static vector<SwOutline> sharedOutline;
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
SwOutline* resMgrRequestOutline(unsigned idx)
|
||||
{
|
||||
return &sharedOutline[idx];
|
||||
}
|
||||
|
||||
|
||||
void resMgrRetrieveOutline(unsigned idx)
|
||||
{
|
||||
sharedOutline[idx].cntrsCnt = 0;
|
||||
sharedOutline[idx].ptsCnt = 0;
|
||||
}
|
||||
|
||||
|
||||
bool resMgrInit(unsigned threads)
|
||||
{
|
||||
sharedOutline.reserve(threads);
|
||||
sharedOutline.resize(threads);
|
||||
threadsCnt = threads;
|
||||
|
||||
for (auto& outline : sharedOutline) {
|
||||
outline.cntrs = nullptr;
|
||||
outline.pts = nullptr;
|
||||
outline.types = nullptr;
|
||||
outline.cntrsCnt = outline.reservedCntrsCnt = 0;
|
||||
outline.ptsCnt = outline.reservedPtsCnt = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool resMgrClear()
|
||||
{
|
||||
for (auto& outline : sharedOutline) {
|
||||
if (outline.cntrs) {
|
||||
free(outline.cntrs);
|
||||
outline.cntrs = nullptr;
|
||||
}
|
||||
if (outline.pts) {
|
||||
free(outline.pts);
|
||||
outline.pts = nullptr;
|
||||
}
|
||||
if (outline.types) {
|
||||
free(outline.types);
|
||||
outline.types = nullptr;
|
||||
}
|
||||
outline.cntrsCnt = outline.reservedCntrsCnt = 0;
|
||||
outline.ptsCnt = outline.reservedPtsCnt = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool resMgrTerm()
|
||||
{
|
||||
return resMgrClear();
|
||||
}
|
|
@ -443,9 +443,9 @@ bool _fastTrack(const SwOutline* outline)
|
|||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
bool shapePrepare(SwShape* shape, const Shape* sdata, const SwSize& clip, const Matrix* transform)
|
||||
bool shapePrepare(SwShape* shape, const Shape* sdata, unsigned tid, const SwSize& clip, const Matrix* transform)
|
||||
{
|
||||
if (!shapeGenOutline(shape, sdata, transform)) return false;
|
||||
if (!shapeGenOutline(shape, sdata, tid, transform)) return false;
|
||||
|
||||
if (!_updateBBox(shape->outline, shape->bbox)) return false;
|
||||
|
||||
|
@ -476,17 +476,15 @@ bool shapeGenRle(SwShape* shape, TVG_UNUSED const Shape* sdata, const SwSize& cl
|
|||
}
|
||||
|
||||
|
||||
void shapeDelOutline(SwShape* shape)
|
||||
void shapeDelOutline(SwShape* shape, uint32_t tid)
|
||||
{
|
||||
auto outline = shape->outline;
|
||||
_delOutline(outline);
|
||||
resMgrRetrieveOutline(tid);
|
||||
shape->outline = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void shapeReset(SwShape* shape)
|
||||
{
|
||||
shapeDelOutline(shape);
|
||||
rleFree(shape->rle);
|
||||
shape->rle = nullptr;
|
||||
shape->rect = false;
|
||||
|
@ -494,7 +492,7 @@ void shapeReset(SwShape* shape)
|
|||
}
|
||||
|
||||
|
||||
bool shapeGenOutline(SwShape* shape, const Shape* sdata, const Matrix* transform)
|
||||
bool shapeGenOutline(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform)
|
||||
{
|
||||
const PathCommand* cmds = nullptr;
|
||||
auto cmdCnt = sdata->pathCommands(&cmds);
|
||||
|
@ -534,8 +532,8 @@ bool shapeGenOutline(SwShape* shape, const Shape* sdata, const Matrix* transform
|
|||
++outlinePtsCnt; //for close
|
||||
++outlineCntrsCnt; //for end
|
||||
|
||||
shape->outline = resMgrRequestOutline(tid);
|
||||
auto outline = shape->outline;
|
||||
if (!outline) outline = static_cast<SwOutline*>(calloc(1, sizeof(SwOutline)));
|
||||
outline->opened = true;
|
||||
|
||||
_growOutlinePoint(*outline, outlinePtsCnt);
|
||||
|
@ -583,7 +581,6 @@ bool shapeGenOutline(SwShape* shape, const Shape* sdata, const Matrix* transform
|
|||
|
||||
void shapeFree(SwShape* shape)
|
||||
{
|
||||
shapeDelOutline(shape);
|
||||
rleFree(shape->rle);
|
||||
shapeDelFill(shape);
|
||||
|
||||
|
@ -617,7 +614,7 @@ void shapeResetStroke(SwShape* shape, const Shape* sdata, const Matrix* transfor
|
|||
}
|
||||
|
||||
|
||||
bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transform, const SwSize& clip)
|
||||
bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, unsigned tid, const Matrix* transform, const SwSize& clip)
|
||||
{
|
||||
SwOutline* shapeOutline = nullptr;
|
||||
SwOutline* strokeOutline = nullptr;
|
||||
|
@ -632,7 +629,7 @@ bool shapeGenStrokeRle(SwShape* shape, const Shape* sdata, const Matrix* transfo
|
|||
//Normal Style stroke
|
||||
} else {
|
||||
if (!shape->outline) {
|
||||
if (!shapeGenOutline(shape, sdata, transform)) return false;
|
||||
if (!shapeGenOutline(shape, sdata, tid, transform)) return false;
|
||||
}
|
||||
shapeOutline = shape->outline;
|
||||
}
|
||||
|
|
|
@ -49,12 +49,12 @@ Result Initializer::init(CanvasEngine engine, uint32_t threads) noexcept
|
|||
|
||||
if (static_cast<uint32_t>(engine) & static_cast<uint32_t>(CanvasEngine::Sw)) {
|
||||
#ifdef THORVG_SW_RASTER_SUPPORT
|
||||
if (!SwRenderer::init()) return Result::InsufficientCondition;
|
||||
if (!SwRenderer::init(threads)) return Result::InsufficientCondition;
|
||||
nonSupport = false;
|
||||
#endif
|
||||
} else if (static_cast<uint32_t>(engine) & static_cast<uint32_t>(CanvasEngine::Gl)) {
|
||||
#ifdef THORVG_GL_RASTER_SUPPORT
|
||||
if (!GlRenderer::init()) return Result::InsufficientCondition;
|
||||
if (!GlRenderer::init(threads)) return Result::InsufficientCondition;
|
||||
nonSupport = false;
|
||||
#endif
|
||||
} else {
|
||||
|
|
|
@ -133,7 +133,7 @@ public:
|
|||
}
|
||||
|
||||
if (!success && !taskQueues[i].pop(&task)) break;
|
||||
(*task)();
|
||||
(*task)(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -149,7 +149,7 @@ public:
|
|||
taskQueues[i % threadCnt].push(task);
|
||||
//Sync
|
||||
} else {
|
||||
task->run();
|
||||
task->run(0);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -50,12 +50,12 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
virtual void run() = 0;
|
||||
virtual void run(unsigned tid) = 0;
|
||||
|
||||
private:
|
||||
void operator()()
|
||||
void operator()(unsigned tid)
|
||||
{
|
||||
run();
|
||||
run(tid);
|
||||
sender.set_value();
|
||||
}
|
||||
|
||||
|
|
|
@ -2431,7 +2431,7 @@ SvgLoader::~SvgLoader()
|
|||
}
|
||||
|
||||
|
||||
void SvgLoader::run()
|
||||
void SvgLoader::run(unsigned tid)
|
||||
{
|
||||
if (!simpleXmlParse(content, size, true, _svgLoaderParser, &(loaderData))) return;
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ public:
|
|||
bool header();
|
||||
bool read() override;
|
||||
bool close() override;
|
||||
void run() override;
|
||||
void run(unsigned tid) override;
|
||||
|
||||
unique_ptr<Scene> data() override;
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue