sw_engine: optimize rasterizey by threading it. 39/237039/6
authorHermet Park <chuneon.park@samsung.com>
Wed, 24 Jun 2020 08:10:50 +0000 (17:10 +0900)
committerHermet Park <chuneon.park@samsung.com>
Wed, 24 Jun 2020 09:43:11 +0000 (18:43 +0900)
Also, newly introduced render interfaces: preRender(), postRender(), flush()

Change-Id: If506fa27e3c7dbd89f6734cad4774c1d151b88aa

13 files changed:
inc/tizenvg.h
src/lib/gl_engine/tvgGlRenderer.cpp
src/lib/gl_engine/tvgGlRenderer.h
src/lib/sw_engine/tvgSwCommon.h
src/lib/sw_engine/tvgSwRenderer.cpp
src/lib/sw_engine/tvgSwRenderer.h
src/lib/sw_engine/tvgSwShape.cpp
src/lib/tvgCanvas.cpp
src/lib/tvgCanvasImpl.h
src/lib/tvgGlCanvas.cpp
src/lib/tvgRender.h
src/lib/tvgSwCanvas.cpp
test/testStress.cpp

index a7eede4..a9e797f 100644 (file)
@@ -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;
 
index ecabf6a..bef3871 100644 (file)
@@ -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;
 }
 
 
index 5214a63..7d0972a 100644 (file)
@@ -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;
index 9c54088..72fa700 100644 (file)
@@ -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)};
index 8c59029..2458cdb 100644 (file)
@@ -17,6 +17,8 @@
 #ifndef _TVG_SW_RENDERER_CPP_
 #define _TVG_SW_RENDERER_CPP_
 
+using namespace std;
+
 #include "tvgSwCommon.h"
 #include "tvgSwRenderer.h"
 
 /************************************************************************/
 /* 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::render(const Shape& sdata, void *data)
+bool SwRenderer::preRender()
 {
-    auto task = static_cast<SwTask*>(data);
-    if (!task) return false;
+    //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;
+}
 
-    if (task->prepared.valid()) task->prepared.get();
 
-    uint8_t r, g, b, a;
+bool SwRenderer::postRender()
+{
+    auto asyncTask = [](SwRenderer* renderer) {
+        renderer->doRender();
+    };
 
-    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);
+    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;
+}
+
 
-    sdata.strokeColor(&r, &g, &b, &a);
-    if (a > 0) rasterStroke(surface, task->shape, r, g, b, a);
+bool SwRenderer::render(const Shape& sdata, void *data)
+{
+    //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;
 }
index 4a4fafd..3669d03 100644 (file)
 #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_ */
index d9a4e81..9a79c6e 100644 (file)
@@ -568,6 +568,8 @@ void shapeFree(SwShape& shape)
     shapeDelOutline(shape);
     rleFree(shape.rle);
 
+    shapeDelFill(shape);
+
     if (shape.stroke) {
         rleFree(shape.strokeRle);
         strokeFree(shape.stroke);
index dc05d66..01fcae1 100644 (file)
@@ -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_ */
index ae0ce3c..94737c9 100644 (file)
@@ -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;
     }
 };
index 80a0017..1af7eac 100644 (file)
@@ -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);
index 8e9a50f..b0a3c84 100644 (file)
@@ -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;
 };
index 780e463..a0bfdd0 100644 (file)
@@ -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);
index 870742e..f500078 100644 (file)
@@ -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();