evas: make pipe rendering faster by forcing it to update region that fit in CPU cache.
authorcedric <cedric@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Sun, 10 Jun 2012 04:58:24 +0000 (04:58 +0000)
committercedric <cedric@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Sun, 10 Jun 2012 04:58:24 +0000 (04:58 +0000)
NOTE: for people using Evas pipe rendering infrastructure. I am interested in reporting
expedite test before and after this patch with the associated type of CPU (number, thread,
cache). Thanks.

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/evas@71887 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

ChangeLog
NEWS
src/lib/engines/common/evas_pipe.c
src/lib/engines/common/evas_pipe.h
src/lib/include/evas_common.h

index 36bf224..b13c5b2 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
         fixes 1 rounding error in text objects that placed ascent in the wrong
         place by 1 pixel for even ascents.
 
+2012-06-10  Cedric Bail
+
+       * Limit the updated region to fit in CPU cache for Pipe rendering.
diff --git a/NEWS b/NEWS
index 82d8fb9..33eb364 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,7 @@ Improvements:
    * Lock less font rendering.
    * Reduce cost of propagating event by limiting the object we explore by using a bouncing box.
    * Don't wake up prepare thread if there is nothing to prepare.
+   * Limit the updated region to fit in CPU cache for Pipe rendering.
 
 Fixes:
    * Add missing files in the tarball.
