From e380ddb742384546ad05a5f8f5472ecdce795538 Mon Sep 17 00:00:00 2001 From: Cedric Bail Date: Sat, 16 Sep 2017 23:23:36 -0700 Subject: [PATCH] ector: move RLE shape/stroke computation to a pool of thread. 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. --- .../ector/software/ector_renderer_software_shape.c | 188 ++++++++++++++------- src/lib/ector/software/ector_software_private.h | 8 +- src/lib/ector/software/ector_software_rasterizer.c | 42 +++-- src/lib/ector/software/ector_software_surface.c | 9 +- 4 files changed, 163 insertions(+), 84 deletions(-) diff --git a/src/lib/ector/software/ector_renderer_software_shape.c b/src/lib/ector/software/ector_renderer_software_shape.c index 5bbdbf1..25da9ca 100644 --- a/src/lib/ector/software/ector_renderer_software_shape.c +++ b/src/lib/ector/software/ector_renderer_software_shape.c @@ -13,16 +13,32 @@ #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); diff --git a/src/lib/ector/software/ector_software_private.h b/src/lib/ector/software/ector_software_private.h index a255fd3..e35f681 100644 --- a/src/lib/ector/software/ector_software_private.h +++ b/src/lib/ector/software/ector_software_private.h @@ -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); diff --git a/src/lib/ector/software/ector_software_rasterizer.c b/src/lib/ector/software/ector_software_rasterizer.c index 02f24df..fcbd3d0 100644 --- a/src/lib/ector/software/ector_software_rasterizer.c +++ b/src/lib/ector/software/ector_software_rasterizer.c @@ -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, ¶ms); + sw_ft_grays_raster.raster_render(thread->raster, ¶ms); // 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); diff --git a/src/lib/ector/software/ector_software_surface.c b/src/lib/ector/software/ector_software_surface.c index 016b267..e3e72fb 100644 --- a/src/lib/ector/software/ector_software_surface.c +++ b/src/lib/ector/software/ector_software_surface.c @@ -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; -- 2.7.4