diff --git a/inc/tizenvg.h b/inc/tizenvg.h index a7eede4c..a9e797fd 100644 --- a/inc/tizenvg.h +++ b/inc/tizenvg.h @@ -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 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 gen() noexcept; diff --git a/src/lib/gl_engine/tvgGlRenderer.cpp b/src/lib/gl_engine/tvgGlRenderer.cpp index ecabf6ad..bef3871b 100644 --- a/src/lib/gl_engine/tvgGlRenderer.cpp +++ b/src/lib/gl_engine/tvgGlRenderer.cpp @@ -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; } diff --git a/src/lib/gl_engine/tvgGlRenderer.h b/src/lib/gl_engine/tvgGlRenderer.h index 5214a63d..7d0972a7 100644 --- a/src/lib/gl_engine/tvgGlRenderer.h +++ b/src/lib/gl_engine/tvgGlRenderer.h @@ -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; diff --git a/src/lib/sw_engine/tvgSwCommon.h b/src/lib/sw_engine/tvgSwCommon.h index 9c540888..72fa7006 100644 --- a/src/lib/sw_engine/tvgSwCommon.h +++ b/src/lib/sw_engine/tvgSwCommon.h @@ -17,8 +17,6 @@ #ifndef _TVG_SW_COMMON_H_ #define _TVG_SW_COMMON_H_ -#include -#include #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 prepared; -}; - static inline SwPoint TO_SWPOINT(const Point* pt) { return {SwCoord(pt->x * 64), SwCoord(pt->y * 64)}; diff --git a/src/lib/sw_engine/tvgSwRenderer.cpp b/src/lib/sw_engine/tvgSwRenderer.cpp index 8c59029c..2458cdb6 100644 --- a/src/lib/sw_engine/tvgSwRenderer.cpp +++ b/src/lib/sw_engine/tvgSwRenderer.cpp @@ -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 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(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(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(surface.w), static_cast(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; } diff --git a/src/lib/sw_engine/tvgSwRenderer.h b/src/lib/sw_engine/tvgSwRenderer.h index 4a4fafdb..3669d034 100644 --- a/src/lib/sw_engine/tvgSwRenderer.h +++ b/src/lib/sw_engine/tvgSwRenderer.h @@ -17,16 +17,26 @@ #ifndef _TVG_SW_RENDERER_H_ #define _TVG_SW_RENDERER_H_ +#include +#include +#include + +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 progress; + queue prepareTasks; + queue renderTasks; + SwRenderer(){}; - ~SwRenderer(){}; + ~SwRenderer(); }; +} + #endif /* _TVG_SW_RENDERER_H_ */ diff --git a/src/lib/sw_engine/tvgSwShape.cpp b/src/lib/sw_engine/tvgSwShape.cpp index d9a4e816..9a79c6ed 100644 --- a/src/lib/sw_engine/tvgSwShape.cpp +++ b/src/lib/sw_engine/tvgSwShape.cpp @@ -568,6 +568,8 @@ void shapeFree(SwShape& shape) shapeDelOutline(shape); rleFree(shape.rle); + shapeDelFill(shape); + if (shape.stroke) { rleFree(shape.strokeRle); strokeFree(shape.stroke); diff --git a/src/lib/tvgCanvas.cpp b/src/lib/tvgCanvas.cpp index dc05d666..01fcae1f 100644 --- a/src/lib/tvgCanvas.cpp +++ b/src/lib/tvgCanvas.cpp @@ -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_ */ diff --git a/src/lib/tvgCanvasImpl.h b/src/lib/tvgCanvasImpl.h index ae0ce3c0..94737c92 100644 --- a/src/lib/tvgCanvasImpl.h +++ b/src/lib/tvgCanvasImpl.h @@ -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; } }; diff --git a/src/lib/tvgGlCanvas.cpp b/src/lib/tvgGlCanvas.cpp index 80a00177..1af7eace 100644 --- a/src/lib/tvgGlCanvas.cpp +++ b/src/lib/tvgGlCanvas.cpp @@ -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(Canvas::pImpl.get()->renderer); - assert(renderer); - - renderer->flush(); - return Result::Success; -} - - unique_ptr GlCanvas::gen() noexcept { auto canvas = unique_ptr(new GlCanvas); diff --git a/src/lib/tvgRender.h b/src/lib/tvgRender.h index 8e9a50f3..b0a3c846 100644 --- a/src/lib/tvgRender.h +++ b/src/lib/tvgRender.h @@ -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; }; diff --git a/src/lib/tvgSwCanvas.cpp b/src/lib/tvgSwCanvas.cpp index 780e4636..a0bfdd04 100644 --- a/src/lib/tvgSwCanvas.cpp +++ b/src/lib/tvgSwCanvas.cpp @@ -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::gen() noexcept { auto canvas = unique_ptr(new SwCanvas); diff --git a/test/testStress.cpp b/test/testStress.cpp index 870742ed..f500078b 100644 --- a/test/testStress.cpp +++ b/test/testStress.cpp @@ -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();