mirror of
https://github.com/thorvg/thorvg.git
synced 2025-07-25 23:59:12 +00:00
sw_engine: optimize rasterizey by threading it.
Also, newly introduced render interfaces: preRender(), postRender(), flush() Change-Id: If506fa27e3c7dbd89f6734cad4774c1d151b88aa
This commit is contained in:
parent
36c76ca73c
commit
4156de72f1
13 changed files with 166 additions and 66 deletions
|
@ -153,7 +153,7 @@ public:
|
|||
virtual Result update() noexcept;
|
||||
virtual Result update(Paint* paint) noexcept;
|
||||
virtual Result draw(bool async = true) noexcept;
|
||||
virtual Result sync() = 0;
|
||||
virtual Result sync() noexcept;
|
||||
|
||||
_TVG_DECLARE_ACCESSOR(Scene);
|
||||
_TVG_DECLARE_PRIVATE(Canvas);
|
||||
|
@ -315,7 +315,6 @@ public:
|
|||
~SwCanvas();
|
||||
|
||||
Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept;
|
||||
Result sync() noexcept override;
|
||||
|
||||
static std::unique_ptr<SwCanvas> gen() noexcept;
|
||||
|
||||
|
@ -337,9 +336,7 @@ public:
|
|||
~GlCanvas();
|
||||
|
||||
//TODO: Gl Specific methods. Need gl backend configuration methods as well.
|
||||
|
||||
Result target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept;
|
||||
Result sync() noexcept override;
|
||||
|
||||
static std::unique_ptr<GlCanvas> gen() noexcept;
|
||||
|
||||
|
|
|
@ -53,10 +53,28 @@ bool GlRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t
|
|||
}
|
||||
|
||||
|
||||
void GlRenderer::flush()
|
||||
bool GlRenderer::flush()
|
||||
{
|
||||
GL_CHECK(glFinish());
|
||||
mColorProgram->unload();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool GlRenderer::preRender()
|
||||
{
|
||||
//TODO: called just before render()
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool GlRenderer::postRender()
|
||||
{
|
||||
//TODO: called just after render()
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -28,9 +28,11 @@ public:
|
|||
|
||||
void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override;
|
||||
bool dispose(const Shape& shape, void *data) override;
|
||||
bool preRender() override;
|
||||
bool render(const Shape& shape, void *data) override;
|
||||
bool postRender() override;
|
||||
bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h);
|
||||
void flush();
|
||||
bool flush() override;
|
||||
bool clear() override;
|
||||
uint32_t ref() override;
|
||||
uint32_t unref() override;
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
#ifndef _TVG_SW_COMMON_H_
|
||||
#define _TVG_SW_COMMON_H_
|
||||
|
||||
#include <future>
|
||||
#include <thread>
|
||||
#include "tvgCommon.h"
|
||||
|
||||
#if 0
|
||||
|
@ -203,16 +201,6 @@ struct SwShape
|
|||
};
|
||||
|
||||
|
||||
struct SwTask
|
||||
{
|
||||
SwShape shape;
|
||||
const Shape* sdata;
|
||||
SwSize clip;
|
||||
const Matrix* transform;
|
||||
RenderUpdateFlag flags;
|
||||
future<void> prepared;
|
||||
};
|
||||
|
||||
static inline SwPoint TO_SWPOINT(const Point* pt)
|
||||
{
|
||||
return {SwCoord(pt->x * 64), SwCoord(pt->y * 64)};
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#ifndef _TVG_SW_RENDERER_CPP_
|
||||
#define _TVG_SW_RENDERER_CPP_
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include "tvgSwCommon.h"
|
||||
#include "tvgSwRenderer.h"
|
||||
|
||||
|
@ -24,19 +26,37 @@
|
|||
/************************************************************************/
|
||||
/* Internal Class Implementation */
|
||||
/************************************************************************/
|
||||
namespace tvg {
|
||||
struct SwTask
|
||||
{
|
||||
SwShape shape;
|
||||
const Shape* sdata;
|
||||
SwSize clip;
|
||||
const Matrix* transform;
|
||||
RenderUpdateFlag flags;
|
||||
future<void> progress;
|
||||
};
|
||||
}
|
||||
|
||||
static RenderInitializer renderInit;
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* External Class Implementation */
|
||||
/************************************************************************/
|
||||
|
||||
bool SwRenderer::clear()
|
||||
SwRenderer::~SwRenderer()
|
||||
{
|
||||
return rasterClear(surface);
|
||||
if (progress.valid()) progress.get();
|
||||
}
|
||||
|
||||
|
||||
bool SwRenderer::clear()
|
||||
{
|
||||
if (progress.valid()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h)
|
||||
{
|
||||
if (!buffer || stride == 0 || w == 0 || h == 0) return false;
|
||||
|
@ -50,24 +70,64 @@ bool SwRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t
|
|||
}
|
||||
|
||||
|
||||
bool SwRenderer::preRender()
|
||||
{
|
||||
//before we start rendering, we should finish all preparing tasks
|
||||
while (prepareTasks.size() > 0) {
|
||||
auto task = prepareTasks.front();
|
||||
if (task->progress.valid()) task->progress.get();
|
||||
prepareTasks.pop();
|
||||
renderTasks.push(task);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool SwRenderer::postRender()
|
||||
{
|
||||
auto asyncTask = [](SwRenderer* renderer) {
|
||||
renderer->doRender();
|
||||
};
|
||||
|
||||
progress = async(launch::async, asyncTask, this);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void SwRenderer::doRender()
|
||||
{
|
||||
rasterClear(surface);
|
||||
|
||||
while (renderTasks.size() > 0) {
|
||||
auto task = renderTasks.front();
|
||||
uint8_t r, g, b, a;
|
||||
if (auto fill = task->sdata->fill()) {
|
||||
rasterGradientShape(surface, task->shape, fill->id());
|
||||
} else{
|
||||
task->sdata->fill(&r, &g, &b, &a);
|
||||
if (a > 0) rasterSolidShape(surface, task->shape, r, g, b, a);
|
||||
}
|
||||
task->sdata->strokeColor(&r, &g, &b, &a);
|
||||
if (a > 0) rasterStroke(surface, task->shape, r, g, b, a);
|
||||
renderTasks.pop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool SwRenderer::flush()
|
||||
{
|
||||
if (progress.valid()) {
|
||||
progress.get();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool SwRenderer::render(const Shape& sdata, void *data)
|
||||
{
|
||||
auto task = static_cast<SwTask*>(data);
|
||||
if (!task) return false;
|
||||
|
||||
if (task->prepared.valid()) task->prepared.get();
|
||||
|
||||
uint8_t r, g, b, a;
|
||||
|
||||
if (auto fill = sdata.fill()) {
|
||||
rasterGradientShape(surface, task->shape, fill->id());
|
||||
} else {
|
||||
sdata.fill(&r, &g, &b, &a);
|
||||
if (a > 0) rasterSolidShape(surface, task->shape, r, g, b, a);
|
||||
}
|
||||
|
||||
sdata.strokeColor(&r, &g, &b, &a);
|
||||
if (a > 0) rasterStroke(surface, task->shape, r, g, b, a);
|
||||
//Do Nothing
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -77,7 +137,7 @@ bool SwRenderer::dispose(const Shape& sdata, void *data)
|
|||
{
|
||||
auto task = static_cast<SwTask*>(data);
|
||||
if (!task) return true;
|
||||
if (task->prepared.valid()) task->prepared.wait();
|
||||
if (task->progress.valid()) task->progress.get();
|
||||
shapeFree(task->shape);
|
||||
free(task);
|
||||
return true;
|
||||
|
@ -93,7 +153,7 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform*
|
|||
if (!task) return nullptr;
|
||||
}
|
||||
|
||||
if (flags == RenderUpdateFlag::None || task->prepared.valid()) return task;
|
||||
if (flags == RenderUpdateFlag::None || task->progress.valid()) return task;
|
||||
|
||||
task->sdata = &sdata;
|
||||
task->clip = {static_cast<SwCoord>(surface.w), static_cast<SwCoord>(surface.h)};
|
||||
|
@ -140,7 +200,8 @@ void* SwRenderer::prepare(const Shape& sdata, void* data, const RenderTransform*
|
|||
shapeDelOutline(task->shape);
|
||||
};
|
||||
|
||||
task->prepared = async((launch::async | launch::deferred), asyncTask, task);
|
||||
prepareTasks.push(task);
|
||||
task->progress = async((launch::async | launch::deferred), asyncTask, task);
|
||||
|
||||
return task;
|
||||
}
|
||||
|
|
|
@ -17,16 +17,26 @@
|
|||
#ifndef _TVG_SW_RENDERER_H_
|
||||
#define _TVG_SW_RENDERER_H_
|
||||
|
||||
#include <queue>
|
||||
#include <future>
|
||||
#include <thread>
|
||||
|
||||
namespace tvg
|
||||
{
|
||||
|
||||
struct SwTask;
|
||||
|
||||
class SwRenderer : public RenderMethod
|
||||
{
|
||||
public:
|
||||
Surface surface;
|
||||
|
||||
void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) override;
|
||||
bool dispose(const Shape& shape, void *data) override;
|
||||
bool preRender() override;
|
||||
bool render(const Shape& shape, void *data) override;
|
||||
bool postRender() override;
|
||||
bool target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h);
|
||||
bool clear() override;
|
||||
bool flush() override;
|
||||
uint32_t ref() override;
|
||||
uint32_t unref() override;
|
||||
|
||||
|
@ -34,9 +44,18 @@ public:
|
|||
static int init();
|
||||
static int term();
|
||||
|
||||
void doRender(); //Internally used for threading
|
||||
|
||||
private:
|
||||
Surface surface;
|
||||
future<void> progress;
|
||||
queue<SwTask*> prepareTasks;
|
||||
queue<SwTask*> renderTasks;
|
||||
|
||||
SwRenderer(){};
|
||||
~SwRenderer(){};
|
||||
~SwRenderer();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* _TVG_SW_RENDERER_H_ */
|
||||
|
|
|
@ -568,6 +568,8 @@ void shapeFree(SwShape& shape)
|
|||
shapeDelOutline(shape);
|
||||
rleFree(shape.rle);
|
||||
|
||||
shapeDelFill(shape);
|
||||
|
||||
if (shape.stroke) {
|
||||
rleFree(shape.strokeRle);
|
||||
strokeFree(shape.stroke);
|
||||
|
|
|
@ -82,4 +82,15 @@ Result Canvas::update(Paint* paint) noexcept
|
|||
return impl->update(paint);
|
||||
}
|
||||
|
||||
|
||||
Result Canvas::sync() noexcept
|
||||
{
|
||||
auto impl = pImpl.get();
|
||||
if (!impl) return Result::MemoryCorruption;
|
||||
|
||||
if (impl->renderer->flush()) return Result::Success;
|
||||
|
||||
return Result::InsufficientCondition;
|
||||
}
|
||||
|
||||
#endif /* _TVG_CANVAS_CPP_ */
|
||||
|
|
|
@ -52,6 +52,9 @@ struct Canvas::Impl
|
|||
{
|
||||
if (!renderer) return Result::InsufficientCondition;
|
||||
|
||||
//Clear render target before drawing
|
||||
if (!renderer->clear()) return Result::InsufficientCondition;
|
||||
|
||||
for (auto paint : paints) {
|
||||
if (paint->id() == PAINT_ID_SCENE) {
|
||||
//We know renderer type, avoid dynamic_cast for performance.
|
||||
|
@ -104,8 +107,7 @@ struct Canvas::Impl
|
|||
{
|
||||
if (!renderer) return Result::InsufficientCondition;
|
||||
|
||||
//Clear render target before drawing
|
||||
if (!renderer->clear()) return Result::InsufficientCondition;
|
||||
if (!renderer->preRender()) return Result::InsufficientCondition;
|
||||
|
||||
for(auto paint: paints) {
|
||||
if (paint->id() == PAINT_ID_SCENE) {
|
||||
|
@ -117,6 +119,9 @@ struct Canvas::Impl
|
|||
if(!SHAPE_IMPL->render(*shape, *renderer)) return Result::InsufficientCondition;
|
||||
}
|
||||
}
|
||||
|
||||
if (!renderer->postRender()) return Result::InsufficientCondition;
|
||||
|
||||
return Result::Success;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -57,16 +57,6 @@ Result GlCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t
|
|||
}
|
||||
|
||||
|
||||
Result GlCanvas::sync() noexcept
|
||||
{
|
||||
auto renderer = dynamic_cast<GlRenderer*>(Canvas::pImpl.get()->renderer);
|
||||
assert(renderer);
|
||||
|
||||
renderer->flush();
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
|
||||
unique_ptr<GlCanvas> GlCanvas::gen() noexcept
|
||||
{
|
||||
auto canvas = unique_ptr<GlCanvas>(new GlCanvas);
|
||||
|
|
|
@ -53,8 +53,11 @@ public:
|
|||
virtual ~RenderMethod() {}
|
||||
virtual void* prepare(const Shape& shape, void* data, const RenderTransform* transform, RenderUpdateFlag flags) = 0;
|
||||
virtual bool dispose(const Shape& shape, void *data) = 0;
|
||||
virtual bool preRender() = 0;
|
||||
virtual bool render(const Shape& shape, void *data) = 0;
|
||||
virtual bool postRender() = 0;
|
||||
virtual bool clear() = 0;
|
||||
virtual bool flush() = 0;
|
||||
virtual uint32_t ref() = 0;
|
||||
virtual uint32_t unref() = 0;
|
||||
};
|
||||
|
|
|
@ -45,6 +45,7 @@ SwCanvas::~SwCanvas()
|
|||
{
|
||||
}
|
||||
|
||||
|
||||
Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t h) noexcept
|
||||
{
|
||||
//We know renderer type, avoid dynamic_cast for performance.
|
||||
|
@ -57,12 +58,6 @@ Result SwCanvas::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t
|
|||
}
|
||||
|
||||
|
||||
Result SwCanvas::sync() noexcept
|
||||
{
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
|
||||
unique_ptr<SwCanvas> SwCanvas::gen() noexcept
|
||||
{
|
||||
auto canvas = unique_ptr<SwCanvas>(new SwCanvas);
|
||||
|
|
|
@ -21,9 +21,17 @@ void tvgtest()
|
|||
|
||||
Eina_Bool anim_cb(void *data)
|
||||
{
|
||||
auto t = ecore_time_get();
|
||||
|
||||
//Explicitly clear all retained paint nodes.
|
||||
t1 = ecore_time_get();
|
||||
canvas->clear();
|
||||
if (canvas->clear() != tvg::Result::Success)
|
||||
{
|
||||
//Probably, you missed sync() call before.
|
||||
return ECORE_CALLBACK_RENEW;
|
||||
}
|
||||
|
||||
t1 = t;
|
||||
|
||||
t2 = ecore_time_get();
|
||||
|
||||
for (int i = 0; i < COUNT; i++) {
|
||||
|
@ -61,6 +69,11 @@ Eina_Bool anim_cb(void *data)
|
|||
canvas->push(move(shape));
|
||||
}
|
||||
|
||||
t3 = ecore_time_get();
|
||||
|
||||
//Draw Next frames
|
||||
canvas->draw();
|
||||
|
||||
//Update Efl Canvas
|
||||
Eo* img = (Eo*) data;
|
||||
evas_object_image_pixels_dirty_set(img, EINA_TRUE);
|
||||
|
@ -71,10 +84,6 @@ Eina_Bool anim_cb(void *data)
|
|||
|
||||
void render_cb(void* data, Eo* obj)
|
||||
{
|
||||
t3 = ecore_time_get();
|
||||
|
||||
//Draw Next frames
|
||||
canvas->draw();
|
||||
canvas->sync();
|
||||
|
||||
t4 = ecore_time_get();
|
||||
|
|
Loading…
Add table
Reference in a new issue