index 26074ec..37bc12e 100644 (file)
@@ -70,31 +70,29 @@ evas_common_pipe_thread(void *data)
    thinfo = data;
    for (;;)
      {
-        RGBA_Pipe_Thread_Info *info;
+        const RGBA_Pipe_Thread_Info *info;
         RGBA_Pipe *p;
 
         /* wait for start signal */
 // INF(" TH %i START...", thinfo->thread_num);
         pthread_barrier_wait(&(thinfo->barrier[0]));
-        info = thinfo->info;
-// if (info)
-//   {
-//      thinfo->info = NULL;
-//      INF(" TH %i GO", thinfo->thread_num);
-        EINA_INLIST_FOREACH(EINA_INLIST_GET(info->im->cache_entry.pipe), p)
-          {
-             int i;
 
-             for (i = 0; i < p->op_num; i++)
+        EINA_INLIST_FOREACH(thinfo->tasks, info)
+          {
+             EINA_INLIST_FOREACH(EINA_INLIST_GET(info->im->cache_entry.pipe), p)
                {
-                  if (p->op[i].op_func)
-                  p->op[i].op_func(info->im, &(p->op[i]), info);
+                  int i;
+
+                  for (i = 0; i < p->op_num; i++)
+                    {
+                       if (p->op[i].op_func)
+                         p->op[i].op_func(info->im, &(p->op[i]), info);
+                    }
                }
           }
-        free(info);
-//   }
-// INF(" TH %i DONE", thinfo->thread_num);
-        /* send finished signal */
+
+        thinfo->tasks = NULL;
+
         pthread_barrier_wait(&(thinfo->barrier[1]));
      }
    return NULL;
@@ -105,40 +103,61 @@ evas_common_pipe_thread(void *data)
 static int               thread_num = 0;
 static Thinfo            thinfo[TH_MAX];
 static pthread_barrier_t thbarrier[2];
+
+static RGBA_Pipe_Thread_Info *buf = NULL;
+static unsigned int           buf_size = 0;
 #endif
 
 static void
 evas_common_pipe_begin(RGBA_Image *im)
 {
+#define SZ 128
 #ifdef BUILD_PTHREAD
-   int i, y, h;
+   unsigned int x, y, cpu;
+   RGBA_Pipe_Thread_Info *info;
+   unsigned int estimatex, estimatey;
+   unsigned int needed_size;
 
    if (!im->cache_entry.pipe) return;
    if (thread_num == 1) return;
-   y = 0;
-   h = im->cache_entry.h / thread_num;
-   if (h < 1) h = 1;
-   for (i = 0; i < thread_num; i++)
+
+   if (im->cache_entry.w * im->cache_entry.h / thread_num < SZ * SZ)
      {
-        RGBA_Pipe_Thread_Info *info;
-
-//      if (y >= im->cache_entry.h) break;
-        info = calloc(1, sizeof(RGBA_Pipe_Thread_Info));
-        info->im = im;
-        info->x = 0;
-        info->y = y;
-        info->w = im->cache_entry.w;
-        if (i == (thread_num - 1))
-          {
-             info->h = im->cache_entry.h - y;
-          }
-        else
-          {
-             info->h = h;
-          }
-        y += info->h;
-        thinfo[i].info = info;
+        estimatex = im->cache_entry.w;
+        estimatey = im->cache_entry.h / thread_num;
+        if (estimatey == 0) estimatey = 1;
+     }
+   else
+     {
+        estimatex = SZ;
+        estimatey = SZ;
+     }
+
+   needed_size = ((im->cache_entry.w / estimatex) + 1 ) * ((im->cache_entry.h /  estimatey) + 1);
+   if (buf_size < needed_size)
+     {
+        buf = realloc(buf, sizeof (RGBA_Pipe_Thread_Info) * needed_size);
+        buf_size = needed_size;
      }
+
+   info = buf;
+   cpu = 0;
+   for (y = 0; y < im->cache_entry.h; y += estimatey)
+     for (x = 0; x < im->cache_entry.w; x += estimatex)
+       {
+          info->im = im;
+          info->x = x;
+          info->y = y;
+          info->w = (x + estimatex > im->cache_entry.w) ? im->cache_entry.w - x : estimatex;
+          info->h = (y + estimatey > im->cache_entry.h) ? im->cache_entry.h - y : estimatey;
+
+          thinfo[cpu].tasks = eina_inlist_prepend((void*) thinfo[cpu].tasks, EINA_INLIST_GET(info));
+          cpu++;
+          if (cpu >= (unsigned int) thread_num) cpu = 0;
+
+          info++;
+       }
+
    /* tell worker threads to start */
    pthread_barrier_wait(&(thbarrier[0]));
 #endif
@@ -157,20 +176,27 @@ evas_common_pipe_flush(RGBA_Image *im)
    else
 #endif
      {
-       RGBA_Pipe *p;
-       int i;
-       
-       /* process pipe - 1 thead */
-       for (p = im->cache_entry.pipe; p; p = (RGBA_Pipe *)(EINA_INLIST_GET(p))->next)
-        {
-          for (i = 0; i < p->op_num; i++)
-            {
-              if (p->op[i].op_func)
-                {
-                  p->op[i].op_func(im, &(p->op[i]), NULL);
-                }
-            }
-        }
+        RGBA_Pipe_Thread_Info info;
+        RGBA_Pipe *p;
+        int i;
+
+        info.im = im;
+        info.x = 0;
+        info.y = 0;
+        info.w = im->cache_entry.w;
+        info.h = im->cache_entry.h;
+
+        /* process pipe - 1 thead */
+        for (p = im->cache_entry.pipe; p; p = (RGBA_Pipe *)(EINA_INLIST_GET(p))->next)
+          {
+             for (i = 0; i < p->op_num; i++)
+               {
+                  if (p->op[i].op_func)
+                    {
+                       p->op[i].op_func(im, &(p->op[i]), &info);
+                    }
+               }
+          }
      }
 
    evas_common_cpu_end_opt();
@@ -208,24 +234,15 @@ evas_common_pipe_free(RGBA_Image *im)
 /* draw ops */
 /**************** RECT ******************/
 static void
-evas_common_pipe_rectangle_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Thread_Info *info)
+evas_common_pipe_rectangle_draw_do(RGBA_Image *dst, const RGBA_Pipe_Op *op, const RGBA_Pipe_Thread_Info *info)
 {
-   if (info)
-     {
-        RGBA_Draw_Context context;
+   RGBA_Draw_Context context;
 
-        memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
-        evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
-        evas_common_rectangle_draw(dst, &(context),
-               op->op.rect.x, op->op.rect.y,
-               op->op.rect.w, op->op.rect.h);
-     }
-   else
-     {
-        evas_common_rectangle_draw(dst, &(op->context),
-               op->op.rect.x, op->op.rect.y,
-               op->op.rect.w, op->op.rect.h);
-     }
+   memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
+   evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
+   evas_common_rectangle_draw(dst, &(context),
+                              op->op.rect.x, op->op.rect.y,
+                              op->op.rect.w, op->op.rect.h);
 }
 
 EAPI void
@@ -247,24 +264,15 @@ evas_common_pipe_rectangle_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, i
 
 /**************** LINE ******************/
 static void
-evas_common_pipe_line_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Thread_Info *info)
+evas_common_pipe_line_draw_do(RGBA_Image *dst, const RGBA_Pipe_Op *op, const RGBA_Pipe_Thread_Info *info)
 {
-   if (info)
-     {
-        RGBA_Draw_Context context;
+   RGBA_Draw_Context context;
 
-        memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
-        evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
-        evas_common_line_draw(dst, &(context),
-               op->op.line.x0, op->op.line.y0,
-               op->op.line.x1, op->op.line.y1);
-     }
-   else
-     {
-        evas_common_line_draw(dst, &(op->context),
-               op->op.line.x0, op->op.line.y0,
-               op->op.line.x1, op->op.line.y1);
-     }
+   memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
+   evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
+   evas_common_line_draw(dst, &(context),
+                         op->op.line.x0, op->op.line.y0,
+                         op->op.line.x1, op->op.line.y1);
 }
 
 EAPI void
