evas: make pipe rendering faster by forcing it to update region that fit in CPU cache.

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.


SVN revision: 71887
This commit is contained in:
Cedric BAIL 2012-06-10 04:58:24 +00:00
parent 9d96a8ec62
commit c9cd50983f
5 changed files with 162 additions and 219 deletions

View File

@ -788,3 +788,6 @@
fixes 1 rounding error in text objects that placed ascent in the wrong fixes 1 rounding error in text objects that placed ascent in the wrong
place by 1 pixel for even ascents. place by 1 pixel for even ascents.
2012-06-10 Cedric Bail
* Limit the updated region to fit in CPU cache for Pipe rendering.

View File

@ -7,6 +7,7 @@ Improvements:
* Lock less font rendering. * Lock less font rendering.
* Reduce cost of propagating event by limiting the object we explore by using a bouncing box. * 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. * 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: Fixes:
* Add missing files in the tarball. * Add missing files in the tarball.

View File

@ -70,31 +70,29 @@ evas_common_pipe_thread(void *data)
thinfo = data; thinfo = data;
for (;;) for (;;)
{ {
RGBA_Pipe_Thread_Info *info; const RGBA_Pipe_Thread_Info *info;
RGBA_Pipe *p; RGBA_Pipe *p;
/* wait for start signal */ /* wait for start signal */
// INF(" TH %i START...", thinfo->thread_num); // INF(" TH %i START...", thinfo->thread_num);
pthread_barrier_wait(&(thinfo->barrier[0])); 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) int i;
p->op[i].op_func(info->im, &(p->op[i]), info);
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);
// } thinfo->tasks = NULL;
// INF(" TH %i DONE", thinfo->thread_num);
/* send finished signal */
pthread_barrier_wait(&(thinfo->barrier[1])); pthread_barrier_wait(&(thinfo->barrier[1]));
} }
return NULL; return NULL;
@ -105,40 +103,61 @@ evas_common_pipe_thread(void *data)
static int thread_num = 0; static int thread_num = 0;
static Thinfo thinfo[TH_MAX]; static Thinfo thinfo[TH_MAX];
static pthread_barrier_t thbarrier[2]; static pthread_barrier_t thbarrier[2];
static RGBA_Pipe_Thread_Info *buf = NULL;
static unsigned int buf_size = 0;
#endif #endif
static void static void
evas_common_pipe_begin(RGBA_Image *im) evas_common_pipe_begin(RGBA_Image *im)
{ {
#define SZ 128
#ifdef BUILD_PTHREAD #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 (!im->cache_entry.pipe) return;
if (thread_num == 1) 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++)
{
RGBA_Pipe_Thread_Info *info;
// if (y >= im->cache_entry.h) break; if (im->cache_entry.w * im->cache_entry.h / thread_num < SZ * SZ)
info = calloc(1, sizeof(RGBA_Pipe_Thread_Info)); {
info->im = im; estimatex = im->cache_entry.w;
info->x = 0; estimatey = im->cache_entry.h / thread_num;
info->y = y; if (estimatey == 0) estimatey = 1;
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;
} }
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 */ /* tell worker threads to start */
pthread_barrier_wait(&(thbarrier[0])); pthread_barrier_wait(&(thbarrier[0]));
#endif #endif
@ -157,20 +176,27 @@ evas_common_pipe_flush(RGBA_Image *im)
else else
#endif #endif
{ {
RGBA_Pipe *p; RGBA_Pipe_Thread_Info info;
int i; RGBA_Pipe *p;
int i;
/* process pipe - 1 thead */
for (p = im->cache_entry.pipe; p; p = (RGBA_Pipe *)(EINA_INLIST_GET(p))->next) info.im = im;
{ info.x = 0;
for (i = 0; i < p->op_num; i++) info.y = 0;
{ info.w = im->cache_entry.w;
if (p->op[i].op_func) info.h = im->cache_entry.h;
{
p->op[i].op_func(im, &(p->op[i]), NULL); /* 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(); evas_common_cpu_end_opt();
@ -208,24 +234,15 @@ evas_common_pipe_free(RGBA_Image *im)
/* draw ops */ /* draw ops */
/**************** RECT ******************/ /**************** RECT ******************/
static void 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)); 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_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
evas_common_rectangle_draw(dst, &(context), evas_common_rectangle_draw(dst, &(context),
op->op.rect.x, op->op.rect.y, op->op.rect.x, op->op.rect.y,
op->op.rect.w, op->op.rect.h); 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);
}
} }
EAPI void EAPI void
@ -247,24 +264,15 @@ evas_common_pipe_rectangle_draw(RGBA_Image *dst, RGBA_Draw_Context *dc, int x, i
/**************** LINE ******************/ /**************** LINE ******************/
static void 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)); 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_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
evas_common_line_draw(dst, &(context), evas_common_line_draw(dst, &(context),
op->op.line.x0, op->op.line.y0, op->op.line.x0, op->op.line.y0,
op->op.line.x1, op->op.line.y1); 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);
}
} }
EAPI void EAPI void
@ -301,22 +309,14 @@ evas_common_pipe_op_poly_free(RGBA_Pipe_Op *op)
} }
static void 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)); 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_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
evas_common_polygon_draw(dst, &(context), evas_common_polygon_draw(dst, &(context),
op->op.poly.points, 0, 0); op->op.poly.points, 0, 0);
}
else
{
evas_common_polygon_draw(dst, &(op->context),
op->op.poly.points, 0, 0);
}
} }
EAPI void EAPI void
@ -355,20 +355,13 @@ evas_common_pipe_op_text_free(RGBA_Pipe_Op *op)
} }
static void 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)); 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_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); 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);
}
} }
EAPI void EAPI void
@ -402,99 +395,53 @@ evas_common_pipe_op_image_free(RGBA_Pipe_Op *op)
} }
static void 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)); 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_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
#ifdef SCALECACHE #ifdef SCALECACHE
evas_common_rgba_image_scalecache_do((Image_Entry *)(op->op.image.src), evas_common_rgba_image_scalecache_do((Image_Entry *)(op->op.image.src),
dst, &(context), dst, &(context),
op->op.image.smooth, op->op.image.smooth,
op->op.image.sx, op->op.image.sx,
op->op.image.sy, op->op.image.sy,
op->op.image.sw, op->op.image.sw,
op->op.image.sh, op->op.image.sh,
op->op.image.dx, op->op.image.dx,
op->op.image.dy, op->op.image.dy,
op->op.image.dw, op->op.image.dw,
op->op.image.dh); op->op.image.dh);
#else #else
if (op->op.image.smooth) if (op->op.image.smooth)
{ {
evas_common_scale_rgba_in_to_out_clip_smooth(op->op.image.src, evas_common_scale_rgba_in_to_out_clip_smooth(op->op.image.src,
dst, &(context), dst, &(context),
op->op.image.sx, op->op.image.sx,
op->op.image.sy, op->op.image.sy,
op->op.image.sw, op->op.image.sw,
op->op.image.sh, op->op.image.sh,
op->op.image.dx, op->op.image.dx,
op->op.image.dy, op->op.image.dy,
op->op.image.dw, op->op.image.dw,
op->op.image.dh); 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
} }
else else
{ {
#ifdef SCALECACHE evas_common_scale_rgba_in_to_out_clip_sample(op->op.image.src,
evas_common_rgba_image_scalecache_do((Image_Entry *)(op->op.image.src), dst, &(context),
dst, &(op->context), op->op.image.sx,
op->op.image.smooth, op->op.image.sy,
op->op.image.sx, op->op.image.sw,
op->op.image.sy, op->op.image.sh,
op->op.image.sw, op->op.image.dx,
op->op.image.sh, op->op.image.dy,
op->op.image.dx, op->op.image.dw,
op->op.image.dy, op->op.image.dh);
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
} }
#endif
} }
EAPI void EAPI void
@ -540,25 +487,16 @@ evas_common_pipe_op_map_free(RGBA_Pipe_Op *op)
} }
static void 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)); 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_draw_context_clip_clip(&(context), info->x, info->y, info->w, info->h);
evas_common_map_rgba(op->op.map.src, dst, evas_common_map_rgba(op->op.map.src, dst,
&context, op->op.map.npoints, op->op.map.p, &context, op->op.map.npoints, op->op.map.p,
op->op.map.smooth, op->op.map.level); 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);
}
} }
EAPI void EAPI void
@ -605,7 +543,7 @@ evas_common_pipe_map_render(RGBA_Image *root)
/* Map imply that we need to process them recursively first. */ /* 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 (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) 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; Evas_Text_Props *text_props;
RGBA_Font_Int *fi; RGBA_Font_Int *fi;
LKL(text_task_mutex); LKL(text_task_mutex);
fi = eina_list_data_get(text_task); fi = eina_list_data_get(text_task);
text_task = eina_list_remove_list(text_task, 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])); pthread_barrier_wait(&(tinfo->barrier[1]));
} }
@ -742,7 +680,7 @@ evas_common_pipe_init(void)
CPU_SET(i % cpunum, &cpu); CPU_SET(i % cpunum, &cpu);
pthread_attr_setaffinity_np(&attr, sizeof(cpu), &cpu); pthread_attr_setaffinity_np(&attr, sizeof(cpu), &cpu);
thinfo[i].thread_num = i; thinfo[i].thread_num = i;
thinfo[i].info = NULL; thinfo[i].tasks = NULL;
thinfo[i].barrier = thbarrier; thinfo[i].barrier = thbarrier;
/* setup initial locks */ /* setup initial locks */
pthread_create(&(thinfo[i].thread_id), &attr, pthread_create(&(thinfo[i].thread_id), &attr,
@ -762,7 +700,7 @@ evas_common_pipe_init(void)
CPU_SET(i % cpunum, &cpu); CPU_SET(i % cpunum, &cpu);
pthread_attr_setaffinity_np(&attr, sizeof(cpu), &cpu); pthread_attr_setaffinity_np(&attr, sizeof(cpu), &cpu);
task_thinfo[i].thread_num = i; task_thinfo[i].thread_num = i;
task_thinfo[i].info = NULL; task_thinfo[i].tasks = NULL;
task_thinfo[i].barrier = task_thbarrier; task_thinfo[i].barrier = task_thbarrier;
/* setup initial locks */ /* setup initial locks */
pthread_create(&(task_thinfo[i].thread_id), &attr, 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) if (im->cache_entry.space == EVAS_COLORSPACE_ARGB8888)
evas_cache_image_load_data(&im->cache_entry); evas_cache_image_load_data(&im->cache_entry);
evas_common_image_colorspace_normalize(im); evas_common_image_colorspace_normalize(im);
im->flags &= ~RGBA_IMAGE_TODO_LOAD; im->flags &= ~RGBA_IMAGE_TODO_LOAD;
} }
} }

View File

@ -10,7 +10,7 @@ typedef struct _Thinfo
int thread_num; int thread_num;
pthread_t thread_id; pthread_t thread_id;
pthread_barrier_t *barrier; pthread_barrier_t *barrier;
RGBA_Pipe_Thread_Info *info; const Eina_Inlist *tasks;
} Thinfo; } Thinfo;
#endif #endif

View File

@ -726,7 +726,7 @@ struct _RGBA_Draw_Context
struct _RGBA_Pipe_Op struct _RGBA_Pipe_Op
{ {
RGBA_Draw_Context context; 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); void (*free_func) (RGBA_Pipe_Op *op);
union { union {
@ -770,6 +770,7 @@ struct _RGBA_Pipe
struct _RGBA_Pipe_Thread_Info struct _RGBA_Pipe_Thread_Info
{ {
EINA_INLIST;
RGBA_Image *im; RGBA_Image *im;
int x, y, w, h; int x, y, w, h;
}; };