evas render2 work - begin to make rectangles deal with render 2 basic

infra
This commit is contained in:
Carsten Haitzler 2015-06-02 20:39:57 +09:00
parent 0a2362fa69
commit 25983dcedd
9 changed files with 462 additions and 46 deletions

View File

@ -892,6 +892,22 @@ class Evas.Canvas (Eo.Base, Evas.Common_Interface)
return: bool;
}
render2_updates {
/*@
Render the given Evas canvas using the new rendering infra.
This is experimental and will change over time until noted here.
@return A newly allocated list of updated rectangles of thecanvas
(@c Eina.Rectangle structs). Free this list with
evas_render_updates_free().
@ingroup Evas_Canvas
@since 1.15 */
return: free(own(list<Eina.Rectangle *> *), evas_render_updates_free)
@warn_unused;
}
focus_out {
/*@
Inform to the evas that it lost the focus.

View File

@ -41,6 +41,13 @@ static int evas_object_rectangle_was_opaque(Evas_Object *eo_obj,
Evas_Object_Protected_Data *obj,
void *type_private_data);
static void evas_object_rectangle_render2_walk(Evas_Object *eo_obj,
Evas_Object_Protected_Data *obj,
void *type_private_data,
void *updates,
int offx,
int offy);
#if 0 /* usless calls for a rect object. much more useful for images etc. */
static void evas_object_rectangle_store(Evas_Object *eo_obj);
static void evas_object_rectangle_unstore(Evas_Object *eo_obj);
@ -73,7 +80,8 @@ static const Evas_Object_Func object_func =
NULL,
NULL,
NULL,
NULL
NULL,
evas_object_rectangle_render2_walk
};
/* the actual api call to add a rect */
@ -116,6 +124,75 @@ evas_object_rectangle_init(Evas_Object *eo_obj)
obj->type = o_type;
}
static void
evas_object_rectangle_render2_walk(Evas_Object *eo_obj,
Evas_Object_Protected_Data *obj,
void *type_private_data EINA_UNUSED,
void *updates, int offx, int offy)
{
Eina_Bool visible_is, visible_was;
unsigned int col_prev, col_cur;
if (obj->clip.clipees) return;
visible_is = evas_object_is_visible(eo_obj, obj);
if (!obj->changed) goto nochange;
if ((obj->cur->clipper) && (obj->cur->cache.clip.dirty))
evas_object_clip_recalc(obj->cur->clipper);
visible_was = evas_object_was_visible(eo_obj,obj);
// just became visible or invisible
if (visible_is != visible_was)
{
printf(" UP1 %p - %i %i %ix%i\n", eo_obj,
obj->cur->cache.clip.x, obj->cur->cache.clip.y,
obj->cur->cache.clip.w, obj->cur->cache.clip.h);
evas_common_tilebuf_add_redraw
(updates,
obj->cur->cache.clip.x - offx, obj->cur->cache.clip.y - offy,
obj->cur->cache.clip.w, obj->cur->cache.clip.h);
return;
}
// general change (prev and cur clip geom change)
col_prev = (obj->prev->color.a << 24) | (obj->prev->color.r << 16) |
(obj->prev->color.g << 8) | (obj->prev->color.b );
col_cur = (obj->cur->color.a << 24) | (obj->cur->color.r << 16) |
(obj->cur->color.g << 8) | (obj->cur->color.b );
if ((col_prev != col_cur) ||
((obj->cur->cache.clip.x != obj->prev->cache.clip.x) ||
(obj->cur->cache.clip.y != obj->prev->cache.clip.y) ||
(obj->cur->cache.clip.w != obj->prev->cache.clip.w) ||
(obj->cur->cache.clip.h != obj->prev->cache.clip.h)) ||
(obj->cur->render_op != obj->prev->render_op) ||
(obj->restack)
)
{
printf(" UP2 %p - %i %i %ix%i\n", eo_obj,
obj->prev->cache.clip.x, obj->prev->cache.clip.y,
obj->prev->cache.clip.w, obj->prev->cache.clip.h);
evas_common_tilebuf_add_redraw
(updates,
obj->prev->cache.clip.x - offx, obj->prev->cache.clip.y - offy,
obj->prev->cache.clip.w, obj->prev->cache.clip.h);
evas_common_tilebuf_add_redraw
(updates,
obj->cur->cache.clip.x - offx, obj->cur->cache.clip.y - offy,
obj->cur->cache.clip.w, obj->cur->cache.clip.h);
return;
}
nochange:
// object hasn't really changed
if ((visible_is) && (evas_object_is_opaque(eo_obj, obj)))
{
printf(" NO- %p - %i %i %ix%i\n", eo_obj,
obj->cur->cache.clip.x, obj->cur->cache.clip.y,
obj->cur->cache.clip.w, obj->cur->cache.clip.h);
evas_common_tilebuf_del_redraw
(updates,
obj->cur->cache.clip.x - offx, obj->cur->cache.clip.y - offy,
obj->cur->cache.clip.w, obj->cur->cache.clip.h);
}
}
static void
evas_object_rectangle_render(Evas_Object *eo_obj EINA_UNUSED,
Evas_Object_Protected_Data *obj,

View File

@ -434,7 +434,6 @@ _evas_object_smart_members_get(Eo *eo_obj, Evas_Smart_Data *o)
Eina_List *members = NULL;
Eina_Inlist *member;
evas_object_async_block(obj);
for (member = o->contained; member; member = member->next)
members = eina_list_append(members, ((Evas_Object_Protected_Data *)member)->object);
@ -448,7 +447,6 @@ evas_object_smart_members_get_direct(const Evas_Object *eo_obj)
MAGIC_CHECK(eo_obj, Evas_Object, MAGIC_OBJ);
return NULL;
MAGIC_CHECK_END();
evas_object_async_block(obj);
if (!eo_isa(eo_obj, MY_CLASS)) return NULL;
Evas_Smart_Data *o = eo_data_scope_get(eo_obj, MY_CLASS);
return o->contained;

View File

@ -2818,6 +2818,17 @@ _evas_canvas_render2(Eo *eo_e, Evas_Public_Data *e)
return ret;
}
EOLIAN Eina_List *
_evas_canvas_render2_updates(Eo *eo_e, Evas_Public_Data *e)
{
Eina_List *updates = NULL;
eina_evlog("+render2_updates", eo_e, 0.0, NULL);
updates = _evas_render2_updates(eo_e, e);
eina_evlog("-render2_updates", eo_e, 0.0, NULL);
return updates;
}
EOLIAN Eina_Bool
_evas_canvas_render_async(Eo *eo_e, Evas_Public_Data *e)
{

View File

@ -1,6 +1,5 @@
#include "evas_render2.h"
#ifdef EVAS_RENDER_DEBUG_TIMING
#include <sys/time.h>
#ifndef _WIN32
@ -23,12 +22,8 @@ static inline void
out_time(double t)
{
double b = (t * 100.0) / (1.0 / 60.0);
printf("%1.8fs (%1.2f%% 60fps budget)\n", t, b);
printf("%1.2f%% / 60fps\n", b);
}
#endif
// a list of canvases currently rendering
static Eina_List *_rendering = NULL;
static void
_always_call(Eo *eo_e, Evas_Callback_Type type, void *event_info)
@ -41,10 +36,31 @@ _always_call(Eo *eo_e, Evas_Callback_Type type, void *event_info)
for (i = 0; i < freeze_num; i++) eo_do(eo_e, eo_event_freeze());
}
// a list of canvases currently rendering
static Eina_List *_rendering = NULL;
// just put the thread code inlined here for now as opposed to separate files
#include "evas_render2_th_main.c"
// init all relevant render threads if needed
static void
_evas_render2_th_init(void)
{
static Eina_Bool initted = EINA_FALSE;
if (initted) return;
initted = EINA_TRUE;
_th_main_queue = eina_thread_queue_new();
if (!eina_thread_create(&_th_main, EINA_THREAD_URGENT, 0,
_evas_render2_th_main, NULL))
ERR("Cannot create render2 thread");
}
Eina_Bool
_evas_render2(Eo *eo_e, Evas_Public_Data *e)
{
double t;
// if nothing changed at all since last render - skip this frame
if (!e->changed) return EINA_FALSE;
// we are still rendering while being asked to render - skip this
@ -55,60 +71,60 @@ _evas_render2(Eo *eo_e, Evas_Public_Data *e)
if ((e->output.w != e->viewport.w) || (e->output.h != e->viewport.h))
ERR("viewport size != output size!");
// if render threads not initted - init them - maybe move this later?
_evas_render2_th_init();
printf("------------------------------------------------ %p %p\n", eo_e, e);
// wait for any previous render pass to do its thing
t = get_time();
evas_canvas_async_block(e);
t = get_time() - t;
printf("T: block wait: "); out_time(t);
// we have to calculate smare objects before render so do that here
t = get_time();
evas_call_smarts_calculate(eo_e);
t = get_time() - t;
printf("T: smart calc: "); out_time(t);
// call canvas callbacks saying we are in the pre-render state
_always_call(eo_e, EVAS_CALLBACK_RENDER_PRE, NULL);
// bock any susbequent rneders from doing this walk
eina_lock_take(&(e->lock_objects));
// XXX: gain a reference
// gain a reference
eo_ref(eo_e);
// XXX: put into the "i'm rendering" pool
// put into the "i'm rendering" pool
e->rendering = EINA_TRUE;
_rendering = eina_list_append(_rendering, eo_e);
// XXX; should wake up thread here to begin doing it's work
// XXX: call this from object walk thread
eina_lock_release(&(e->lock_objects));
// XXX: remove from the "i'm rendering" pool - do back in mainloop
e->rendering = EINA_FALSE;
_rendering = eina_list_remove(_rendering, eo_e);
// XXX: like below - call from thread messages - figure out if they just
// should be dumbly called before render post anyway
// call our flush pre at this point before rendering begins...
_always_call(eo_e, EVAS_CALLBACK_RENDER_FLUSH_PRE, NULL);
_always_call(eo_e, EVAS_CALLBACK_RENDER_FLUSH_POST, NULL);
// XXX: call render post - should be a result from thread message called
// from mainloop - also fill in post struct
Evas_Event_Render_Post post;
_always_call(eo_e, EVAS_CALLBACK_RENDER_POST, &post);
// XXX: release our reference
eo_unref(eo_e);
// tell main render thread to wake up and begin processing this canvas
_evas_render2_th_main_msg_render(eo_e, e);
printf("%p %p\n", eo_e, e);
return EINA_FALSE;
}
void
_evas_norender2(Eo *eo_e EINA_UNUSED, Evas_Public_Data *e)
Eina_List *
_evas_render2_updates(Eo *eo_e, Evas_Public_Data *e)
{
evas_canvas_async_block(e);
if (!_evas_render2(eo_e, e)) return NULL;
return _evas_render2_updates_wait(eo_e, e);
}
Eina_List *
_evas_render2_updates_wait(Eo *eo_e EINA_UNUSED, Evas_Public_Data *e)
{
evas_canvas_async_block(e);
while (e->rendering) evas_async_events_process_blocking();
return NULL;
}
void
_evas_norender2(Eo *eo_e EINA_UNUSED, Evas_Public_Data *e)
{
evas_canvas_async_block(e);
}
void
_evas_render2_idle_flush(Eo *eo_e EINA_UNUSED, Evas_Public_Data *e)
{

View File

@ -9,8 +9,9 @@
#endif
Eina_Bool _evas_render2(Eo *eo_e, Evas_Public_Data *e);
void _evas_norender2(Eo *eo_e, Evas_Public_Data *e);
Eina_List *_evas_render2_updates(Eo *eo_e, Evas_Public_Data *e);
Eina_List *_evas_render2_updates_wait(Eo *eo_e, Evas_Public_Data *e);
void _evas_norender2(Eo *eo_e, Evas_Public_Data *e);
void _evas_render2_idle_flush(Eo *eo_e, Evas_Public_Data *e);
void _evas_render2_sync(Eo *eo_e, Evas_Public_Data *e);
void _evas_render2_dump(Eo *eo_e, Evas_Public_Data *e);

View File

@ -0,0 +1,265 @@
//#define DBG_OBJTREE 1
#define OBJ_ARRAY_PUSH(array, obj) \
do \
{ \
eina_array_push(array, obj); \
eo_data_ref(obj->object, NULL); \
} while (0)
#define OBJS_ARRAY_CLEAN(array) \
do \
{ \
Evas_Object_Protected_Data *item; \
Eina_Array_Iterator iterator; \
unsigned int idx; \
EINA_ARRAY_ITER_NEXT(array, idx, item, iterator) \
eo_data_unref(item->object, item); \
eina_array_clean(array); \
} while (0)
typedef struct _Msg_Main_Render Msg_Main_Render;
typedef struct _Render2_Finish_Data Render2_Finish_Data;
struct _Msg_Main_Render
{
Eina_Thread_Queue_Msg head;
Eo *eo_e;
Evas_Public_Data *e;
};
struct _Render2_Finish_Data
{
Eo *eo_e;
Evas_Public_Data *e;
Eina_List *updates;
};
static Eina_Thread_Queue *_th_main_queue = NULL;
static Eina_Thread _th_main;
#ifdef DBG_OBJTREE
static void
indent(int l)
{
int i; for (i = 0; i < l; i++) printf(" ");
}
#endif
static void
_evas_render2_th_main_delete_objects_clean(Evas_Public_Data *e)
{
Evas_Object_Protected_Data *obj;
unsigned int i;
double t;
// cleanup deferred object deletion
t = get_time();
for (i = 0; i < e->delete_objects.count; ++i)
{
obj = eina_array_data_get(&e->delete_objects, i);
evas_object_free(obj->object, 1);
}
// OBJS_ARRAY_CLEAN(&e->delete_objects);
eina_array_clean(&e->delete_objects);
t = get_time() - t;
printf("T: object deletion: "); out_time(t);
}
static void
_evas_render2_th_main_mainloop_done(void *data, Evas_Callback_Type type EINA_UNUSED, void *event_info EINA_UNUSED)
{
Render2_Finish_Data *render_finish_data = data;
Evas_Event_Render_Post post;
Eo *eo_e;
Evas_Public_Data *e;
Eina_Rectangle *rect;
e = render_finish_data->e;
eo_e = render_finish_data->eo_e;
// call the flush post callbacks
_always_call(render_finish_data->eo_e, EVAS_CALLBACK_RENDER_FLUSH_POST, NULL);
// and now call the actual render post callbacks with updates list
post.updated_area = render_finish_data->updates;
_always_call(eo_e, EVAS_CALLBACK_RENDER_POST, &post);
EINA_LIST_FREE(render_finish_data->updates, rect) free(rect);
free(render_finish_data);
_evas_render2_th_main_delete_objects_clean(e);
}
static Eina_Bool
_evas_render2_th_main_obj_del_handle(Evas_Public_Data *e,
Evas_Object_Protected_Data *obj)
{
if (obj->delete_me == 2)
{
OBJ_ARRAY_PUSH(&e->delete_objects, obj);
obj->delete_me++;
return EINA_FALSE;
}
else if (obj->delete_me != 0) obj->delete_me++;
return EINA_TRUE;
}
static void
_evas_render2_th_main_obj_basic_process(Evas_Public_Data *e,
Evas_Object_Protected_Data *obj,
void *updates,
int offx,
int offy,
int l EINA_UNUSED)
{
Evas_Object *eo_obj = obj->object;
if (!_evas_render2_th_main_obj_del_handle(e, obj)) return;
evas_object_clip_recalc(obj);
#ifdef DBG_OBJTREE
indent(l); printf("BASIC %p %p [%10s]\n", e, eo_obj, obj->type);
#endif
if (obj->func->render2_walk)
obj->func->render2_walk(eo_obj, obj, obj->private_data,
updates, offx, offy);
if (obj->changed)
{
evas_object_clip_changes_clean(eo_obj);
evas_object_cur_prev(eo_obj);
evas_object_change_reset(eo_obj);
}
}
static void
_evas_render2_th_main_obj_process(Evas_Public_Data *e,
Evas_Object_Protected_Data *obj,
void *updates,
int offx,
int offy,
int l EINA_UNUSED)
{
// process object OR walk through child objects if smart and process those
Evas_Object_Protected_Data *obj2;
Evas_Object *eo_obj = obj->object;
const Eina_Inlist *il;
if (!obj->changed) return;
il = evas_object_smart_members_get_direct(eo_obj);
if (il)
{
if (!_evas_render2_th_main_obj_del_handle(e, obj)) return;
evas_object_clip_recalc(obj);
#ifdef DBG_OBJTREE
indent(l); printf("SMART %p %p [%10s] ch %i\n", e, eo_obj, obj->type, obj->changed);
#endif
if (obj->func->render2_walk)
obj->func->render2_walk(eo_obj, obj, obj->private_data,
updates, offx, offy);
EINA_INLIST_FOREACH(il, obj2)
_evas_render2_th_main_obj_process(e, obj2, updates,
offx, offy, l + 1);
if (obj->changed)
{
evas_object_clip_changes_clean(eo_obj);
evas_object_cur_prev(eo_obj);
evas_object_change_reset(eo_obj);
}
}
else _evas_render2_th_main_obj_basic_process(e, obj, updates,
offx, offy, l);
}
static void
_evas_render2_th_main_do(Eo *eo_e, Evas_Public_Data *e)
{
Render2_Finish_Data *render_finish_data;
Evas_Layer *lay;
Evas_Object_Protected_Data *obj;
double t;
Tilebuf *updates = NULL;
Tilebuf_Rect *rects, *r;
Eina_List *updates_list = NULL;
Eina_Rectangle *rect;
updates = evas_common_tilebuf_new(e->output.w, e->output.h);
evas_common_tilebuf_set_tile_size(updates, TILESIZE, TILESIZE);
// evas_common_tilebuf_tile_strict_set(updates, EINA_TRUE);
static int num = 0;
printf("........... updates # %i\n", num++);
t = get_time();
EINA_INLIST_FOREACH(e->layers, lay)
{
EINA_INLIST_FOREACH(lay->objects, obj)
{
_evas_render2_th_main_obj_process(e, obj,
updates, 0, 0,
0);
}
}
t = get_time() - t;
printf("T: update generation: "); out_time(t);
rects = evas_common_tilebuf_get_render_rects(updates);
EINA_INLIST_FOREACH(EINA_INLIST_GET(rects), r)
{
rect = malloc(sizeof(Eina_Rectangle));
if (rect)
{
printf(" %i %i %ix%i\n", r->x, r->y, r->w, r->h);
rect->x = r->x; rect->y = r->y;
rect->w = r->w; rect->h = r->h;
updates_list = eina_list_append(updates_list, rect);
}
}
evas_common_tilebuf_free_render_rects(rects);
evas_common_tilebuf_free(updates);
e->changed = EINA_FALSE;
// remove from the "i'm rendering" pool - do back in mainloop
e->rendering = EINA_FALSE;
_rendering = eina_list_remove(_rendering, eo_e);
// unblock mainlopp that may be waiting on the render thread
eina_lock_release(&(e->lock_objects));
// send back
render_finish_data = calloc(1, sizeof(Render2_Finish_Data));
if (render_finish_data)
{
render_finish_data->eo_e = eo_e;
render_finish_data->e = e;
render_finish_data->updates = updates_list;
evas_async_events_put(render_finish_data, 0, NULL,
_evas_render2_th_main_mainloop_done);
}
else
{
EINA_LIST_FREE(updates_list, rect) free(rect);
}
eo_unref(eo_e);
}
static void *
_evas_render2_th_main(void *data EINA_UNUSED, Eina_Thread thread EINA_UNUSED)
{
void *ref = NULL;
Msg_Main_Render *msg;
for (;;)
{
msg = eina_thread_queue_wait(_th_main_queue, &ref);
_evas_render2_th_main_do(msg->eo_e, msg->e);
eina_thread_queue_wait_done(_th_main_queue, ref);
}
return NULL;
}
static void
_evas_render2_th_main_msg_render(Eo *eo_e, Evas_Public_Data *e)
{
void *ref;
Msg_Main_Render *msg =
eina_thread_queue_send(_th_main_queue, sizeof(Msg_Main_Render), &ref);
msg->eo_e = eo_e;
msg->e = e;
eina_thread_queue_send_done(_th_main_queue, ref);
}

View File

@ -1216,6 +1216,15 @@ struct _Evas_Object_Func
Evas_Coord *x, Evas_Coord *y, Evas_Coord *w, Evas_Coord *h);
int (*can_map) (Evas_Object *obj);
// new render2 functions
void (*render2_walk) (Evas_Object *obj, Evas_Object_Protected_Data *pd,
void *type_private_data, void *updates,
int offx, int offy);
// void (*render2) (Evas_Object *obj, Evas_Object_Protected_Data *pd,
// void *type_private_data, void *output, void *context,
// void *surface, int x, int y);
};
struct _Evas_Func