@@ -301,22 +309,14 @@ evas_common_pipe_op_poly_free(RGBA_Pipe_Op *op)
 }
 
 static void
-evas_common_pipe_poly_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Thread_Info *info)
+evas_common_pipe_poly_draw_do(RGBA_Image *dst, const RGBA_Pipe_Op *op, const RGBA_Pipe_Thread_Info *info)
 {
-   if (info)
-     {
-        RGBA_Draw_Context context;
+   RGBA_Draw_Context context;
 
-        memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
-        evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
-        evas_common_polygon_draw(dst, &(context),
-                     op->op.poly.points, 0, 0);
-     }
-   else
-     {
-        evas_common_polygon_draw(dst, &(op->context),
-                     op->op.poly.points, 0, 0);
-     }
+   memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
+   evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
+   evas_common_polygon_draw(dst, &(context),
+                            op->op.poly.points, 0, 0);
 }
 
 EAPI void
@@ -355,20 +355,13 @@ evas_common_pipe_op_text_free(RGBA_Pipe_Op *op)
 }
 
 static void
-evas_common_pipe_text_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Thread_Info *info)
+evas_common_pipe_text_draw_do(RGBA_Image *dst, const RGBA_Pipe_Op *op, const RGBA_Pipe_Thread_Info *info)
 {
-   if (info)
-     {
-        RGBA_Draw_Context context;
+   RGBA_Draw_Context context;
 
-        memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
-        evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
-        evas_common_font_draw(dst, &(context), op->op.text.x, op->op.text.y, op->op.text.intl_props);
-     }
-   else
-     {
-        evas_common_font_draw(dst, &(op->context), op->op.text.x, op->op.text.y, op->op.text.intl_props);
-     }
+   memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
+   evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
+   evas_common_font_draw(dst, &(context), op->op.text.x, op->op.text.y, op->op.text.intl_props);
 }
 
 EAPI void
@@ -402,99 +395,53 @@ evas_common_pipe_op_image_free(RGBA_Pipe_Op *op)
 }
 
 static void
