evas vg: ++optimization rendering performance. 07/259807/13
authorHermet Park <chuneon.park@samsung.com>
Tue, 15 Jun 2021 03:23:16 +0000 (12:23 +0900)
committerHermet Park <chuneon.park@samsung.com>
Thu, 17 Jun 2021 07:03:04 +0000 (07:03 +0000)
recover to use the tbm-surface to update the texture data from
the tvg canvas. This brings skipping memory copy, improve the
fps around 10 on average.

Change-Id: I6eb54e8b62c88a6475c6750f69f55a50b4a6f566

src/lib/evas/canvas/efl_canvas_vg_object.c
src/lib/evas/canvas/efl_canvas_vg_object.eo
src/lib/evas/canvas/evas_vg_private.h
src/lib/evas/include/evas_private.h
src/modules/evas/engines/gl_generic/evas_engine.c
src/modules/evas/engines/software_generic/evas_engine.c

index 2e7ecef..abb3971 100644 (file)
@@ -95,8 +95,7 @@ _evas_vg_resize(void *data, const Efl_Event *ev)
 {
    Efl_Canvas_Vg_Object_Data *pd = data;
 
-   if (eina_rectangle_is_empty(&pd->viewbox.rect))
-     return;
+   if (eina_rectangle_is_empty(&pd->viewbox.rect)) return;
    _update_vgtree_viewport(ev->object, pd);
 }
 
@@ -260,6 +259,11 @@ _efl_canvas_vg_object_efl_file_file_set(Eo *eo_obj, Efl_Canvas_Vg_Object_Data *p
              evas_cache_vg_entry_del(pd->vg_entry);
              evas_object_change(eo_obj, obj);
              pd->vg_entry = NULL;
+             if (pd->image)
+               {
+                  ENFN->image_free(ENC, pd->image);
+                  pd->image = NULL;
+               }
              evas_object_change(eo_obj, obj);
              pd->changed = EINA_TRUE;
           }
@@ -313,6 +317,11 @@ _efl_canvas_vg_object_efl_file_unload(Eo *eo_obj, Efl_Canvas_Vg_Object_Data *pd)
    evas_cache_vg_entry_del(pd->vg_entry);
    evas_object_change(eo_obj, obj);
    pd->vg_entry = NULL;
+   if (pd->image)
+     {
+        ENFN->image_free(ENC, pd->image);
+        pd->image = NULL;
+     }
 }
 
 EOLIAN static Eina_Bool
@@ -327,8 +336,26 @@ _efl_canvas_vg_object_efl_file_save_save(const Eo *obj, Efl_Canvas_Vg_Object_Dat
 }
 
 EOLIAN static void
