ector: move RLE shape/stroke computation to a pool of thread.
authorCedric Bail <cedric@osg.samsung.com>
Sun, 17 Sep 2017 06:23:36 +0000 (23:23 -0700)
committerCedric Bail <cedric@osg.samsung.com>
Sun, 17 Sep 2017 18:49:48 +0000 (11:49 -0700)
This has been a long standing plan for improving performance in rendering
vector object. Depending on the test, you will get an improvement between
10 to 35% when rendering vector based object.

We are still maintaining the Cairo backend as the default one at the moment
due to a lack of result comparison tests between the two engine. Hopefully
we should get that covered and we can all enjoy a backend that is 4 times
faster by default.

src/lib/ector/software/ector_renderer_software_shape.c
src/lib/ector/software/ector_software_private.h
src/lib/ector/software/ector_software_rasterizer.c
src/lib/ector/software/ector_software_surface.c

index 5bbdbf1..25da9ca 100644 (file)
 #include "ector_software_private.h"
 
 typedef struct _Ector_Renderer_Software_Shape_Data Ector_Renderer_Software_Shape_Data;
+typedef struct _Ector_Software_Shape_Task Ector_Software_Shape_Task;
+
+struct _Ector_Software_Shape_Task
+{
+   Ector_Renderer_Software_Shape_Data *pd;
+
+   const Efl_Gfx_Path_Command *cmds;
+   const double *pts;
+
+   Efl_Gfx_Fill_Rule fill_rule;
+};
+
 struct _Ector_Renderer_Software_Shape_Data
 {
-   Efl_Gfx_Shape_Public                *public_shape;
+   Efl_Gfx_Shape_Public        *public_shape;
 
-   Ector_Software_Surface_Data         *surface;
+   Ector_Software_Surface_Data *surface;
    Ector_Renderer_Shape_Data   *shape;
-   Ector_Renderer_Data    *base;
+   Ector_Renderer_Data         *base;
 
-   Shape_Rle_Data                      *shape_data;
-   Shape_Rle_Data                      *outline_data;
+   Shape_Rle_Data              *shape_data;
+   Shape_Rle_Data              *outline_data;
+
+   Ector_Software_Shape_Task   *task;
+
+   Eina_Bool                    done;
 };
 
 typedef struct _Outline
@@ -511,70 +527,110 @@ _generate_shape_data(Ector_Renderer_Software_Shape_Data *pd)
    return EINA_TRUE;
 }
 