-evas_common_pipe_image_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Thread_Info *info)
+evas_common_pipe_image_draw_do(RGBA_Image *dst, const RGBA_Pipe_Op *op, const RGBA_Pipe_Thread_Info *info)
 {
-   if (info)
-     {
-        RGBA_Draw_Context context;
+   RGBA_Draw_Context context;
 
-        memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
-        evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
+   memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
+   evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
 
 #ifdef SCALECACHE
-        evas_common_rgba_image_scalecache_do((Image_Entry *)(op->op.image.src),
-                                             dst, &(context),
-                                             op->op.image.smooth,
-                                             op->op.image.sx,
-                                             op->op.image.sy,
-                                             op->op.image.sw,
-                                             op->op.image.sh,
-                                             op->op.image.dx,
-                                             op->op.image.dy,
-                                             op->op.image.dw,
-                                             op->op.image.dh);
+   evas_common_rgba_image_scalecache_do((Image_Entry *)(op->op.image.src),
+                                        dst, &(context),
+                                        op->op.image.smooth,
+                                        op->op.image.sx,
+                                        op->op.image.sy,
+                                        op->op.image.sw,
+                                        op->op.image.sh,
+                                        op->op.image.dx,
+                                        op->op.image.dy,
+                                        op->op.image.dw,
+                                        op->op.image.dh);
 #else
-        if (op->op.image.smooth)
-          {
-             evas_common_scale_rgba_in_to_out_clip_smooth(op->op.image.src,
-                           dst, &(context),
-                           op->op.image.sx,
-                           op->op.image.sy,
-                           op->op.image.sw,
-                           op->op.image.sh,
-                           op->op.image.dx,
-                           op->op.image.dy,
-                           op->op.image.dw,
-                           op->op.image.dh);
-          }
-        else
-          {
-             evas_common_scale_rgba_in_to_out_clip_sample(op->op.image.src,
-                           dst, &(context),
-                           op->op.image.sx,
-                           op->op.image.sy,
-                           op->op.image.sw,
-                           op->op.image.sh,
-                           op->op.image.dx,
-                           op->op.image.dy,
-                           op->op.image.dw,
-                           op->op.image.dh);
-                   }
-#endif
+   if (op->op.image.smooth)
+     {
+        evas_common_scale_rgba_in_to_out_clip_smooth(op->op.image.src,
+                                                     dst, &(context),
+                                                     op->op.image.sx,
+                                                     op->op.image.sy,
+                                                     op->op.image.sw,
+                                                     op->op.image.sh,
+                                                     op->op.image.dx,
+                                                     op->op.image.dy,
+                                                     op->op.image.dw,
+                                                     op->op.image.dh);
      }
    else
      {
-#ifdef SCALECACHE
-        evas_common_rgba_image_scalecache_do((Image_Entry *)(op->op.image.src),
-                                             dst, &(op->context),
-                                             op->op.image.smooth,
-                                             op->op.image.sx,
-                                             op->op.image.sy,
-                                             op->op.image.sw,
-                                             op->op.image.sh,
-                                             op->op.image.dx,
-                                             op->op.image.dy,
-                                             op->op.image.dw,
-                                             op->op.image.dh);
-#else
-        if (op->op.image.smooth)
-          {
-             evas_common_scale_rgba_in_to_out_clip_smooth(op->op.image.src,
-                                 dst, &(op->context),
-                                 op->op.image.sx,
-                                 op->op.image.sy,
-                                 op->op.image.sw,
-                                 op->op.image.sh,
-                                 op->op.image.dx,
-                                 op->op.image.dy,
-                                 op->op.image.dw,
-                                 op->op.image.dh);
-          }
-        else
-                {
-             evas_common_scale_rgba_in_to_out_clip_sample(op->op.image.src,
-                                 dst, &(op->context),
-                                 op->op.image.sx,
-                                 op->op.image.sy,
-                                 op->op.image.sw,
-                                 op->op.image.sh,
-                                 op->op.image.dx,
-                                 op->op.image.dy,
-                                 op->op.image.dw,
-                                 op->op.image.dh);
-           }
-#endif
+        evas_common_scale_rgba_in_to_out_clip_sample(op->op.image.src,
+                                                     dst, &(context),
+                                                     op->op.image.sx,
+                                                     op->op.image.sy,
+                                                     op->op.image.sw,
+                                                     op->op.image.sh,
+                                                     op->op.image.dx,
+                                                     op->op.image.dy,
+                                                     op->op.image.dw,
+                                                     op->op.image.dh);
      }
+#endif
 }
 
 EAPI void
@@ -540,25 +487,16 @@ evas_common_pipe_op_map_free(RGBA_Pipe_Op *op)
 }
 
 static void
