From b557bd9e0d3f1e056a7c554d9767710e096dace8 Mon Sep 17 00:00:00 2001 From: Paulo Alcantara Date: Tue, 15 Jan 2013 17:35:11 +0000 Subject: [PATCH] efl/engines: Introduce multi_font_draw() function This new engine function will only be used in software generic for now - since it's the only engine used with the async render. This function has been introduced in order to avoid growing thread command queue too much to draw a text_props at a time on render calls from textgrid objects. Patch by: Paulo Alcantara SVN revision: 82832 --- ChangeLog | 5 + NEWS | 2 + src/lib/evas/canvas/evas_main.c | 2 + src/lib/evas/canvas/evas_object_textgrid.c | 128 +++++++++++++++--- src/lib/evas/canvas/evas_render.c | 16 +++ src/lib/evas/common/evas_font_draw.c | 15 ++ src/lib/evas/common/evas_text_utils.h | 27 +++- src/lib/evas/include/evas_private.h | 5 + .../engines/software_generic/evas_engine.c | 76 ++++++++++- 9 files changed, 251 insertions(+), 25 deletions(-) diff --git a/ChangeLog b/ChangeLog index d8997ebdb7..421e2e3397 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2013-01-15 Paulo Alcantara (pcacjr) + + * Evas engines: Introduce multi_font_draw() function + * Evas textgrid: Change render to support multi_font_draw() + 2013-01-15 Tom Hacohen (TAsn) * Evas textblock: Fixed issue and simplified cursor_geometry_get. diff --git a/NEWS b/NEWS index 71325bdcee..34437a01ee 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,7 @@ Changes since 1.7.0: -------------------- Additions: + * Add multiple font draws support to engines * Add DOCTYPE children parsing in eina_simple_xml * Add eina_barrier thread API * Add eina_tmpstr_add() and eina_tmpstr_del() @@ -65,6 +66,7 @@ Removed: * Removed XRender, WinCE, X11-16 and X11-8 ecore_evas support. Improvements: + * Reduced number of enqueued font commands when rendering textgrid objects * Single EFL tree covering all EFL library components. * Speedup Eina Rbtree Iterator by recycling memory instead of repeatedly calling malloc/free. diff --git a/src/lib/evas/canvas/evas_main.c b/src/lib/evas/canvas/evas_main.c index 0dc6fae1b8..dbe07e1d31 100644 --- a/src/lib/evas/canvas/evas_main.c +++ b/src/lib/evas/canvas/evas_main.c @@ -144,6 +144,7 @@ _constructor(Eo *eo_obj, void *class_data, va_list *list EINA_UNUSED) EVAS_ARRAY_SET(e, clip_changes); EVAS_ARRAY_SET(e, image_unref_queue); EVAS_ARRAY_SET(e, glyph_unref_queue); + EVAS_ARRAY_SET(e, texts_unref_queue); #undef EVAS_ARRAY_SET } @@ -251,6 +252,7 @@ _destructor(Eo *eo_e, void *_pd, va_list *list EINA_UNUSED) eina_array_flush(&e->clip_changes); eina_array_flush(&e->image_unref_queue); eina_array_flush(&e->glyph_unref_queue); + eina_array_flush(&e->texts_unref_queue); EINA_LIST_FREE(e->touch_points, touch_point) free(touch_point); diff --git a/src/lib/evas/canvas/evas_object_textgrid.c b/src/lib/evas/canvas/evas_object_textgrid.c index 63f557732e..4e80f7a568 100644 --- a/src/lib/evas/canvas/evas_object_textgrid.c +++ b/src/lib/evas/canvas/evas_object_textgrid.c @@ -23,8 +23,8 @@ typedef struct _Evas_Object_Textgrid_Row Evas_Object_Textgrid_Row; typedef struct _Evas_Object_Textgrid_Rect Evas_Object_Textgrid_Rect; typedef struct _Evas_Object_Textgrid_Text Evas_Object_Textgrid_Text; typedef struct _Evas_Object_Textgrid_Line Evas_Object_Textgrid_Line; -typedef struct _Evas_Textgrid_Hash_Master Evas_Textgrid_Hash_Master; -typedef struct _Evas_Textgrid_Hash_Glyphs Evas_Textgrid_Hash_Glyphs; +typedef struct _Evas_Textgrid_Hash_Master Evas_Textgrid_Hash_Master; +typedef struct _Evas_Textgrid_Hash_Glyphs Evas_Textgrid_Hash_Glyphs; struct _Evas_Textgrid_Hash_Master { @@ -370,7 +370,7 @@ static void evas_object_textgrid_row_clear(Evas_Object_Textgrid *o, Evas_Object_Textgrid_Row *r) { int i; - + if (r->rects) { free(r->rects); @@ -480,7 +480,7 @@ evas_object_textgrid_row_rect_append(Evas_Object_Textgrid_Row *row, int x, int w if (row->rects_num > row->rects_alloc) { Evas_Object_Textgrid_Rect *t; - + row->rects_alloc += 8; // dont expect many rects per line t = realloc(row->rects, sizeof(Evas_Object_Textgrid_Rect) * row->rects_alloc); if (!t) @@ -501,11 +501,13 @@ evas_object_textgrid_row_rect_append(Evas_Object_Textgrid_Row *row, int x, int w static void evas_object_textgrid_row_text_append(Evas_Object_Textgrid_Row *row, Evas_Object *eo_obj, Evas_Object_Textgrid *o, int x, Eina_Unicode codepoint, int r, int g, int b, int a) { + unsigned int text_props_index; + row->texts_num++; if (row->texts_num > row->texts_alloc) { Evas_Object_Textgrid_Text *t; - + row->texts_alloc += 32; // expect more text per line t = realloc(row->texts, sizeof(Evas_Object_Textgrid_Text) * row->texts_alloc); if (!t) @@ -516,7 +518,9 @@ evas_object_textgrid_row_text_append(Evas_Object_Textgrid_Row *row, Evas_Object row->texts = t; } - row->texts[row->texts_num - 1].text_props = evas_object_textgrid_textprop_ref(eo_obj, o, codepoint); + text_props_index = evas_object_textgrid_textprop_ref(eo_obj, o, codepoint); + + row->texts[row->texts_num - 1].text_props = text_props_index; row->texts[row->texts_num - 1].x = x; row->texts[row->texts_num - 1].r = r; row->texts[row->texts_num - 1].g = g; @@ -531,7 +535,7 @@ evas_object_textgrid_row_line_append(Evas_Object_Textgrid_Row *row, int x, int w if (row->lines_num > row->lines_alloc) { Evas_Object_Textgrid_Line *t; - + row->lines_alloc += 8; // dont expect many lines per line t = realloc(row->lines, sizeof(Evas_Object_Textgrid_Line) * row->lines_alloc); if (!t) @@ -550,6 +554,18 @@ evas_object_textgrid_row_line_append(Evas_Object_Textgrid_Row *row, int x, int w row->lines[row->lines_num - 1].a = a; } +static Eina_Bool +_drop_glyphs_ref(const void *container EINA_UNUSED, void *data, void *fdata) +{ + Evas_Font_Array_Data *fad = data; + Evas_Public_Data *pd = fdata; + + evas_common_font_glyphs_unref(fad->glyphs); + eina_array_pop(&pd->glyph_unref_queue); + + return EINA_TRUE; +} + static void evas_object_textgrid_render(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj, void *output, void *context, void *surface, int x, int y, Eina_Bool do_async) { @@ -559,13 +575,13 @@ evas_object_textgrid_render(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj int xx, yy, xp, yp, w, h, ww, hh; int rr = 0, rg = 0, rb = 0, ra = 0, rx = 0, rw = 0, run; - /* render object to surface with context, and offxet by x,y */ + /* render object to surface with context, and offset by x,y */ Evas_Object_Textgrid *o = eo_data_get(eo_obj, MY_CLASS); ENFN->context_multiplier_unset(output, context); ENFN->context_render_op_set(output, context, obj->cur.render_op); if (!(o->font) || (!o->cur.cells)) return; - + w = o->cur.char_width; h = o->cur.char_height; ww = obj->cur.geometry.w; @@ -575,7 +591,7 @@ evas_object_textgrid_render(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj for (yy = 0, cells = o->cur.cells; yy < o->cur.h; yy++) { Evas_Object_Textgrid_Row *row = &(o->cur.rows[yy]); - + if (row->ch1 < 0) { cells += o->cur.w; @@ -661,34 +677,104 @@ evas_object_textgrid_render(Evas_Object *eo_obj, Evas_Object_Protected_Data *obj for (yy = 0, cells = o->cur.cells; yy < o->cur.h; yy++) { Evas_Object_Textgrid_Row *row = &(o->cur.rows[yy]); + Evas_Font_Array *texts; xp = obj->cur.geometry.x + x; for (xx = 0; xx < row->rects_num; xx++) { ENFN->context_color_set(output, context, row->rects[xx].r, row->rects[xx].g, - row->rects[xx].b, row->rects[xx].a); + row->rects[xx].b, row->rects[xx].a); ENFN->rectangle_draw(output, context, surface, xp + row->rects[xx].x, yp, row->rects[xx].w, h, do_async); } - for (xx = 0; xx < row->texts_num; xx++) + + if (row->texts_num) { - ENFN->context_color_set(output, context, - row->texts[xx].r, row->texts[xx].g, - row->texts[xx].b, row->texts[xx].a); - evas_font_draw_async_check(obj, output, context, surface, o->font, - xp + row->texts[xx].x, yp + o->max_ascent, - ww, hh, ww, hh, - evas_object_textgrid_textprop_int_to(o, row->texts[xx].text_props), - do_async); + if ((do_async) && (ENFN->multi_font_draw)) + { + Eina_Bool async_unref; + + texts = malloc(sizeof(*texts)); + texts->array = eina_inarray_new(sizeof(Evas_Font_Array_Data), + 32); + texts->refcount = 1; + + for (xx = 0; xx < row->texts_num; xx++) + { + Evas_Text_Props *props; + Evas_Font_Array_Data fad; + + props = + evas_object_textgrid_textprop_int_to + (o, row->texts[xx].text_props); + + evas_common_font_draw_prepare(props); + + evas_common_font_glyphs_ref(props->glyphs); + evas_unref_queue_glyph_put(obj->layer->evas, + props->glyphs); + + fad.color.r = row->texts[xx].r; + fad.color.g = row->texts[xx].g; + fad.color.b = row->texts[xx].b; + fad.color.a = row->texts[xx].a; + fad.x = row->texts[xx].x; + fad.glyphs = props->glyphs; + + if (eina_inarray_push(texts->array, &fad) < 0) + ERR("Failed to push text onto texts array %p", + texts->array); + } + + async_unref = + ENFN->multi_font_draw(output, context, surface, + o->font, xp, yp + o->max_ascent, + ww, hh, ww, hh, texts, do_async); + if (async_unref) + evas_unref_queue_texts_put(obj->layer->evas, texts); + else + { + eina_inarray_foreach(texts->array, _drop_glyphs_ref, + obj->layer->evas); + eina_inarray_free(texts->array); + free(texts); + } + } + else + { + for (xx = 0; xx < row->texts_num; xx++) + { + Evas_Text_Props *props; + unsigned int r, g, b, a; + int tx = xp + row->texts[xx].x; + int ty = yp + o->max_ascent; + + props = + evas_object_textgrid_textprop_int_to + (o, row->texts[xx].text_props); + + r = row->texts[xx].r; + g = row->texts[xx].g; + b = row->texts[xx].b; + a = row->texts[xx].a; + + ENFN->context_color_set(output, context, + r, g, b, a); + evas_font_draw_async_check(obj, output, context, surface, + o->font, tx, ty, ww, hh, + ww, hh, props, do_async); + } + } } + for (xx = 0; xx < row->lines_num; xx++) { ENFN->context_color_set(output, context, row->lines[xx].r, row->lines[xx].g, - row->lines[xx].b, row->lines[xx].a); + row->lines[xx].b, row->lines[xx].a); ENFN->rectangle_draw(output, context, surface, xp + row->lines[xx].x, yp + row->lines[xx].y, row->lines[xx].w, 1, diff --git a/src/lib/evas/canvas/evas_render.c b/src/lib/evas/canvas/evas_render.c index 0b7a056eda..0136f736a9 100644 --- a/src/lib/evas/canvas/evas_render.c +++ b/src/lib/evas/canvas/evas_render.c @@ -1843,6 +1843,14 @@ _drop_glyph_ref(const void *container EINA_UNUSED, void *data, void *fdata EINA_ return EINA_TRUE; } +static Eina_Bool +_drop_texts_ref(const void *container EINA_UNUSED, void *data, void *fdata EINA_UNUSED) +{ + evas_common_font_fonts_unref(data); + + return EINA_TRUE; +} + static void evas_render_wakeup(Evas *eo_e) { @@ -1887,6 +1895,8 @@ evas_render_wakeup(Evas *eo_e) eina_array_clean(&e->image_unref_queue); eina_array_foreach(&e->glyph_unref_queue, _drop_glyph_ref, NULL); eina_array_clean(&e->glyph_unref_queue); + eina_array_foreach(&e->texts_unref_queue, _drop_texts_ref, NULL); + eina_array_clean(&e->texts_unref_queue); up_cb = e->render.updates_cb; up_data = e->render.data; @@ -2172,4 +2182,10 @@ evas_unref_queue_glyph_put(Evas_Public_Data *pd, void *glyph) eina_array_push(&pd->glyph_unref_queue, glyph); } +void +evas_unref_queue_texts_put(Evas_Public_Data *pd, void *texts) +{ + eina_array_push(&pd->texts_unref_queue, texts); +} + /* vim:set ts=8 sw=3 sts=3 expandtab cino=>5n-2f0^-2{2(0W1st0 :*/ diff --git a/src/lib/evas/common/evas_font_draw.c b/src/lib/evas/common/evas_font_draw.c index cfb8aac6f9..99883926ae 100644 --- a/src/lib/evas/common/evas_font_draw.c +++ b/src/lib/evas/common/evas_font_draw.c @@ -239,6 +239,21 @@ evas_common_font_glyphs_unref(Evas_Glyph_Array *array) free(array); } +void +evas_common_font_fonts_ref(Evas_Font_Array *array) +{ + array->refcount++; +} + +void +evas_common_font_fonts_unref(Evas_Font_Array *array) +{ + if (--array->refcount) return; + + eina_inarray_free(array->array); + free(array); +} + EAPI void evas_common_font_draw_prepare(Evas_Text_Props *text_props) { diff --git a/src/lib/evas/common/evas_text_utils.h b/src/lib/evas/common/evas_text_utils.h index f2f65a396b..144761ea28 100644 --- a/src/lib/evas/common/evas_text_utils.h +++ b/src/lib/evas/common/evas_text_utils.h @@ -1,12 +1,13 @@ #ifndef _EVAS_TEXT_UTILS_H # define _EVAS_TEXT_UTILS_H - -typedef struct _Evas_Text_Props Evas_Text_Props; +typedef struct _Evas_Text_Props Evas_Text_Props; // special case props -typedef struct _Evas_Text_Props_One Evas_Text_Props_One; +typedef struct _Evas_Text_Props_One Evas_Text_Props_One; typedef struct _Evas_Text_Props_Info Evas_Text_Props_Info; +typedef struct _Evas_Font_Array_Data Evas_Font_Array_Data; +typedef struct _Evas_Font_Array Evas_Font_Array; typedef struct _Evas_Font_Glyph_Info Evas_Font_Glyph_Info; typedef enum @@ -100,6 +101,21 @@ struct _Evas_Text_Props_Info unsigned int refcount; // 4 }; +struct _Evas_Font_Array_Data +{ + struct { + unsigned char r, g, b, a; + } color; + int x; + Evas_Glyph_Array *glyphs; +}; + +struct _Evas_Font_Array +{ + Eina_Inarray *array; + unsigned int refcount; +}; + /* Sorted in visual order when created */ struct _Evas_Font_Glyph_Info { @@ -124,6 +140,11 @@ evas_common_font_glyphs_ref(Evas_Glyph_Array *array); void evas_common_font_glyphs_unref(Evas_Glyph_Array *array); +void +evas_common_font_fonts_ref(Evas_Font_Array *array); +void +evas_common_font_fonts_unref(Evas_Font_Array *array); + void evas_common_text_props_bidi_set(Evas_Text_Props *props, Evas_BiDi_Paragraph_Props *bidi_par_props, size_t start); diff --git a/src/lib/evas/include/evas_private.h b/src/lib/evas/include/evas_private.h index 4a7ec28e74..c5527db740 100644 --- a/src/lib/evas/include/evas_private.h +++ b/src/lib/evas/include/evas_private.h @@ -388,6 +388,7 @@ struct _Evas_Public_Data Eina_Array clip_changes; Eina_Array image_unref_queue; Eina_Array glyph_unref_queue; + Eina_Array texts_unref_queue; Eina_Clist calc_list; Eina_Clist calc_done; @@ -900,6 +901,9 @@ struct _Evas_Func /* max size query */ void (*image_max_size_get) (void *data, int *maxw, int *maxh); + + /* multiple font draws */ + Eina_Bool (*multi_font_draw) (void *data, void *context, void *surface, Evas_Font_Set *font, int x, int y, int w, int h, int ow, int oh, Evas_Font_Array *texts, Eina_Bool do_async); }; struct _Evas_Image_Load_Func @@ -1051,6 +1055,7 @@ void _evas_object_textblock_rehint(Evas_Object *obj); void evas_unref_queue_image_put(Evas_Public_Data *pd, void *image); void evas_unref_queue_glyph_put(Evas_Public_Data *pd, void *glyph); +void evas_unref_queue_texts_put(Evas_Public_Data *pd, void *glyph); void evas_draw_image_map_async_check(Evas_Object_Protected_Data *obj, void *data, void *context, void *surface, diff --git a/src/modules/evas/engines/software_generic/evas_engine.c b/src/modules/evas/engines/software_generic/evas_engine.c index 9dad67c96d..7c00d541f9 100644 --- a/src/modules/evas/engines/software_generic/evas_engine.c +++ b/src/modules/evas/engines/software_generic/evas_engine.c @@ -282,6 +282,7 @@ typedef struct _Evas_Thread_Command_Polygon Evas_Thread_Command_Polygon; typedef struct _Evas_Thread_Command_Image Evas_Thread_Command_Image; typedef struct _Evas_Thread_Command_Font Evas_Thread_Command_Font; typedef struct _Evas_Thread_Command_Map Evas_Thread_Command_Map; +typedef struct _Evas_Thread_Command_Multi_Font Evas_Thread_Command_Multi_Font; struct _Evas_Thread_Command_Rect { @@ -351,12 +352,21 @@ struct _Evas_Thread_Command_Map int smooth, level, offset; }; +struct _Evas_Thread_Command_Multi_Font +{ + RGBA_Draw_Context context; + void *surface; + int x, y; + Evas_Font_Array *texts; +}; + Eina_Mempool *_mp_command_rect = NULL; Eina_Mempool *_mp_command_line = NULL; Eina_Mempool *_mp_command_polygon = NULL; Eina_Mempool *_mp_command_image = NULL; Eina_Mempool *_mp_command_font = NULL; Eina_Mempool *_mp_command_map = NULL; +Eina_Mempool *_mp_command_multi_font = NULL; /* ***** @@ -1753,6 +1763,66 @@ eng_image_animated_frame_set(void *data EINA_UNUSED, void *image, int frame_inde return EINA_TRUE; } +static void +_draw_thread_multi_font_draw(void *data) +{ + Evas_Thread_Command_Multi_Font *mf = data; + Evas_Font_Array_Data *itr; + + EINA_INARRAY_FOREACH(mf->texts->array, itr) + { + unsigned int r, g, b, a; + int x = mf->x + itr->x, y = mf->y; + + r = itr->color.r; + g = itr->color.g; + b = itr->color.b; + a = itr->color.a; + + eng_context_color_set(NULL, &mf->context, r, g, b, a); + evas_common_font_draw(mf->surface, &mf->context, x, y, itr->glyphs); + evas_common_cpu_end_opt(); + } + + eina_mempool_free(_mp_command_multi_font, mf); +} + +static Eina_Bool +_multi_font_draw_thread_cmd(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, Evas_Font_Array *texts) +{ + Evas_Thread_Command_Multi_Font *mf; + + mf = eina_mempool_malloc(_mp_command_multi_font, + sizeof(Evas_Thread_Command_Multi_Font)); + if (!mf) + { + ERR("Failed to allocate memory on mempool for multiple text_props " + "commands."); + return EINA_FALSE; + } + + memcpy(&mf->context, dc, sizeof(*dc)); + mf->surface = dst; + mf->x = x; + mf->y = y; + mf->texts = texts; + + evas_thread_cmd_enqueue(_draw_thread_multi_font_draw, mf); + + return EINA_TRUE; +} + +static Eina_Bool +eng_multi_font_draw(void *data EINA_UNUSED, void *context, void *surface, Evas_Font_Set *font EINA_UNUSED, int x, int y, int w EINA_UNUSED, int h EINA_UNUSED, int ow EINA_UNUSED, int oh EINA_UNUSED, Evas_Font_Array *texts, Eina_Bool do_async) +{ + if (!texts) return EINA_FALSE; + + if (do_async) + return _multi_font_draw_thread_cmd(surface, context, x, y, texts); + + return EINA_FALSE; +} + static void eng_image_cache_flush(void *data EINA_UNUSED) { @@ -2485,7 +2555,8 @@ static Evas_Func func = eng_image_animated_loop_count_get, eng_image_animated_frame_duration_get, eng_image_animated_frame_set, - NULL + NULL, + eng_multi_font_draw, /* FUTURE software generic calls go here */ }; @@ -3503,6 +3574,9 @@ module_open(Evas_Module *em) _mp_command_map = eina_mempool_add("chained_mempool", "Evas_Thread_Command_Map", NULL, sizeof (Evas_Thread_Command_Map), 64); + _mp_command_multi_font = + eina_mempool_add("chained_mempool", "Evas_Thread_Command_Multi_Font", + NULL, sizeof(Evas_Thread_Command_Multi_Font), 128); init_gl(); evas_common_pipe_init();