-static void 
-_update_rle(Eo *obj, Ector_Renderer_Software_Shape_Data *pd)
+static Ector_Software_Shape_Task *
+_need_update_rle(Eo *obj, Ector_Renderer_Software_Shape_Data *pd)
 {
-   const Efl_Gfx_Path_Command *cmds = NULL;
-   const double *pts = NULL;
-   Eina_Bool close_path;
+   Ector_Software_Shape_Task *r;
+   const Efl_Gfx_Path_Command *cmds;
+   const double *pts;
    Efl_Gfx_Fill_Rule fill_rule;
-   Outline *outline, *dash_outline;
+
+   if (!pd->done && pd->task) return pd->task;
+
+   if (!_generate_stroke_data(pd) &&
+       !_generate_shape_data(pd))
+     return NULL;
 
    efl_gfx_path_get(obj, &cmds, &pts);
    fill_rule = efl_gfx_shape_fill_rule_get(obj);
-   if (cmds && (_generate_stroke_data(pd) || _generate_shape_data(pd)))
-     {
-        outline = _outline_create();
-        close_path = _generate_outline(cmds, pts, outline);
-        if (fill_rule == EFL_GFX_FILL_RULE_ODD_EVEN)
-          outline->ft_outline.flags = SW_FT_OUTLINE_EVEN_ODD_FILL;
-        else
-          outline->ft_outline.flags = SW_FT_OUTLINE_NONE; // default is winding fill
 
-        _outline_transform(outline, pd->base->m);
+   if (!cmds) return NULL;
+
+   r = pd->task;
+   if (!r) r = malloc(sizeof (Ector_Software_Shape_Task));
+   if (!r) return NULL;
+
+   r->pd = pd;
+   r->cmds = cmds;
+   r->pts = pts;
+   r->fill_rule = fill_rule;
+
+   pd->done = EINA_FALSE;
+   pd->task = r;
 
-        //shape data generation 
-        if (_generate_shape_data(pd))
-          pd->shape_data = ector_software_rasterizer_generate_rle_data(pd->surface->rasterizer,
-                                                                       &outline->ft_outline);
+   return r;
+}
+
+static void
+_done_rle(void *data)
+{
+   Ector_Software_Shape_Task *task = data;
+
+   task->pd->done = EINA_TRUE;
+}
 
-        //stroke data generation
-        if ( _generate_stroke_data(pd))
+static void
+_update_rle(void *data, Ector_Software_Thread *thread)
+{
+   Ector_Software_Shape_Task *task = data;
+   Eina_Bool close_path;
+   Outline *outline, *dash_outline;
+
+   outline = _outline_create();
+   close_path = _generate_outline(task->cmds, task->pts, outline);
+   if (task->fill_rule == EFL_GFX_FILL_RULE_ODD_EVEN)
+     outline->ft_outline.flags = SW_FT_OUTLINE_EVEN_ODD_FILL;
+   else
+     outline->ft_outline.flags = SW_FT_OUTLINE_NONE; // default is winding fill
+
+   _outline_transform(outline, task->pd->base->m);
+
+   //shape data generation
+   if (_generate_shape_data(task->pd))
+     task->pd->shape_data = ector_software_rasterizer_generate_rle_data(thread,
+                                                                        task->pd->surface->rasterizer,
+                                                                        &outline->ft_outline);
+
+   //stroke data generation
+   if (_generate_stroke_data(task->pd))
+     {
+        ector_software_rasterizer_stroke_set(thread, task->pd->surface->rasterizer,
+                                             (task->pd->public_shape->stroke.width *
+                                              task->pd->public_shape->stroke.scale),
+                                             task->pd->public_shape->stroke.cap,
+                                             task->pd->public_shape->stroke.join,
+                                             task->pd->base->m);
+
+        if (task->pd->public_shape->stroke.dash)
           {
-             ector_software_rasterizer_stroke_set(pd->surface->rasterizer,
-                                                  (pd->public_shape->stroke.width *
-                                                  pd->public_shape->stroke.scale),
-                                                  pd->public_shape->stroke.cap,
-                                                  pd->public_shape->stroke.join,
-                                                  pd->base->m);
-
-             if (pd->public_shape->stroke.dash)
-               {
-                  dash_outline = _outline_create();
-                  close_path = _generate_dashed_outline(cmds, pts, dash_outline,
-                                                        pd->public_shape->stroke.dash,
-                                                        pd->public_shape->stroke.dash_length);
-                  _outline_transform(dash_outline, pd->base->m);
-                  pd->outline_data = ector_software_rasterizer_generate_stroke_rle_data(pd->surface->rasterizer,
-                                                                                        &dash_outline->ft_outline,
-                                                                                        close_path);
-                  _outline_destroy(dash_outline);
-               }
-             else
-               {
-                  pd->outline_data = ector_software_rasterizer_generate_stroke_rle_data(pd->surface->rasterizer,
-                                                                                        &outline->ft_outline,
-                                                                                        close_path);
-               }
+             dash_outline = _outline_create();
+             close_path = _generate_dashed_outline(task->cmds, task->pts, dash_outline,
+                                                   task->pd->public_shape->stroke.dash,
+                                                   task->pd->public_shape->stroke.dash_length);
+             _outline_transform(dash_outline, task->pd->base->m);
+             task->pd->outline_data = ector_software_rasterizer_generate_stroke_rle_data(thread,
+                                                                                         task->pd->surface->rasterizer,
+                                                                                         &dash_outline->ft_outline,
+                                                                                         close_path);
+             _outline_destroy(dash_outline);
+          }
+        else
+          {
+             task->pd->outline_data = ector_software_rasterizer_generate_stroke_rle_data(thread,
+                                                                                         task->pd->surface->rasterizer,
+                                                                                         &outline->ft_outline,
+                                                                                         close_path);
           }
-        _outline_destroy(outline);
      }
+   _outline_destroy(outline);
 }
 
 static Eina_Bool
 _ector_renderer_software_shape_ector_renderer_prepare(Eo *obj,
-                                                                   Ector_Renderer_Software_Shape_Data *pd)
+                                                      Ector_Renderer_Software_Shape_Data *pd)
 {
+   Ector_Software_Shape_Task *task;
+
    // FIXME: shouldn't this be part of the shape generic implementation?
    if (pd->shape->fill)
      ector_renderer_prepare(pd->shape->fill);
@@ -587,19 +643,25 @@ _ector_renderer_software_shape_ector_renderer_prepare(Eo *obj,
    if (!pd->surface)
      pd->surface = efl_data_xref(pd->base->surface, ECTOR_SOFTWARE_SURFACE_CLASS, obj);
 
+   // Asynchronously lazy build of the RLE data for this shape
+   task = _need_update_rle(obj, pd);
+   if (task) ector_software_schedule(_update_rle, _done_rle, task);
+
    return EINA_TRUE;
 }
 
 static Eina_Bool
 _ector_renderer_software_shape_ector_renderer_draw(Eo *obj,
-                                                                Ector_Renderer_Software_Shape_Data *pd,
-                                                                Efl_Gfx_Render_Op op, Eina_Array *clips,
-                                                                unsigned int mul_col)
+                                                   Ector_Renderer_Software_Shape_Data *pd,
+                                                   Efl_Gfx_Render_Op op, Eina_Array *clips,
+                                                   unsigned int mul_col)
 {
+   Ector_Software_Shape_Task *task;
    int x, y;
 
-   // do lazy creation of rle
-   _update_rle(obj, pd);
+   // check if RLE data are ready
+   task = _need_update_rle(obj, pd);
+   if (task) ector_software_wait(_update_rle, _done_rle, task);
 
    // adjust the offset
    x = pd->surface->x + (int)pd->base->origin.x;
@@ -684,10 +746,10 @@ static void
 _ector_renderer_software_shape_path_changed(void *data, const Efl_Event *event EINA_UNUSED)
 {
    Ector_Renderer_Software_Shape_Data *pd = data;
-   
+
    if (pd->shape_data) ector_software_rasterizer_destroy_rle_data(pd->shape_data);
    if (pd->outline_data) ector_software_rasterizer_destroy_rle_data(pd->outline_data);
-   
+
    pd->shape_data = NULL;
    pd->outline_data = NULL;
 }
@@ -698,6 +760,8 @@ _ector_renderer_software_shape_efl_object_constructor(Eo *obj, Ector_Renderer_So
    obj = efl_constructor(efl_super(obj, ECTOR_RENDERER_SOFTWARE_SHAPE_CLASS));
    if (!obj) return NULL;
 
+   pd->task = NULL;
+   pd->done = EINA_FALSE;
    pd->public_shape = efl_data_xref(obj, EFL_GFX_SHAPE_MIXIN, obj);
    pd->shape = efl_data_xref(obj, ECTOR_RENDERER_SHAPE_MIXIN, obj);
    pd->base = efl_data_xref(obj, ECTOR_RENDERER_CLASS, obj);
@@ -711,10 +775,14 @@ _ector_renderer_software_shape_efl_object_destructor(Eo *obj, Ector_Renderer_Sof
 {
    // FIXME: As base class, destructor can't call destructor of mixin class.
    // Call explicit API to free shape data.
+   if (!pd->done && pd->task)
+     ector_software_wait(_update_rle, _done_rle, pd->task);
+
    efl_gfx_path_reset(obj);
 
    if (pd->shape_data) ector_software_rasterizer_destroy_rle_data(pd->shape_data);
    if (pd->outline_data) ector_software_rasterizer_destroy_rle_data(pd->outline_data);
+   free(pd->task);
 
    efl_data_xunref(pd->base->surface, pd->surface, obj);
    efl_data_xunref(obj, pd->shape, obj);
index a255fd3..e35f681 100644 (file)
@@ -95,13 +95,9 @@ typedef struct _Span_Data
 
 typedef struct _Software_Rasterizer
 {
-   SW_FT_Raster     raster;
-   SW_FT_Stroker    stroker;
-
    Span_Data        fill_data;
    Eina_Matrix3    *transform;
    Eina_Rectangle   system_clip;
-
 } Software_Rasterizer;
 
 struct _Ector_Software_Surface_Data
@@ -114,9 +110,9 @@ struct _Ector_Software_Surface_Data
 
 int  ector_software_gradient_init(void);
 void ector_software_rasterizer_init(Software_Rasterizer *rasterizer);
-void ector_software_rasterizer_done(Software_Rasterizer *rasterizer);
 
-void ector_software_rasterizer_stroke_set(Software_Rasterizer *rasterizer, double width,
+void ector_software_rasterizer_stroke_set(Ector_Software_Thread *thread, Software_Rasterizer *rasterizer,
+                                          double width,
                                           Efl_Gfx_Cap cap_style, Efl_Gfx_Join join_style, Eina_Matrix3 *m);
 
 void ector_software_rasterizer_transform_set(Software_Rasterizer *rasterizer, Eina_Matrix3 *t);
index 02f24df..fcbd3d0 100644 (file)
@@ -300,14 +300,18 @@ _adjust_span_fill_methods(Span_Data *spdata)
      }
 }
 
-void ector_software_rasterizer_init(Software_Rasterizer *rasterizer)
+void ector_software_thread_init(Ector_Software_Thread *thread)
 {
    // initialize the rasterizer and stroker
-   sw_ft_grays_raster.raster_new(&rasterizer->raster);
+   sw_ft_grays_raster.raster_new(&thread->raster);
 
-   SW_FT_Stroker_New(&rasterizer->stroker);
-   SW_FT_Stroker_Set(rasterizer->stroker, 1<<6,SW_FT_STROKER_LINECAP_BUTT,SW_FT_STROKER_LINEJOIN_MITER,0);
+   SW_FT_Stroker_New(&thread->stroker);
+   SW_FT_Stroker_Set(thread->stroker, 1 << 6,
+                     SW_FT_STROKER_LINECAP_BUTT, SW_FT_STROKER_LINEJOIN_MITER, 0);
+}
 
+void ector_software_rasterizer_init(Software_Rasterizer *rasterizer)
+{
    //initialize the span data.
    rasterizer->fill_data.clip.enabled = EINA_FALSE;
    rasterizer->fill_data.unclipped_blend = 0;
@@ -316,13 +320,14 @@ void ector_software_rasterizer_init(Software_Rasterizer *rasterizer)
    ector_software_gradient_init();
 }
 
-void ector_software_rasterizer_done(Software_Rasterizer *rasterizer)
+void ector_software_thread_shutdown(Ector_Software_Thread *thread)
 {
-   sw_ft_grays_raster.raster_done(rasterizer->raster);
-   SW_FT_Stroker_Done(rasterizer->stroker);
+   sw_ft_grays_raster.raster_done(thread->raster);
+   SW_FT_Stroker_Done(thread->stroker);
 }
 
-void ector_software_rasterizer_stroke_set(Software_Rasterizer *rasterizer, double width,
+void ector_software_rasterizer_stroke_set(Ector_Software_Thread *thread,
+                                          Software_Rasterizer *rasterizer EINA_UNUSED, double width,
                                           Efl_Gfx_Cap cap_style, Efl_Gfx_Join join_style,
                                           Eina_Matrix3 *m)
 {
@@ -366,7 +371,7 @@ void ector_software_rasterizer_stroke_set(Software_Rasterizer *rasterizer, doubl
           join = SW_FT_STROKER_LINEJOIN_MITER;
           break;
      }
-   SW_FT_Stroker_Set(rasterizer->stroker, stroke_width, cap, join, 0);
+   SW_FT_Stroker_Set(thread->stroker, stroke_width, cap, join, 0);
 }
 
 static void
@@ -393,7 +398,9 @@ _rle_generation_cb( int count, const SW_FT_Span*  spans,void *user)
 }
 
 Shape_Rle_Data *
-ector_software_rasterizer_generate_rle_data(Software_Rasterizer *rasterizer, SW_FT_Outline *outline)
+ector_software_rasterizer_generate_rle_data(Ector_Software_Thread *thread,
+                                            Software_Rasterizer *rasterizer EINA_UNUSED,
+                                            SW_FT_Outline *outline)
 {
    int i, rle_size;
    int l = 0, t = 0, r = 0, b = 0;
@@ -406,7 +413,7 @@ ector_software_rasterizer_generate_rle_data(Software_Rasterizer *rasterizer, SW_
    params.user = rle_data;
    params.source = outline;
 
-   sw_ft_grays_raster.raster_render(rasterizer->raster, &params);
+   sw_ft_grays_raster.raster_render(thread->raster, &params);
 
    // update RLE bounding box.
    span = rle_data->spans;
@@ -429,22 +436,25 @@ ector_software_rasterizer_generate_rle_data(Software_Rasterizer *rasterizer, SW_
 }
 
 Shape_Rle_Data *
-ector_software_rasterizer_generate_stroke_rle_data(Software_Rasterizer *rasterizer, SW_FT_Outline *outline, Eina_Bool closePath)
+ector_software_rasterizer_generate_stroke_rle_data(Ector_Software_Thread *thread,
+                                                   Software_Rasterizer *rasterizer,
+                                                   SW_FT_Outline *outline,
+                                                   Eina_Bool closePath)
 {
    uint32_t points,contors;
    Shape_Rle_Data *rle_data;
    SW_FT_Outline strokeOutline = { 0, 0, NULL, NULL, NULL, 0 };
 
-   SW_FT_Stroker_ParseOutline(rasterizer->stroker, outline, !closePath);
-   SW_FT_Stroker_GetCounts(rasterizer->stroker,&points, &contors);
+   SW_FT_Stroker_ParseOutline(thread->stroker, outline, !closePath);
+   SW_FT_Stroker_GetCounts(thread->stroker,&points, &contors);
 
    strokeOutline.points = (SW_FT_Vector *) calloc(points, sizeof(SW_FT_Vector));
    strokeOutline.tags = (char *) calloc(points, sizeof(char));
    strokeOutline.contours = (short *) calloc(contors, sizeof(short));
 
-   SW_FT_Stroker_Export(rasterizer->stroker, &strokeOutline);
+   SW_FT_Stroker_Export(thread->stroker, &strokeOutline);
 
-   rle_data = ector_software_rasterizer_generate_rle_data(rasterizer, &strokeOutline);
+   rle_data = ector_software_rasterizer_generate_rle_data(thread, rasterizer, &strokeOutline);
 
    // cleanup the outline data.
    free(strokeOutline.points);
index 016b267..e3e72fb 100644 (file)
@@ -90,6 +90,7 @@ _ector_software_init(void)
 
         t = &ths[i];
         t->queue = eina_thread_queue_new();
+        ector_software_thread_init(t);
         if (!eina_thread_create(&t->thread, EINA_THREAD_NORMAL, -1,
                                 _prepare_process, t))
           {
@@ -107,7 +108,11 @@ _ector_software_shutdown(void)
 
    if (!--count_init) return ;
 
-   if (!ths) return ;
+   if (!ths)
+     {
+        ector_software_thread_shutdown(&render_thread);
+        return ;
+     }
 
    for (i = 0; i < cpu_core; i++)
      {
@@ -123,6 +128,7 @@ _ector_software_shutdown(void)
 
         eina_thread_join(t->thread);
         eina_thread_queue_free(t->queue);
+        ector_software_thread_shutdown(t);
      }
 
    eina_thread_queue_free(render_queue);
@@ -220,7 +226,6 @@ _ector_software_surface_efl_object_constructor(Eo *obj, Ector_Software_Surface_D
 static void
 _ector_software_surface_efl_object_destructor(Eo *obj, Ector_Software_Surface_Data *pd)
 {
-   ector_software_rasterizer_done(pd->rasterizer);
    efl_data_unref(obj, pd->rasterizer->fill_data.raster_buffer);
    free(pd->rasterizer);
    pd->rasterizer = NULL;