+_efl_canvas_vg_object_efl_gfx_entity_visible_set(Eo *eo_obj, Efl_Canvas_Vg_Object_Data *pd, Eina_Bool vis)
+{
+   if (_evas_object_intercept_call(eo_obj, EVAS_OBJECT_INTERCEPT_CB_VISIBLE, 0, vis))  return;
+
+   efl_gfx_entity_visible_set(efl_super(eo_obj, MY_CLASS), vis);
+
+   Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
+
+   if (!vis && pd->image)
+     {
+        ENFN->image_free(ENC, pd->image);
+        pd->image = NULL;
+     }
+}
+
+EOLIAN static void
 _efl_canvas_vg_object_efl_object_invalidate(Eo *eo_obj, Efl_Canvas_Vg_Object_Data *pd)
 {
+   Evas_Object_Protected_Data *obj = efl_data_scope_get(eo_obj, EFL_CANVAS_OBJECT_CLASS);
+
    efl_unref(pd->root);
    pd->root = NULL;
 
@@ -341,17 +368,18 @@ _efl_canvas_vg_object_efl_object_invalidate(Eo *eo_obj, Efl_Canvas_Vg_Object_Dat
 
    evas_cache_vg_entry_del(pd->vg_entry);
 
-   if (pd->tvg_buffer)
-     {
-        free(pd->tvg_buffer);
-        pd->tvg_buffer = NULL;
-     }
    if (pd->tvg_canvas)
      {
         tvg_canvas_clear(pd->tvg_canvas, false);
         tvg_canvas_destroy(pd->tvg_canvas);
      }
 
+   if (pd->image)
+     {
+        ENFN->image_free(ENC, pd->image);
+        pd->image = NULL;
+     }
+
    efl_invalidate(efl_super(eo_obj, MY_CLASS));
 }
 
@@ -372,8 +400,8 @@ _efl_canvas_vg_object_efl_object_constructor(Eo *eo_obj, Efl_Canvas_Vg_Object_Da
    pd->obj = obj;
    pd->root = efl_add_ref(EFL_CANVAS_VG_CONTAINER_CLASS, NULL);
    pd->tvg_canvas = tvg_swcanvas_create();
-   pd->tvg_canvas_size.w = 0;
-   pd->tvg_canvas_size.h = 0;
+   pd->size.w = 0;
+   pd->size.h = 0;
 
 
    return eo_obj;
@@ -402,46 +430,49 @@ _update_scene(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd, Ef
 }
 
 static void
-_render_tvg_buffer_to_screen(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd,
-                             void *engine, void *output, void *context, void *surface,
-                             int x, int y, int w, int h, Eina_Bool do_async)
+_render_image_to_screen(Evas_Object_Protected_Data *obj, Efl_Canvas_Vg_Object_Data *pd,
+                        void *engine, void *output, void *context, void *surface,
+                        int x, int y, Eina_Bool async)
 {
-   Eina_Bool async_unref = EINA_FALSE;
-   Image_Entry *image = NULL;
-
-   if (!pd || !pd->tvg_buffer)
-     return;
-
-   image = ENFN->image_new_from_copied_data(engine,
-                                            pd->tvg_canvas_size.w,
-                                            pd->tvg_canvas_size.h,
-                                            pd->tvg_buffer, 255,
-                                            EVAS_COLORSPACE_ARGB8888);
+   if (!pd || !pd->image) return;
 
-   async_unref = ENFN->image_draw(engine, output, context, surface, image,
-                                  0, 0, w, h, x, y, w, h,
-                                  EINA_TRUE, do_async);
+   ENFN->image_dirty_region(engine, pd->image, 0, 0, pd->size.w, pd->size.h);
 
-   if (do_async && async_unref)
+   Eina_Bool async_unref = ENFN->image_draw(engine, output, context, surface, pd->image, 0, 0,
+                                            pd->size.w, pd->size.h, x, y, pd->size.w, pd->size.h,
+                                            EINA_TRUE, async);
+   if (async && async_unref)
      {
-        evas_cache_image_ref(image);
-        evas_unref_queue_image_put(obj->layer->evas, image);
+        evas_cache_image_ref(pd->image);
+        evas_unref_queue_image_put(obj->layer->evas, pd->image);
      }
+}
+
+static void
+_prepare_render_image(Evas_Object_Protected_Data* obj, Efl_Canvas_Vg_Object_Data *pd, void *engine)
+{
+   if (pd->image) ENFN->image_free(engine, pd->image);
 
-   ENFN->image_free(engine, image);
+   pd->image = ENFN->tvg_image_new(engine, pd->size.w, pd->size.h);
+   if (!pd->image) return;
+
+   int stride = 0;
+   DATA32* pixels = ENFN->tvg_image_acquire(engine, pd->image, &stride);
+
+   tvg_swcanvas_set_target(pd->tvg_canvas, (uint32_t*) pixels, stride, pd->size.w, pd->size.h, TVG_COLORSPACE_ARGB8888);
+
+   ENFN->tvg_image_release(engine, pd->image, pixels);
 }
 
 static void
 _efl_canvas_vg_object_render(Evas_Object *eo_obj EINA_UNUSED,
                              Evas_Object_Protected_Data *obj,
                              void *type_private_data,
-                             void *engine, void *output, void *context, void *surface,
+                             void *engine, void *output EINA_UNUSED, void *context, void *surface EINA_UNUSED,
                              int x, int y, Eina_Bool do_async)
 {
    Efl_Canvas_Vg_Object_Data *pd = type_private_data;
    Eina_Position2D offset = {0, 0};  //Offset after keeping aspect ratio.
-   Eina_Bool updated = pd->changed;
-
    ENFN->context_color_set(engine, context, 255, 255, 255, 255);
    ENFN->context_multiplier_set(engine, context,
                                 obj->cur->cache.clip.r,
@@ -495,7 +526,6 @@ _efl_canvas_vg_object_render(Evas_Object *eo_obj EINA_UNUSED,
                   vg_entry = evas_cache_vg_entry_resize(vg_entry, size.w, size.h);
                   evas_cache_vg_entry_del(pd->vg_entry);
                   pd->vg_entry = vg_entry;
-                  updated = EINA_TRUE;
                }
 
              //update for adjusted pos and size.
@@ -508,38 +538,58 @@ _efl_canvas_vg_object_render(Evas_Object *eo_obj EINA_UNUSED,
           }
      }
 
+   Eina_Bool resized = EINA_FALSE;
+   Eina_Bool prepared = EINA_FALSE;
+
    //Reset canvas size
-   if (pd->tvg_canvas_size.w != w || pd->tvg_canvas_size.h != h)
+   if (pd->size.w != w || pd->size.h != h)
      {
-        pd->tvg_buffer = realloc(pd->tvg_buffer, w * h * sizeof(uint32_t));
-        pd->tvg_canvas_size.w = w;
-        pd->tvg_canvas_size.h = h;
-
-        tvg_swcanvas_set_target(pd->tvg_canvas, pd->tvg_buffer,
-                                w, w, h, TVG_COLORSPACE_ARGB8888);
-        updated = EINA_TRUE;
+        pd->size.w = w;
+        pd->size.h = h;
+        resized = EINA_TRUE;
      }
 
-   if (pd->vg_entry && updated)
+   if (pd->vg_entry && (resized || pd->changed))
      {
         Efl_VG *root = evas_cache_vg_tree_get(pd->vg_entry, pd->frame_idx);
-        if (root) _update_scene(obj, pd, root);
+        if (root)
+          {
+             if (resized && !prepared)
+               {
+                  _prepare_render_image(obj, pd, engine);
+                  prepared = EINA_TRUE;
+               }
+             _update_scene(obj, pd, root);
+          }
      }
 
-   if (pd->user_entry && updated) _update_scene(obj, pd, pd->user_entry->root);
+   if (pd->user_entry && (resized || pd->changed))
+     {
+        if (resized && !prepared)
+          {
+             _prepare_render_image(obj, pd, engine);
+             prepared = EINA_TRUE;
+          }
+        _update_scene(obj, pd, pd->user_entry->root);
+     }
 
    //Render the vector canvas
-   if (updated)
+   if ((resized || pd->changed) && pd->image)
      {
+        DATA32 *pixels = ENFN->tvg_image_acquire(engine, pd->image, NULL);
+
         if (tvg_canvas_draw(pd->tvg_canvas) == TVG_RESULT_SUCCESS)
           tvg_canvas_sync(pd->tvg_canvas);
+
+        ENFN->tvg_image_release(engine, pd->image, pixels);
+
         tvg_canvas_clear(pd->tvg_canvas, EINA_FALSE);
      }
 
-   _render_tvg_buffer_to_screen(obj, pd, engine, output, context, surface,
-                                obj->cur->geometry.x + x + offset.x,
-                                obj->cur->geometry.y + y + offset.y,
-                                w, h, do_async);
+   _render_image_to_screen(obj, pd, engine, output, context, surface,
+                           obj->cur->geometry.x + x + offset.x,
+                           obj->cur->geometry.y + y + offset.y, do_async);
+
    pd->changed = EINA_FALSE;
 }
 
index a81eb63..5931e20 100644 (file)
@@ -83,6 +83,7 @@ class @beta Efl.Canvas.Vg.Object extends Efl.Canvas.Object implements Efl.File,
       Efl.File.unload;
       Efl.File.file { set; }
       Efl.File_Save.save;
+      Efl.Gfx.Entity.visible { set; }
       Efl.Gfx.Frame_Controller.animated { get; }
       Efl.Gfx.Frame_Controller.frame { get; set; }
       Efl.Gfx.Frame_Controller.frame_count { get; }
index 3c31dec..4e71a95 100644 (file)
@@ -53,17 +53,15 @@ struct _Efl_Canvas_Vg_Object_Data
    Evas_Object_Protected_Data *obj;
    Eina_Rect                  fill;
    Eina_Rect                  viewbox;
-   unsigned int               width, height;
    double                     align_x, align_y;
    Efl_Canvas_Vg_Fill_Mode    fill_mode;
    int                        frame_idx;
    void                      *ckeys[2];  //cache keys for first, last frames if animation
+   Tvg_Canvas *tvg_canvas;
+   void* image;                          //engine image that holds the canvas buffer
+   Eina_Size2D size;
 
    Eina_Bool                  changed : 1;
-
-   Tvg_Canvas *tvg_canvas;
-   Eina_Size2D tvg_canvas_size;
-   uint32_t   *tvg_buffer;
 };
 
 struct _Efl_Canvas_Vg_Node_Data
index 5df409a..1d7f794 100755 (executable)
@@ -1097,6 +1097,9 @@ struct _Evas_Func
 
    Ector_Buffer *(*ector_buffer_wrap)    (void *engine, Evas *e, void *engine_image);
    Ector_Buffer *(*ector_buffer_new)     (void *engine, Evas *e, int width, int height, Efl_Gfx_Colorspace cspace, Ector_Buffer_Flag flags);
+   void *(*tvg_image_new)                (void *engine, int widht, int height);
+   void *(*tvg_image_acquire)            (void *engine, void *surface, int *stride);
+   void (*tvg_image_release)             (void *engine, void *surface, DATA32 *pixels);
 
    Evas_Filter_Support (*gfx_filter_supports) (void *engine, Evas_Filter_Command *cmd);
    Eina_Bool (*gfx_filter_process)       (void *engine, Evas_Filter_Command *cmd);
index c9fd544..b988dd4 100755 (executable)
@@ -2749,6 +2749,37 @@ eng_ector_buffer_wrap(void *engine EINA_UNUSED, Evas *evas, void *engine_image)
 //FIXME: Currently Ector GL doens't work properly. Use software instead.
 #include "../software_generic/evas_ector_software.h"
 
+static void*
+eng_tvg_image_new(void *engine, int width, int height)
+{
+   void *surface = eng_image_new_from_copied_data(engine, width, height, NULL, EINA_TRUE, EVAS_COLORSPACE_ARGB8888);
+   if (!surface) return NULL;
+
+   eng_image_content_hint_set(engine, surface, EVAS_IMAGE_CONTENT_HINT_DYNAMIC);
+
+   return surface;
+}
+
+static void*
+eng_tvg_image_acquire(void *engine, void *surface, int *stride)
+{
+   DATA32 *pixels;
+   eng_image_data_get(engine, surface, EINA_TRUE, &pixels, NULL, NULL);
+   if (stride)
+     {
+        int s;
+        eng_image_stride_get(engine, surface, &s);
+        *stride = s / 4;
+     }
+   return pixels;
+}
+
+static void
+eng_tvg_image_release(void *engine, void *surface, DATA32 *pixels)
+{
+   eng_image_data_put(engine, surface, pixels);
+}
+
 static Ector_Buffer *
 eng_ector_buffer_new(void *engine, Evas *evas, int w, int h,
                      Efl_Gfx_Colorspace cspace, Ector_Buffer_Flag flags)
@@ -3379,6 +3410,9 @@ module_open(Evas_Module *em)
 
    ORD(ector_buffer_wrap);
    ORD(ector_buffer_new);
+   ORD(tvg_image_new);
+   ORD(tvg_image_acquire);
+   ORD(tvg_image_release);
    ORD(gfx_filter_supports);
    ORD(gfx_filter_process);
    ORD(font_glyphs_gc_collect);
index 9c07315..fe5fdd6 100755 (executable)
@@ -4356,6 +4356,28 @@ eng_output_idle_flush(void *engine EINA_UNUSED, void *data)
    if (re->outbuf_idle_flush) re->outbuf_idle_flush(re->ob);
 }
 
+static void*
+eng_tvg_image_new(void *engine, int width, int height)
+{
+    return eng_image_new_from_copied_data(engine, width, height, NULL, EINA_TRUE, EVAS_COLORSPACE_ARGB8888);
+}
+
+static void*
+eng_tvg_image_acquire(void *engine EINA_UNUSED, void *surface, int *stride)
+{
+    RGBA_Image *sf = surface;
+    DATA32 *pixels = evas_cache_image_pixels(&sf->cache_entry);
+    if (stride) *stride = sf->cache_entry.w;
+
+    return pixels;
+}
+
+static void
+eng_tvg_image_release(void *engine EINA_UNUSED, void *surface EINA_UNUSED, DATA32 *pixels EINA_UNUSED)
+{
+}
+
+
 // Ector functions
 
 static Ector_Buffer *
@@ -4643,6 +4665,9 @@ static Evas_Func func =
      NULL, // eng_context_flush - software doesn't use it
      eng_ector_buffer_wrap,
      eng_ector_buffer_new,
+     eng_tvg_image_new,
+     eng_tvg_image_acquire,
+     eng_tvg_image_release,
      eng_gfx_filter_supports,
      eng_gfx_filter_process,
    /* FUTURE software generic calls go here */