ector: add ability to run task in another thread during preparation stage.

This commit is contained in:
Cedric Bail 2017-09-16 17:43:18 -07:00
parent aec79f9d0d
commit dd297854d1
2 changed files with 203 additions and 3 deletions

View File

@ -7,6 +7,16 @@
#include "../ector_private.h"
typedef struct _Ector_Software_Surface_Data Ector_Software_Surface_Data;
typedef struct _Ector_Software_Thread Ector_Software_Thread;
struct _Ector_Software_Thread
{
Eina_Thread_Queue *queue;
Eina_Thread thread;
SW_FT_Raster raster;
SW_FT_Stroker stroker;
};
// Gradient related structure
typedef struct _Software_Gradient_Linear_Data
@ -118,19 +128,26 @@ void ector_software_rasterizer_clip_shape_set(Software_Rasterizer *rasterizer, S
Shape_Rle_Data * ector_software_rasterizer_generate_rle_data(Software_Rasterizer *rasterizer, SW_FT_Outline *outline);
Shape_Rle_Data * ector_software_rasterizer_generate_stroke_rle_data(Software_Rasterizer *rasterizer, SW_FT_Outline *outline, Eina_Bool closePath);
Shape_Rle_Data * ector_software_rasterizer_generate_rle_data(Ector_Software_Thread *thread, Software_Rasterizer *rasterizer, SW_FT_Outline *outline);
Shape_Rle_Data * ector_software_rasterizer_generate_stroke_rle_data(Ector_Software_Thread *thread, Software_Rasterizer *rasterizer, SW_FT_Outline *outline, Eina_Bool closePath);
void ector_software_rasterizer_draw_rle_data(Software_Rasterizer *rasterizer, int x, int y, uint32_t mul_col, Efl_Gfx_Render_Op op, Shape_Rle_Data* rle);
void ector_software_rasterizer_destroy_rle_data(Shape_Rle_Data *rle);
// Gradient Api
void update_color_table(Ector_Renderer_Software_Gradient_Data *gdata);
void destroy_color_table(Ector_Renderer_Software_Gradient_Data *gdata);
void fetch_linear_gradient(uint32_t *buffer, Span_Data *data, int y, int x, int length);
void fetch_radial_gradient(uint32_t *buffer, Span_Data *data, int y, int x, int length);
void ector_software_thread_init(Ector_Software_Thread *thread);
void ector_software_thread_shutdown(Ector_Software_Thread *thread);
typedef void (*Ector_Thread_Worker_Cb)(void *data, Ector_Software_Thread *thread);
void ector_software_wait(Ector_Thread_Worker_Cb cb, Eina_Free_Cb done, void *data);
void ector_software_schedule(Ector_Thread_Worker_Cb cb, Eina_Free_Cb done, void *data);
#endif

View File

@ -10,6 +10,185 @@
#define MY_CLASS ECTOR_SOFTWARE_SURFACE_CLASS
typedef struct _Ector_Software_Task Ector_Software_Task;
struct _Ector_Software_Task
{
Eina_Thread_Queue_Msg member;
Ector_Thread_Worker_Cb cb;
Eina_Free_Cb done;
void *data;
};
static int count_init = 0;
static unsigned int current = 0;
static unsigned int cpu_core = 0;
static Ector_Software_Thread *ths = NULL;
static Eina_Thread_Queue *render_queue = NULL;
static Ector_Software_Thread render_thread;
static void *
_prepare_process(void *data, Eina_Thread t)
{
Ector_Software_Thread *th = data;
eina_thread_name_set(t, "Ector Preparing Thread");
do
{
Ector_Software_Task *task, todo;
void *ref;
task = eina_thread_queue_wait(th->queue, &ref);
if (!task) break ;
todo.cb = task->cb;
todo.data = task->data;
todo.done = task->done;
eina_thread_queue_wait_done(th->queue, ref);
if (!todo.cb) break ;
todo.cb(todo.data, th);
task = eina_thread_queue_send(render_queue, sizeof (Ector_Software_Task), &ref);
task->cb = todo.cb;
task->data = todo.data;
task->done = todo.done;
eina_thread_queue_send_done(render_queue, ref);
}
while (1);
return th;
}
static void
_ector_software_init(void)
{
int cpu, i;
if (count_init++) return ;
cpu = eina_cpu_count() - 1;
if (cpu < 1)
{
render_thread.queue = NULL;
ector_software_thread_init(&render_thread);
return ;
}
cpu = cpu > 8 ? 8 : cpu;
cpu_core = cpu;
render_queue = eina_thread_queue_new();
ths = malloc(sizeof(Ector_Software_Thread) * cpu);
for (i = 0; i < cpu; i++)
{
Ector_Software_Thread *t;
t = &ths[i];
t->queue = eina_thread_queue_new();
if (!eina_thread_create(&t->thread, EINA_THREAD_NORMAL, -1,
_prepare_process, t))
{
eina_thread_queue_free(t->queue);
t->queue = NULL;
}
}
}
static void
_ector_software_shutdown(void)
{
Ector_Software_Thread *t;
unsigned int i;
if (!--count_init) return ;
if (!ths) return ;
for (i = 0; i < cpu_core; i++)
{
Ector_Software_Task *task;
void *ref;
t = &ths[i];
task = eina_thread_queue_send(t->queue, sizeof (Ector_Software_Task), &ref);
task->cb = NULL;
task->data = NULL;
eina_thread_queue_send_done(t->queue, ref);
eina_thread_join(t->thread);
eina_thread_queue_free(t->queue);
}
eina_thread_queue_free(render_queue);
render_queue = NULL;
free(ths);
ths = NULL;
}
void
ector_software_schedule(Ector_Thread_Worker_Cb cb, Eina_Free_Cb done, void *data)
{
Ector_Software_Thread *t;
Ector_Software_Task *task;
void *ref;
// Not enough CPU, doing it inline in the rendering thread
if (!ths) return ;
t = &ths[current];
current = (current + 1) % cpu_core;
task = eina_thread_queue_send(t->queue, sizeof (Ector_Software_Task), &ref);
task->cb = cb;
task->done = done;
task->data = data;
eina_thread_queue_send_done(t->queue, ref);
}
// Do not call this function if the done function has already called
void
ector_software_wait(Ector_Thread_Worker_Cb cb, Eina_Free_Cb done, void *data)
{
Ector_Software_Task *task, covering;
// First handle case with just inlined prepare code call inside the rendering thread
if (!ths)
{
render_thread.thread = eina_thread_self();
cb(data, &render_thread);
done(data);
return ;
}
// We don't know which task is going to be done first, so
// we iterate until we find ourself back and trigger all
// the done call along the way.
do
{
void *ref;
task = eina_thread_queue_wait(render_queue, &ref);
if (!task) break;
covering.cb = task->cb;
covering.done = task->done;
covering.data = task->data;
eina_thread_queue_wait_done(render_queue, ref);
covering.done(covering.data);
}
while (covering.cb != cb ||
covering.done != done ||
covering.data != data);
}
static Ector_Renderer *
_ector_software_surface_ector_surface_renderer_factory_new(Eo *obj,
Ector_Software_Surface_Data *pd EINA_UNUSED,
@ -29,6 +208,8 @@ _ector_software_surface_ector_surface_renderer_factory_new(Eo *obj,
static Eo *
_ector_software_surface_efl_object_constructor(Eo *obj, Ector_Software_Surface_Data *pd)
{
_ector_software_init();
obj = efl_constructor(efl_super(obj, MY_CLASS));
pd->rasterizer = (Software_Rasterizer *) calloc(1, sizeof(Software_Rasterizer));
ector_software_rasterizer_init(pd->rasterizer);
@ -44,6 +225,8 @@ _ector_software_surface_efl_object_destructor(Eo *obj, Ector_Software_Surface_Da
free(pd->rasterizer);
pd->rasterizer = NULL;
efl_destructor(efl_super(obj, ECTOR_SOFTWARE_SURFACE_CLASS));
_ector_software_shutdown();
}
static void