-evas_common_pipe_map_draw_do(RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Thread_Info *info)
+evas_common_pipe_map_draw_do(RGBA_Image *dst, const RGBA_Pipe_Op *op, const RGBA_Pipe_Thread_Info *info)
 {
-   if (info)
-     {
-       RGBA_Draw_Context context;
+   RGBA_Draw_Context context;
 
-       memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
-       evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
+   memcpy(&(context), &(op->context), sizeof(RGBA_Draw_Context));
+   evas_common_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
 
-       evas_common_map_rgba(op->op.map.src, dst,
-                             &context, op->op.map.npoints, op->op.map.p,
-                             op->op.map.smooth, op->op.map.level);
-     }
-   else
-     {
-       evas_common_map_rgba(op->op.map.src, dst,
-                             &(op->context), op->op.map.npoints, op->op.map.p,
-                             op->op.map.smooth, op->op.map.level);
-     }
+   evas_common_map_rgba(op->op.map.src, dst,
+                        &context, op->op.map.npoints, op->op.map.p,
+                        op->op.map.smooth, op->op.map.level);
 }
 
 EAPI void
@@ -605,7 +543,7 @@ evas_common_pipe_map_render(RGBA_Image *root)
   /* Map imply that we need to process them recursively first. */
   for (p = root->cache_entry.pipe; p; p = (RGBA_Pipe *)(EINA_INLIST_GET(p))->next)
     {
-      for (i = 0; i < p->op_num; i++) 
+      for (i = 0; i < p->op_num; i++)
        {
          if (p->op[i].op_func == evas_common_pipe_map_draw_do)
            {
@@ -668,7 +606,7 @@ evas_common_pipe_load(void *data)
        {
            Evas_Text_Props *text_props;
            RGBA_Font_Int *fi;
-         
+
            LKL(text_task_mutex);
            fi = eina_list_data_get(text_task);
            text_task = eina_list_remove_list(text_task, text_task);
@@ -686,7 +624,7 @@ evas_common_pipe_load(void *data)
              }
        }
 
-      /* send finished signal */    
+      /* send finished signal */
       pthread_barrier_wait(&(tinfo->barrier[1]));
     }
 
@@ -742,7 +680,7 @@ evas_common_pipe_init(void)
             CPU_SET(i % cpunum, &cpu);
             pthread_attr_setaffinity_np(&attr, sizeof(cpu), &cpu);
             thinfo[i].thread_num = i;
-            thinfo[i].info = NULL;
+            thinfo[i].tasks = NULL;
             thinfo[i].barrier = thbarrier;
             /* setup initial locks */
             pthread_create(&(thinfo[i].thread_id), &attr,
@@ -762,7 +700,7 @@ evas_common_pipe_init(void)
             CPU_SET(i % cpunum, &cpu);
             pthread_attr_setaffinity_np(&attr, sizeof(cpu), &cpu);
             task_thinfo[i].thread_num = i;
-            task_thinfo[i].info = NULL;
+            task_thinfo[i].tasks = NULL;
             task_thinfo[i].barrier = task_thbarrier;
             /* setup initial locks */
             pthread_create(&(task_thinfo[i].thread_id), &attr,
@@ -846,7 +784,7 @@ evas_common_pipe_map_begin(RGBA_Image *root)
          if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
            evas_cache_image_load_data(&im->cache_entry);
          evas_common_image_colorspace_normalize(im);
-         
+
          im->flags &= ~RGBA_IMAGE_TODO_LOAD;
        }
     }
index 4bc6572..42531e1 100644 (file)
@@ -10,7 +10,7 @@ typedef struct _Thinfo
    int                    thread_num;
    pthread_t              thread_id;
    pthread_barrier_t     *barrier;
-   RGBA_Pipe_Thread_Info *info;
+   const Eina_Inlist     *tasks;
 } Thinfo;
 #endif
 
index 70088fe..b60dde0 100644 (file)
@@ -726,7 +726,7 @@ struct _RGBA_Draw_Context
 struct _RGBA_Pipe_Op
 {
    RGBA_Draw_Context         context;
-   void                    (*op_func) (RGBA_Image *dst, RGBA_Pipe_Op *op, RGBA_Pipe_Thread_Info *info);
+   void                    (*op_func) (RGBA_Image *dst, const RGBA_Pipe_Op *op, const RGBA_Pipe_Thread_Info *info);
    void                    (*free_func) (RGBA_Pipe_Op *op);
 
    union {
@@ -770,6 +770,7 @@ struct _RGBA_Pipe
 
 struct _RGBA_Pipe_Thread_Info
 {
+   EINA_INLIST;
    RGBA_Image *im;
    int         x, y, w, h;
 };