summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>2015-09-25 14:38:21 +0900
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2015-09-25 14:38:21 +0900
commit11c29579d0d348576980305b6c6a268f279e2a23 (patch)
tree08fab6807635a0fd06394dd38a278f27d9fc0616
parent21c43528234a315a1cab7df00014ab62dca92ced (diff)
downloadefl-11c29579d0d348576980305b6c6a268f279e2a23.tar.gz
evas gl - optimize updates
@feature this makes the gl engine by default not do bounding box, but instead try and smartly merge nearby update regions. this means multiple render passes IF your drivers support buffer age, but it seems to actually help. in my test case on nvidia drivers which support buffer age, i saw compositor cpu overhead drop by about 30%
-rw-r--r--src/modules/evas/engines/gl_x11/evas_engine.c6
-rw-r--r--src/modules/evas/engines/software_generic/Evas_Engine_Software_Generic.h3
-rw-r--r--src/modules/evas/engines/software_generic/evas_engine.c160
3 files changed, 150 insertions, 19 deletions
diff --git a/src/modules/evas/engines/gl_x11/evas_engine.c b/src/modules/evas/engines/gl_x11/evas_engine.c
index b43fc2287b..49b75e9e97 100644
--- a/src/modules/evas/engines/gl_x11/evas_engine.c
+++ b/src/modules/evas/engines/gl_x11/evas_engine.c
@@ -1589,7 +1589,7 @@ eng_setup(Evas *eo_e, void *in)
if (!e->engine.data.output)
{
Outbuf *ob;
- Render_Engine_Merge_Mode merge_mode = MERGE_BOUNDING;
+ Render_Engine_Merge_Mode merge_mode = MERGE_SMART;
if (!initted)
{
@@ -1661,6 +1661,9 @@ eng_setup(Evas *eo_e, void *in)
else if ((!strcmp(s, "full")) ||
(!strcmp(s, "f")))
merge_mode = MERGE_FULL;
+ else if ((!strcmp(s, "smart")) ||
+ (!strcmp(s, "s")))
+ merge_mode = MERGE_SMART;
}
evas_render_engine_software_generic_merge_mode_set(&re->generic.software, merge_mode);
@@ -2792,6 +2795,7 @@ module_open(Evas_Module *em)
if (getenv("EVAS_GL_PARTIAL_DEBUG")) partial_render_debug = 1;
else partial_render_debug = 0;
}
+// partial_render_debug = 1;
/* store it for later use */
func = pfunc;
diff --git a/src/modules/evas/engines/software_generic/Evas_Engine_Software_Generic.h b/src/modules/evas/engines/software_generic/Evas_Engine_Software_Generic.h
index 8369f02178..179dae745e 100644
--- a/src/modules/evas/engines/software_generic/Evas_Engine_Software_Generic.h
+++ b/src/modules/evas/engines/software_generic/Evas_Engine_Software_Generic.h
@@ -36,7 +36,8 @@ typedef enum
typedef enum
{
MERGE_BOUNDING,
- MERGE_FULL
+ MERGE_FULL,
+ MERGE_SMART
} Render_Engine_Merge_Mode;
typedef struct _Render_Engine_Software_Generic Render_Engine_Software_Generic;
diff --git a/src/modules/evas/engines/software_generic/evas_engine.c b/src/modules/evas/engines/software_generic/evas_engine.c
index 8dc64f0c8a..553b35354f 100644
--- a/src/modules/evas/engines/software_generic/evas_engine.c
+++ b/src/modules/evas/engines/software_generic/evas_engine.c
@@ -5,6 +5,8 @@
#include "evas_cs2_private.h"
#endif
+#include "region.h"
+
#include <software/Ector_Software.h>
#include "ector_cairo_software_surface.eo.h"
@@ -3283,6 +3285,118 @@ eng_output_redraws_clear(void *data)
}
static Tilebuf_Rect *
+_smart_merge(Tilebuf *tb, Tilebuf_Rect *rects)
+{
+ Tilebuf_Rect *merged, *mergelist = NULL, *r;
+ Box *box;
+ Region *region;
+ int i, j, k, n, n2;
+ Eina_Bool did_merge;
+
+ n = eina_inlist_count(EINA_INLIST_GET(rects));
+ box = malloc(n * sizeof(Box));
+ i = 0;
+ EINA_INLIST_FOREACH(EINA_INLIST_GET(rects), r)
+ {
+ box[i].x1 = r->x;
+ box[i].y1 = r->y;
+ box[i].x2 = r->x + r->w;
+ box[i].y2 = r->y + r->h;
+ i++;
+ }
+ evas_common_tilebuf_free_render_rects(rects);
+
+ n2 = n;
+ for (;;)
+ {
+ Box *box2, bbox;
+ int mergenum, area, minarea, area1, area2, perc;
+
+ did_merge = EINA_FALSE;
+ box2 = calloc(1, n2 * sizeof(Box));
+ j = 0;
+ for (i = 0; i < n2; i++)
+ {
+ if (box[i].x1 == box[i].x2) continue;
+
+ mergenum = -1;
+ minarea = 0x7fffffff;
+
+ box2[j] = box[i];
+ area1 = (box[i].x2 - box[i].x1) * (box[i].y2 - box[i].y1);
+ box[i].x1 = 0;
+ box[i].x2 = 0;
+ for (k = i + 1; k < n; k++)
+ {
+ if (box[k].x1 == box[k].x2) continue;
+ bbox = box2[j];
+ if (box[k].x1 < bbox.x1) bbox.x1 = box[k].x1;
+ if (box[k].y1 < bbox.y1) bbox.y1 = box[k].y1;
+ if (box[k].x2 > bbox.x2) bbox.x2 = box[k].x2;
+ if (box[k].y2 > bbox.y2) bbox.y2 = box[k].y2;
+ area = (bbox.x2 - bbox.x1) * (bbox.y2 - bbox.y1);
+ if (area < minarea)
+ {
+ mergenum = k;
+ minarea = area;
+ }
+ }
+ if (mergenum >= 0)
+ {
+ k = mergenum;
+ area2 = (box[k].x2 - box[k].x1) * (box[k].y2 - box[k].y1);
+ perc = (minarea * 100) / (area1 + area2);
+ // if combined size of bounding box of rects is <= X% of
+ // the sum of the 2 src areas - then merge
+ if (perc <= 150)
+ {
+ bbox = box2[j];
+ if (box[k].x1 < bbox.x1) bbox.x1 = box[k].x1;
+ if (box[k].y1 < bbox.y1) bbox.y1 = box[k].y1;
+ if (box[k].x2 > bbox.x2) bbox.x2 = box[k].x2;
+ if (box[k].y2 > bbox.y2) bbox.y2 = box[k].y2;
+ box2[j] = bbox;
+ box[k].x1 = 0;
+ box[k].x2 = 0;
+ did_merge = EINA_TRUE;
+ }
+ }
+ j++;
+ }
+ n2 = n;
+ free(box);
+ box = box2;
+ if (!did_merge) break;
+ }
+ region = region_new(tb->outbuf_w, tb->outbuf_h);
+ for (i = 0; i < n2; i++)
+ {
+ if (box[i].x1 == box[i].x2) continue;
+ region_rect_add(region,
+ box[i].x1, box[i].y1,
+ box[i].x2 - box[i].x1,
+ box[i].y2 - box[i].y1);
+ }
+ free(box);
+ box = region_rects(region);
+ n = region_rects_num(region);
+ merged = calloc(1, n * sizeof(Tilebuf_Rect));
+ for (i = 0; i < n; i++)
+ {
+ merged[i].x = box[i].x1;
+ merged[i].y = box[i].y1;
+ merged[i].w = box[i].x2 - box[i].x1;
+ merged[i].h = box[i].y2 - box[i].y1;
+ mergelist = (Tilebuf_Rect *)eina_inlist_append
+ (EINA_INLIST_GET(mergelist), EINA_INLIST_GET(&(merged[i])));
+ }
+ region_free(region);
+ rects = mergelist;
+
+ return rects;
+}
+
+static Tilebuf_Rect *
_merge_rects(Render_Engine_Merge_Mode merge_mode,
Tilebuf *tb,
Tilebuf_Rect *r1,
@@ -3327,27 +3441,37 @@ _merge_rects(Render_Engine_Merge_Mode merge_mode,
// yes we could try and be smart and figure out size of regions, how far
// apart etc. etc. to try and figure out an optimal "set". this is a tradeoff
// between multiple update regions to render and total pixels to render.
- if (merge_mode == MERGE_BOUNDING && rects)
+ if (rects)
{
- int px1, py1, px2, py2;
-
- px1 = rects->x; py1 = rects->y;
- px2 = rects->x + rects->w; py2 = rects->y + rects->h;
- EINA_INLIST_FOREACH(EINA_INLIST_GET(rects), r)
+ if ((merge_mode == MERGE_BOUNDING)
+// disable smart updates for debugging
+// || (merge_mode == MERGE_SMART)
+ )
{
- if (r->x < px1) px1 = r->x;
- if (r->y < py1) py1 = r->y;
- if ((r->x + r->w) > px2) px2 = r->x + r->w;
- if ((r->y + r->h) > py2) py2 = r->y + r->h;
+ int px1, py1, px2, py2;
+
+ px1 = rects->x; py1 = rects->y;
+ px2 = rects->x + rects->w; py2 = rects->y + rects->h;
+ EINA_INLIST_FOREACH(EINA_INLIST_GET(rects), r)
+ {
+ if (r->x < px1) px1 = r->x;
+ if (r->y < py1) py1 = r->y;
+ if ((r->x + r->w) > px2) px2 = r->x + r->w;
+ if ((r->y + r->h) > py2) py2 = r->y + r->h;
+ }
+ evas_common_tilebuf_free_render_rects(rects);
+ rects = calloc(1, sizeof(Tilebuf_Rect));
+ if (rects)
+ {
+ rects->x = px1;
+ rects->y = py1;
+ rects->w = px2 - px1;
+ rects->h = py2 - py1;
+ }
}
- evas_common_tilebuf_free_render_rects(rects);
- rects = calloc(1, sizeof(Tilebuf_Rect));
- if (rects)
+ else if (merge_mode == MERGE_SMART)
{
- rects->x = px1;
- rects->y = py1;
- rects->w = px2 - px1;
- rects->h = py2 - py1;
+ rects = _smart_merge(tb, rects);
}
}
evas_common_tilebuf_clear(tb);
@@ -3468,6 +3592,7 @@ eng_output_redraws_next_update_get(void *data, int *x, int *y, int *w, int *h, i
surface = re->outbuf_new_region_for_update(re->ob,
*x, *y, *w, *h,
cx, cy, cw, ch);
+// printf("UP %i %i %ix%i | %i %i %ix%i\n", *x, *y, *w, *h, *cx, *cy, *cw, *ch);
if ((!re->cur_rect) || (!surface))
{
evas_common_tilebuf_free_render_rects(re->rects);
@@ -3501,6 +3626,7 @@ eng_output_flush(void *data, Evas_Render_Mode render_mode)
Render_Engine_Software_Generic *re;
if (render_mode == EVAS_RENDER_MODE_ASYNC_INIT) return;
+// printf("-------------------------------\n");
re = (Render_Engine_Software_Generic *)data;
if (re->outbuf_flush) re->outbuf_flush(re->ob, re->rects, render_mode);