View File

@ -759,6 +759,7 @@ _ecore_evas_x_render(Ecore_Evas *ee)
Eina_List *ll;
Ecore_Evas *ee2;
Ecore_Evas_Engine_Data_X11 *edata = ee->engine.data;
static int render2 = -1;
if ((!ee->no_comp_sync) && (_ecore_evas_app_comp_sync) &&
(edata->sync_counter) && (!edata->sync_began) &&
@ -780,20 +781,42 @@ _ecore_evas_x_render(Ecore_Evas *ee)
}
if (ee->func.fn_pre_render) ee->func.fn_pre_render(ee);
if (!ee->can_async_render)
if (render2 == -1)
{
Eina_List *updates = evas_render_updates(ee->evas);
rend = _render_updates_process(ee, updates);
evas_render_updates_free(updates);
if (getenv("RENDER2")) render2 = 1;
else render2 = 0;
}
else if (evas_render_async(ee->evas))
if (render2)
{
EDBG("ee=%p started asynchronous render.", ee);
ee->in_async_render = EINA_TRUE;
rend = 1;
if (!ee->can_async_render)
{
Eina_List *updates = evas_render2_updates(ee->evas);
rend = _render_updates_process(ee, updates);
evas_render_updates_free(updates);
}
else
{
ee->in_async_render = EINA_TRUE;
if (evas_render2(ee->evas)) rend = 1;
else ee->in_async_render = EINA_FALSE;
}
}
else
{
if (!ee->can_async_render)
{
Eina_List *updates = evas_render_updates(ee->evas);
rend = _render_updates_process(ee, updates);
evas_render_updates_free(updates);
}
else if (evas_render_async(ee->evas))
{
EDBG("ee=%p started asynchronous render.", ee);
ee->in_async_render = EINA_TRUE;
rend = 1;
}
else if (ee->func.fn_post_render) ee->func.fn_post_render(ee);
}
else if (ee->func.fn_post_render) ee->func.fn_post_render(ee);
return rend;
}