From 274c9159c9da634f8957689e5e1b25ca4b588583 Mon Sep 17 00:00:00 2001 From: Leandro Pereira Date: Mon, 17 Dec 2012 21:27:07 +0000 Subject: [PATCH] evas: Use refcounted glyph arrays This is in preparation for threaded render landing: the render thread will hold a reference to a text object's glyphs while it hasn't been rendered yet (and will drop that reference after drawing). This changes the internal API a little bit (evas_common_font_rgba_draw() now takes an Evas_Glyph_Array instead of an Evas_Text_Props). SVN revision: 81183 --- src/lib/evas/common/evas_font.h | 8 +- src/lib/evas/common/evas_font_draw.c | 283 ++++++++++++++---- src/lib/evas/common/evas_text_utils.c | 11 +- src/lib/evas/common/evas_text_utils.h | 16 +- src/modules/evas/engines/gl_x11/evas_engine.c | 2 +- .../engines/software_generic/evas_engine.c | 4 +- 6 files changed, 255 insertions(+), 69 deletions(-) diff --git a/src/lib/evas/common/evas_font.h b/src/lib/evas/common/evas_font.h index b259e63c8c..5ea15bc6c2 100644 --- a/src/lib/evas/common/evas_font.h +++ b/src/lib/evas/common/evas_font.h @@ -17,11 +17,11 @@ EAPI int evas_common_font_max_descent_get (RGBA_Font *fn); EAPI int evas_common_font_get_line_advance (RGBA_Font *fn); /* draw */ +typedef void (*Evas_Common_Font_Draw_Cb)(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, Evas_Glyph_Array *glyphs, RGBA_Gfx_Func func, int ext_x, int ext_y, int ext_w, int ext_h, int im_w, int im_h); -typedef void (*Evas_Common_Font_Draw_Cb)(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, const Evas_Text_Props *text_props, RGBA_Gfx_Func func, int ext_x, int ext_y, int ext_w, int ext_h, int im_w, int im_h); - -EAPI void evas_common_font_draw_cb (RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, const Evas_Text_Props *intl_props, Evas_Common_Font_Draw_Cb cb); -EAPI void evas_common_font_draw (RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, const Evas_Text_Props *intl_props); +EAPI void evas_common_font_draw_cb (RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, Evas_Glyph_Array *glyphs, Evas_Common_Font_Draw_Cb cb); +EAPI void evas_common_font_draw (RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, Evas_Glyph_Array *glyphs); +EAPI void evas_common_font_rgba_draw (RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, Evas_Glyph_Array *glyphs, RGBA_Gfx_Func func, int ext_x, int ext_y, int ext_w, int ext_h, int im_w, int im_h); EAPI int evas_common_font_glyph_search (RGBA_Font *fn, RGBA_Font_Int **fi_ret, Eina_Unicode gl); EAPI RGBA_Font_Glyph *evas_common_font_int_cache_glyph_get (RGBA_Font_Int *fi, FT_UInt index); EAPI Eina_Bool evas_common_font_int_cache_glyph_render(RGBA_Font_Glyph *fg); diff --git a/src/lib/evas/common/evas_font_draw.c b/src/lib/evas/common/evas_font_draw.c index 784884270e..8bc57a3c50 100644 --- a/src/lib/evas/common/evas_font_draw.c +++ b/src/lib/evas/common/evas_font_draw.c @@ -29,32 +29,29 @@ evas_common_font_draw_init(void) */ static void evas_common_font_draw_internal(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, - const Evas_Text_Props *text_props, RGBA_Gfx_Func func, int ext_x, int ext_y, int ext_w, + Evas_Glyph_Array *glyphs, RGBA_Gfx_Func func, int ext_x, int ext_y, int ext_w, int ext_h, int im_w, int im_h EINA_UNUSED) { DATA32 *im; - Evas_Glyph *glyphs; - unsigned int length; - unsigned int it; + Evas_Glyph *glyph; + + if (!glyphs) return; + if (!glyphs->array) return; im = dst->image.data; - if (!text_props->glyphs) return ; - - glyphs = text_props->glyphs; - length = text_props->glyphs_length; - for (it = 0; it < length; ++it, ++glyphs) + EINA_INARRAY_FOREACH(glyphs->array, glyph) { RGBA_Font_Glyph *fg; int chr_x, chr_y; - fg = glyphs->fg; + fg = glyph->fg; /* FIXME: Why was that moved out of prepare ? This increase cache miss. */ - glyphs->coord.w = fg->glyph_out->bitmap.width; - glyphs->coord.h = fg->glyph_out->bitmap.rows; - glyphs->j = fg->glyph_out->bitmap.pitch; - glyphs->data = fg->glyph_out->bitmap.buffer; + glyph->coord.w = fg->glyph_out->bitmap.width; + glyph->coord.h = fg->glyph_out->bitmap.rows; + glyph->j = fg->glyph_out->bitmap.pitch; + glyph->data = fg->glyph_out->bitmap.buffer; if (dc->font_ext.func.gl_new) { @@ -63,19 +60,19 @@ evas_common_font_draw_internal(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, in fg->ext_dat_free = dc->font_ext.func.gl_free; } - chr_x = x + glyphs->coord.x/* EVAS_FONT_WALK_PEN_X + EVAS_FONT_WALK_X_OFF + EVAS_FONT_WALK_X_BEAR */; - chr_y = y + glyphs->coord.y/* EVAS_FONT_WALK_PEN_Y + EVAS_FONT_WALK_Y_OFF + EVAS_FONT_WALK_Y_BEAR */; + chr_x = x + glyph->coord.x; + chr_y = y + glyph->coord.y; if (chr_x < (ext_x + ext_w)) { DATA8 *data; int i, j, w, h; - data = glyphs->data; - j = glyphs->j; - w = glyphs->coord.w; + data = glyph->data; + j = glyph->j; + w = glyph->coord.w; if (j < w) j = w; - h = glyphs->coord.h; + h = glyph->coord.h; #ifdef HAVE_PIXMAN # ifdef PIXMAN_FONT @@ -225,27 +222,197 @@ evas_common_font_draw_internal(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, in } } +EAPI void +evas_common_font_rgba_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, Evas_Glyph_Array *glyphs, RGBA_Gfx_Func func, int ext_x, int ext_y, int ext_w, int ext_h, int im_w, int im_h EINA_UNUSED) +{ + DATA32 *im; + Evas_Glyph *glyph; + + if (!glyphs) return; + if (!glyphs->array) return; + + im = dst->image.data; + + EINA_INARRAY_FOREACH(glyphs->array, glyph) + { + RGBA_Font_Glyph *fg; + int chr_x, chr_y; + + fg = glyph->fg; + + /* FIXME: Why was that moved out of prepare ? This increase cache miss. */ + glyph->coord.w = fg->glyph_out->bitmap.width; + glyph->coord.h = fg->glyph_out->bitmap.rows; + glyph->j = fg->glyph_out->bitmap.pitch; + glyph->data = fg->glyph_out->bitmap.buffer; + + if (dc->font_ext.func.gl_new) + { + /* extension calls */ + fg->ext_dat = dc->font_ext.func.gl_new(dc->font_ext.data, fg); + fg->ext_dat_free = dc->font_ext.func.gl_free; + } + + chr_x = x + glyph->coord.x; + chr_y = y + glyph->coord.y; + + if (chr_x < (ext_x + ext_w)) + { + DATA8 *data; + int i, j, w, h; + + data = glyph->data; + j = glyph->j; + w = glyph->coord.w; + if (j < w) j = w; + h = glyph->coord.h; + + if ((j > 0) && (chr_x + w > ext_x)) + { + if ((fg->ext_dat) && (dc->font_ext.func.gl_draw)) + { + /* ext glyph draw */ + dc->font_ext.func.gl_draw(dc->font_ext.data, + (void *)dst, + dc, fg, chr_x, + y - (chr_y - y)); + } + else + { + if ((fg->glyph_out->bitmap.num_grays == 256) && + (fg->glyph_out->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY)) + { + for (i = 0; i < h; i++) + { + int dx, dy; + int in_x, in_w; + + in_x = 0; + in_w = 0; + dx = chr_x; + dy = y - (chr_y - i - y); + + if ((dx < (ext_x + ext_w)) && + (dy >= (ext_y)) && + (dy < (ext_y + ext_h))) + { + if (dx + w > (ext_x + ext_w)) + in_w += (dx + w) - (ext_x + ext_w); + if (dx < ext_x) + { + in_w += ext_x - dx; + in_x = ext_x - dx; + dx = ext_x; + } + if (in_w < w) + { + func(NULL, data + (i * j) + in_x, dc->col.col, + im + (dy * im_w) + dx, w - in_w); + } + } + } + } + else + { + DATA8 *tmpbuf = NULL, *dp, *tp, bits; + int bi, bj; + const DATA8 bitrepl[2] = {0x0, 0xff}; + + tmpbuf = alloca(w); + for (i = 0; i < h; i++) + { + int dx, dy; + int in_x, in_w, end; + + in_x = 0; + in_w = 0; + dx = chr_x; + dy = y - (chr_y - i - y); + + tp = tmpbuf; + dp = data + (i * fg->glyph_out->bitmap.pitch); + for (bi = 0; bi < w; bi += 8) + { + bits = *dp; + if ((w - bi) < 8) end = w - bi; + else end = 8; + for (bj = 0; bj < end; bj++) + { + *tp = bitrepl[(bits >> (7 - bj)) & 0x1]; + tp++; + } + dp++; + } + if ((dx < (ext_x + ext_w)) && + (dy >= (ext_y)) && + (dy < (ext_y + ext_h))) + { + if (dx + w > (ext_x + ext_w)) + in_w += (dx + w) - (ext_x + ext_w); + if (dx < ext_x) + { + in_w += ext_x - dx; + in_x = ext_x - dx; + dx = ext_x; + } + if (in_w < w) + { + func(NULL, tmpbuf + in_x, dc->col.col, + im + (dy * im_w) + dx, w - in_w); + } + } + } + } + } + } + } else break; + } +} + +void +evas_common_font_glyphs_ref(Evas_Glyph_Array *array) +{ + if (!array) return; + + eina_lock_take(&array->lock); + array->refcount++; + eina_lock_release(&array->lock); +} + +void +evas_common_font_glyphs_unref(Evas_Glyph_Array *array) +{ + if (!array) return; + + eina_lock_take(&array->lock); + if (--array->refcount) + { + eina_lock_release(&array->lock); + return; + } + + eina_lock_release(&array->lock); + eina_lock_free(&array->lock); + + eina_inarray_free(array->array); + free(array); +} + EAPI void evas_common_font_draw_prepare(Evas_Text_Props *text_props) { RGBA_Font_Int *fi; RGBA_Font_Glyph *fg; - Evas_Glyph *glyphs; - int glyphs_length; - int glyphs_max; + Eina_Inarray *glyphs; EVAS_FONT_WALK_TEXT_INIT(); fi = text_props->font_instance; if (!fi) return; if (!text_props->changed && text_props->generation == fi->generation && text_props->glyphs) - return ; - - glyphs = text_props->glyphs; - glyphs_length = 0; - glyphs_max = text_props->glyphs_length; - text_props->glyphs_length = 0; + return; + glyphs = eina_inarray_new(sizeof(Evas_Glyph), 32); evas_common_font_int_reload(fi); if (fi->src->current_size != fi->size) @@ -259,7 +426,7 @@ evas_common_font_draw_prepare(Evas_Text_Props *text_props) EVAS_FONT_WALK_TEXT_START() { - Evas_Glyph *glyph; + Evas_Glyph glyph; FT_UInt idx; if (!EVAS_FONT_WALK_IS_VISIBLE) continue; @@ -269,37 +436,43 @@ evas_common_font_draw_prepare(Evas_Text_Props *text_props) if (!fg) continue; if (!fg->glyph_out) evas_common_font_int_cache_glyph_render(fg); - if (glyphs_length + 1 >= glyphs_max) - { - Evas_Glyph *tmp; + glyph.fg = fg; + glyph.idx = idx; + glyph.coord.x = EVAS_FONT_WALK_PEN_X + EVAS_FONT_WALK_X_OFF + EVAS_FONT_WALK_X_BEAR; + glyph.coord.y = EVAS_FONT_WALK_PEN_Y + EVAS_FONT_WALK_Y_OFF + EVAS_FONT_WALK_Y_BEAR; - glyphs_max += 8; - tmp = realloc(glyphs, glyphs_max * sizeof (Evas_Glyph)); - if (!tmp) return ; - glyphs = tmp; - text_props->glyphs = glyphs; - } - - glyph = glyphs + glyphs_length++; - - glyph->fg = fg; - glyph->idx = idx; - glyph->coord.x = EVAS_FONT_WALK_PEN_X + EVAS_FONT_WALK_X_OFF + EVAS_FONT_WALK_X_BEAR; - glyph->coord.y = EVAS_FONT_WALK_PEN_Y + EVAS_FONT_WALK_Y_OFF + EVAS_FONT_WALK_Y_BEAR; + if (eina_inarray_push(glyphs, &glyph) < 0) goto error; } EVAS_FONT_WALK_TEXT_END(); - text_props->glyphs_length = glyphs_length; - text_props->glyphs = glyphs; + /* + * Clearing the reference to the glyph array is fine, since this + * reference is only used to use this from another thread, which is now + * holding the reference. + */ + evas_common_font_glyphs_unref(text_props->glyphs); + + text_props->glyphs = malloc(sizeof(*text_props->glyphs)); + if (!text_props->glyphs) goto error; + text_props->glyphs->refcount = 1; + text_props->glyphs->array = glyphs; + if (!eina_lock_new(&text_props->glyphs->lock)) + CRIT("Could not create glyph array lock"); + /* check if there's a request queue in fi, if so ask cserve2 to render * those glyphs */ text_props->generation = fi->generation; + + return; + +error: + eina_inarray_free(glyphs); } EAPI void -evas_common_font_draw_cb(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, const Evas_Text_Props *text_props, Evas_Common_Font_Draw_Cb cb) +evas_common_font_draw_cb(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, Evas_Glyph_Array *glyphs, Evas_Common_Font_Draw_Cb cb) { static Cutout_Rects *rects = NULL; int ext_x, ext_y, ext_w, ext_h; @@ -342,7 +515,7 @@ evas_common_font_draw_cb(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, c if (!dc->cutout.rects) { - cb(dst, dc, x, y, text_props, + cb(dst, dc, x, y, glyphs, func, ext_x, ext_y, ext_w, ext_h, im_w, im_h); } @@ -358,7 +531,7 @@ evas_common_font_draw_cb(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, c { r = rects->rects + i; evas_common_draw_context_set_clip(dc, r->x, r->y, r->w, r->h); - cb(dst, dc, x, y, text_props, + cb(dst, dc, x, y, glyphs, func, r->x, r->y, r->w, r->h, im_w, im_h); } @@ -368,9 +541,9 @@ evas_common_font_draw_cb(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, c } EAPI void -evas_common_font_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, const Evas_Text_Props *text_props) +evas_common_font_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, int y, Evas_Glyph_Array *glyphs) { - evas_common_font_draw_cb(dst, dc, x, y, text_props, + evas_common_font_draw_cb(dst, dc, x, y, glyphs, evas_common_font_draw_internal); } @@ -392,7 +565,7 @@ evas_common_font_draw_do(const Cutout_Rects *reuse, const Eina_Rectangle *clip, evas_common_draw_context_clip_clip(dc, clip->x, clip->y, clip->w, clip->h); - evas_common_font_draw_internal(dst, dc, x, y, text_props, + evas_common_font_draw_internal(dst, dc, x, y, text_props->glyphs, func, dc->clip.x, dc->clip.y, dc->clip.w, dc->clip.h, @@ -407,7 +580,7 @@ evas_common_font_draw_do(const Cutout_Rects *reuse, const Eina_Rectangle *clip, EINA_RECTANGLE_SET(&area, r->x, r->y, r->w - 1, r->h - 1); if (!eina_rectangle_intersection(&area, clip)) continue ; evas_common_draw_context_set_clip(dc, area.x, area.y, area.w, area.h); - evas_common_font_draw_internal(dst, dc, x, y, text_props, + evas_common_font_draw_internal(dst, dc, x, y, text_props->glyphs, func, area.x, area.y, area.w, area.h, im_w, im_h); } diff --git a/src/lib/evas/common/evas_text_utils.c b/src/lib/evas/common/evas_text_utils.c index eb4fc27b13..71b4fa6ddc 100644 --- a/src/lib/evas/common/evas_text_utils.c +++ b/src/lib/evas/common/evas_text_utils.c @@ -37,7 +37,6 @@ evas_common_text_props_content_copy_and_ref(Evas_Text_Props *dst, { memcpy(dst, src, sizeof(Evas_Text_Props)); dst->glyphs = NULL; - dst->glyphs_length = 0; evas_common_text_props_content_ref(dst); } @@ -68,9 +67,10 @@ evas_common_text_props_content_nofree_unref(Evas_Text_Props *props) props->font_instance = NULL; } - free(props->glyphs); + evas_common_font_glyphs_unref(props->glyphs); + /* After unreferencing the glyph array, a thread will still hold + * a reference, so this can be safely set to NULL. */ props->glyphs = NULL; - props->glyphs_length = 0; if (props->info->glyph) free(props->info->glyph); @@ -90,9 +90,10 @@ evas_common_text_props_content_unref(Evas_Text_Props *props) if (!props->info) return; - free(props->glyphs); + evas_common_font_glyphs_unref(props->glyphs); + /* After unreferencing the glyph array, a thread will still hold + * a reference, so this can be safely set to NULL. */ props->glyphs = NULL; - props->glyphs_length = 0; if (--(props->info->refcount) == 0) { diff --git a/src/lib/evas/common/evas_text_utils.h b/src/lib/evas/common/evas_text_utils.h index 3f615699f8..7ce2526834 100644 --- a/src/lib/evas/common/evas_text_utils.h +++ b/src/lib/evas/common/evas_text_utils.h @@ -19,6 +19,14 @@ typedef enum #define REPLACEMENT_CHAR 0xFFFD typedef struct _Evas_Glyph Evas_Glyph; +typedef struct _Evas_Glyph_Array Evas_Glyph_Array; + +struct _Evas_Glyph_Array +{ + Eina_Inarray *array; + unsigned int refcount; + Eina_Lock lock; +}; struct _Evas_Text_Props { @@ -33,8 +41,7 @@ struct _Evas_Text_Props Evas_Text_Props_Info *info; void *font_instance; - Evas_Glyph *glyphs; - int glyphs_length; + Evas_Glyph_Array *glyphs; int generation; Eina_Bool changed : 1; @@ -61,6 +68,11 @@ struct _Evas_Font_Glyph_Info Evas_Coord pen_after; }; +void +evas_common_font_glyphs_ref(Evas_Glyph_Array *array); +void +evas_common_font_glyphs_unref(Evas_Glyph_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/modules/evas/engines/gl_x11/evas_engine.c b/src/modules/evas/engines/gl_x11/evas_engine.c index 9814d2b44e..35bbd9542c 100644 --- a/src/modules/evas/engines/gl_x11/evas_engine.c +++ b/src/modules/evas/engines/gl_x11/evas_engine.c @@ -2625,7 +2625,7 @@ eng_font_draw(void *data, void *context, void *surface, Evas_Font_Set *font EINA evas_gl_font_texture_free, evas_gl_font_texture_draw); evas_common_font_draw_prepare(intl_props); - evas_common_font_draw(im, context, x, y, intl_props); + evas_common_font_draw(im, context, x, y, intl_props->glyphs); evas_common_draw_context_font_ext_set(context, NULL, NULL, diff --git a/src/modules/evas/engines/software_generic/evas_engine.c b/src/modules/evas/engines/software_generic/evas_engine.c index 9efd35efcf..e16795d06c 100644 --- a/src/modules/evas/engines/software_generic/evas_engine.c +++ b/src/modules/evas/engines/software_generic/evas_engine.c @@ -1260,8 +1260,8 @@ eng_font_draw(void *data EINA_UNUSED, void *context, void *surface, Evas_Font_Se #endif { evas_common_font_draw_prepare(text_props); - evas_common_font_draw(surface, context, x, y, text_props); - evas_common_cpu_end_opt(); + evas_common_font_draw(surface, context, x, y, text_props->glyphs); + evas_common_cpu_end_opt(); } }