efl/engines: Introduce multi_font_draw() function
authorPaulo Alcantara <pcacjr@profusion.mobi>
Tue, 15 Jan 2013 17:35:11 +0000 (17:35 +0000)
committerUlisses Furquim <ulisses@profusion.mobi>
Tue, 15 Jan 2013 17:35:11 +0000 (17:35 +0000)
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 <pcacjr@profusion.mobi>

SVN revision: 82832

ChangeLog
NEWS
src/lib/evas/canvas/evas_main.c
src/lib/evas/canvas/evas_object_textgrid.c
src/lib/evas/canvas/evas_render.c
src/lib/evas/common/evas_font_draw.c
src/lib/evas/common/evas_text_utils.h
src/lib/evas/include/evas_private.h
src/modules/evas/engines/software_generic/evas_engine.c

index d8997eb..421e2e3 100644 (file)
--- 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 71325bd..34437a0 100644 (file)
--- 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.
index 0dc6fae..dbe07e1 100644 (file)
@@ -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);
index 63f5577..4e80f7a 100644 (file)
@@ -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,
index 0b7a056..0136f73 100644 (file)
@@ -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 :*/
index cfb8aac..9988392 100644 (file)
@@ -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)
 {
index f2f65a3..144761e 100644 (file)
@@ -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
 {
@@ -125,6 +141,11 @@ 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);
 
index 4a7ec28..c5527db 100644 (file)
@@ -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,
index 9dad67c..7c00d54 100644 (file)
@@ -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;
 
 /*
  *****
@@ -1754,6 +1764,66 @@ eng_image_animated_frame_set(void *data EINA_UNUSED, void *image, int frame_inde
 }
 
 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)
 {
    int tmp_size;
@@ -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();