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:
Hermet Park 2020-11-04 16:28:47 +09:00 committed by GitHub
parent fbe5b87106
commit 1b8188ee67
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 136 additions and 40 deletions

View file

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

View file

@ -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:

View file

@ -5,6 +5,7 @@ source_file = [
'tvgSwRenderer.h',
'tvgSwRaster.cpp',
'tvgSwRenderer.cpp',
'tvgSwResMgr.cpp',
'tvgSwRle.cpp',
'tvgSwShape.cpp',
'tvgSwStroke.cpp',

View file

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

View file

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

View file

@ -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:

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

View file

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

View file

@ -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 {

View file

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

View file

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

View file

@ -2431,7 +2431,7 @@ SvgLoader::~SvgLoader()
}
void SvgLoader::run()
void SvgLoader::run(unsigned tid)
{
if (!simpleXmlParse(content, size, true, _svgLoaderParser, &(loaderData))) return;

View file

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