This is an automated email from the git hooks/post-receive script.

git pushed a commit to branch evas_gl_buffer_optimization
in repository efl.

View the commit online.

commit a46f547aa5fdcb823ee5a7ae9fcfe24a420f860c
Author: Carsten Haitzler <ras...@rasterman.com>
AuthorDate: Tue Jan 10 22:23:46 2017 +0900

    evas gl engine - add rolling per frame vbo buff pool for glmapbuffer
    
    this adds a buffer pool for glmapbuffer over 6 frames with a pool per
    frame of buffers to re-use for holding vertices, colors and more.
---
 .../evas/engines/gl_common/evas_gl_common.h        |  29 ++-
 .../evas/engines/gl_common/evas_gl_context.c       | 200 ++++++++++++++++++---
 src/modules/evas/engines/gl_x11/evas_engine.c      |   4 +
 3 files changed, 207 insertions(+), 26 deletions(-)

diff --git a/src/modules/evas/engines/gl_common/evas_gl_common.h b/src/modules/evas/engines/gl_common/evas_gl_common.h
index 55f5ab95cc..3440a61bdb 100644
--- a/src/modules/evas/engines/gl_common/evas_gl_common.h
+++ b/src/modules/evas/engines/gl_common/evas_gl_common.h
@@ -246,12 +246,22 @@ enum _Shader_Type {
 #define ARRAY_BUFFER_USE 500
 #define ARRAY_BUFFER_USE_SHIFT 100
 
+typedef struct _Evas_GL_Vbo Evas_GL_Vbo;
+
+struct _Evas_GL_Vbo
+{
+   GLuint       buffer;
+   unsigned int size;
+   unsigned int unused;
+};
+
 struct _Evas_Engine_GL_Context
 {
    int                references;
    int                w, h;
    int                rot;
    int                foc, z0, px, py;
+   unsigned int       frame;
    RGBA_Draw_Context *dc;
 
    Evas_GL_Shared     *shared;
@@ -271,7 +281,7 @@ struct _Evas_Engine_GL_Context
          Eina_Bool       anti_alias : 1;
       } current;
    } state;
-   
+
    struct {
       int                x, y, w, h;
       Eina_Bool          enabled : 1;
@@ -307,6 +317,8 @@ struct _Evas_Engine_GL_Context
          GLfloat *texsam;
          GLfloat *mask;
          GLfloat *masksam;
+         Evas_GL_Image *im;
+         GLuint buffer;
          Eina_Bool line: 1;
          Eina_Bool use_vertex : 1; // always true
          Eina_Bool use_color : 1;
@@ -318,17 +330,21 @@ struct _Evas_Engine_GL_Context
          Eina_Bool use_mask : 1;
          Eina_Bool use_masksam : 1;
          Eina_Bool anti_alias : 1;
-         Evas_GL_Image *im;
-         GLuint buffer;
-         int buffer_alloc;
-         int buffer_use;
       } array;
    } pipe[MAX_PIPES];
 
    struct {
       Eina_Bool size : 1;
    } change;
-   
+
+#define VBO_POOL_SLOTS 6
+   struct {
+      struct {
+         Eina_List *spare;
+         Eina_List *used;
+      } pool[VBO_POOL_SLOTS];
+   } vbos;
+
    Eina_List *font_glyph_textures;
 
    Eina_Bool havestuff : 1;
@@ -519,6 +535,7 @@ EAPI Eina_Bool    evas_gl_preload_enabled(void);
 EAPI Evas_Engine_GL_Context  *evas_gl_common_context_new(void);
 
 EAPI void         evas_gl_common_context_flush(Evas_Engine_GL_Context *gc);
+EAPI void         evas_gl_common_context_idle_flush(Evas_Engine_GL_Context *gc);
 EAPI void         evas_gl_common_context_free(Evas_Engine_GL_Context *gc);
 EAPI void         evas_gl_common_context_use(Evas_Engine_GL_Context *gc);
 EAPI void         evas_gl_common_context_newframe(Evas_Engine_GL_Context *gc);
diff --git a/src/modules/evas/engines/gl_common/evas_gl_context.c b/src/modules/evas/engines/gl_common/evas_gl_context.c
index 470b4f7e81..4a446abbcb 100644
--- a/src/modules/evas/engines/gl_common/evas_gl_context.c
+++ b/src/modules/evas/engines/gl_common/evas_gl_context.c
@@ -273,7 +273,7 @@ evas_gl_symbols(void *(*GetProcAddress)(const char *name))
    FINDSYM(glsym_glStartTiling, "glActivateTileQCOM", NULL, glsym_func_void);
    FINDSYM(glsym_glEndTiling, "glEndTilingQCOM", "GL_QCOM_tiled_rendering", glsym_func_void);
    FINDSYM(glsym_glEndTiling, "glEndTiling", NULL, glsym_func_void);
-   
+
    if (!getenv("EVAS_GL_MAPBUFFER_DISABLE"))
      {
         // Not sure there's an EXT variant. (probably no KHR variant)
@@ -773,6 +773,141 @@ _evas_gl_common_viewport_set(Evas_Engine_GL_Context *gc)
      }
 }
 
+///////////////////////////////////////////////////////////////////////////
+
+// debugging just for the fbo pool/cache
+#if 0
+# define VD(...) printf(__VA_ARGS__)
+#else
+# define VD(...)
+#endif
+
+// a vbo bigger than MAX_VBO_SIZE is stupid and likely an error so dont
+// even try
+#define MAX_VBO_SIZE (0x7fffffff)
+// if the final vbo we found is more than MAX_VBO_DIFF bigger than what
+// we need then let's not use it and alloc a new vbo anyway
+#define MAX_VBO_DIFF (128 * 1024)
+// if the buffer is up to MIN_VBO_DIFF buffer than what we want just
+// take it and don't look for a better match as this just costs us
+// time hunting rfor a better one and since this is O(n) why bother
+// with that effort when near enough is good enough
+#define MIN_VBO_DIFF (512)
+
+static void
+_vbo_pool_vbo_del(Evas_GL_Vbo *vbo)
+{
+   glDeleteBuffers(1, &(vbo->buffer));
+   free(vbo);
+}
+
+static void
+_vbo_pool_clear(Evas_Engine_GL_Context *gc)
+{
+   int i;
+   Evas_GL_Vbo *vbo;
+
+   if (!(glsym_glMapBuffer && glsym_glUnmapBuffer)) return;
+   for (i = 0; i < VBO_POOL_SLOTS; i++)
+     {
+        EINA_LIST_FREE(gc->vbos.pool[i].spare, vbo)
+          {
+             VD("FREE UP SPARE buf=%i size=%i\n", vbo->buffer, vbo->size);
+             _vbo_pool_vbo_del(vbo);
+          }
+        EINA_LIST_FREE(gc->vbos.pool[i].used, vbo)
+          {
+             VD("FREE UP USED buf=%i size=%i\n", vbo->buffer, vbo->size);
+             _vbo_pool_vbo_del(vbo);
+          }
+     }
+}
+
+static void
+_vbo_pool_newframe(Evas_Engine_GL_Context *gc)
+{
+   int slot;
+   Eina_List *l, *ll;
+   Evas_GL_Vbo *vbo;
+
+   if (!(glsym_glMapBuffer && glsym_glUnmapBuffer)) return;
+   VD("-------------------------------- FRAME %i\n", gc->frame + 1);
+   slot = gc->frame % VBO_POOL_SLOTS;
+   EINA_LIST_FOREACH_SAFE(gc->vbos.pool[slot].spare, l, ll, vbo)
+     {
+        vbo->unused++;
+        if (vbo->unused >= 2)
+          {
+             VD("DEL UNUSED buf=%i size=%i\n", vbo->buffer, vbo->size);
+             _vbo_pool_vbo_del(vbo);
+             gc->vbos.pool[slot].spare =
+               eina_list_remove_list(gc->vbos.pool[slot].spare, l);
+          }
+     }
+   EINA_LIST_FREE(gc->vbos.pool[slot].used, vbo)
+     {
+        gc->vbos.pool[slot].spare =
+          eina_list_prepend(gc->vbos.pool[slot].spare, vbo);
+     }
+}
+
+static GLuint
+_vbo_pool_buffer_find(Evas_Engine_GL_Context *gc, size_t size)
+{
+   Eina_List *l, *l_sel = NULL;
+   Evas_GL_Vbo *vbo, *vbo_sel = NULL;
+   int slot;
+   unsigned int diff, diff_sel = MAX_VBO_SIZE;
+   int hunt = 0;
+
+   if (size > MAX_VBO_SIZE) return 0; // stupidly too big buffer
+   // look up in a specifc buffer pool that is a ring buffer of the last
+   // N frames (one slot with a pool per frame) where N is VBO_POOL_SLOTS
+   slot = gc->frame % VBO_POOL_SLOTS;
+   EINA_LIST_FOREACH(gc->vbos.pool[slot].spare, l, vbo)
+     {
+        hunt++;
+        if (vbo->size < size) continue;
+        diff = size - vbo->size;
+        if (diff < diff_sel)
+          {
+             vbo_sel = vbo;
+             diff_sel = diff;
+             l_sel = l;
+             if (diff < MIN_VBO_DIFF) break;
+          }
+     }
+   VD("FIND SIZE=%i from #=%i/%i - ", (int)size, hunt, eina_list_count(gc->vbos.pool[slot].spare));
+   if ((vbo_sel) && (diff_sel > MAX_VBO_DIFF))
+     {
+        VD("[BIG %i] ", diff_sel);
+        vbo_sel = NULL;
+     }
+   if (vbo_sel)
+     {
+        vbo = vbo_sel;
+        VD("FOUND buf=%i size=%i unused=%i\n", vbo->buffer, vbo->size, vbo->unused);
+        vbo->unused = 0;;
+        gc->vbos.pool[slot].spare =
+          eina_list_remove_list(gc->vbos.pool[slot].spare, l_sel);
+        gc->vbos.pool[slot].used =
+          eina_list_append(gc->vbos.pool[slot].used, vbo);
+        return vbo->buffer;
+     }
+   vbo = calloc(1, sizeof(Evas_GL_Vbo));
+   if (!vbo) return 0;
+   glGenBuffers(1, &(vbo->buffer));
+   glBindBuffer(GL_ARRAY_BUFFER, vbo->buffer);
+   glBufferData(GL_ARRAY_BUFFER, (long)size, NULL, GL_DYNAMIC_DRAW);
+   vbo->size = size;
+   gc->vbos.pool[slot].used =
+     eina_list_append(gc->vbos.pool[slot].used, vbo);
+   VD("** ALLOC ** buf=%i size=%i\n", vbo->buffer, vbo->size);
+   return vbo->buffer;
+}
+
+///////////////////////////////////////////////////////////////////////////
+
 EAPI Evas_Engine_GL_Context *
 evas_gl_common_context_new(void)
 {
@@ -806,12 +941,12 @@ evas_gl_common_context_new(void)
    for (i = 0; i < MAX_PIPES; i++)
      {
         gc->pipe[i].shader.render_op = EVAS_RENDER_BLEND;
-        if (glsym_glMapBuffer && glsym_glUnmapBuffer)
-          {
-             glGenBuffers(1, &gc->pipe[i].array.buffer);
-             gc->pipe[i].array.buffer_alloc = 0;
-             gc->pipe[i].array.buffer_use = 0;
-          }
+//        if (glsym_glMapBuffer && glsym_glUnmapBuffer)
+//          {
+//             glGenBuffers(1, &gc->pipe[i].array.buffer);
+//             gc->pipe[i].array.buffer_alloc = 0;
+//             gc->pipe[i].array.buffer_use = 0;
+//          }
      }
 
    gc->state.current.tex_target = GL_TEXTURE_2D;
@@ -930,11 +1065,13 @@ evas_gl_common_context_new(void)
              else if (strstr(s, "NVIDIA Tegra"))
                 shared->info.tune.pipes.max = DEF_PIPES_TEGRA_2;
           }
+#if 1
         if (!getenv("EVAS_GL_MAPBUFFER"))
           {
              glsym_glMapBuffer = NULL;
              glsym_glUnmapBuffer= NULL;
           }
+#endif
 
 #define GETENVOPT(name, tune_param, min, max) \
         do { \
@@ -1094,6 +1231,12 @@ error:
    return NULL;
 }
 
+EAPI void
+evas_gl_common_context_idle_flush(Evas_Engine_GL_Context *gc)
+{
+   _vbo_pool_clear(gc);
+}
+
 EAPI void
 evas_gl_common_context_free(Evas_Engine_GL_Context *gc)
 {
@@ -1109,11 +1252,12 @@ evas_gl_common_context_free(Evas_Engine_GL_Context *gc)
    if (gc->font_surface)
      evas_cache_image_drop(&gc->font_surface->cache_entry);
 
-   if (glsym_glMapBuffer && glsym_glUnmapBuffer)
-     {
-        for (i = 0; i < MAX_PIPES; i++)
-          glDeleteBuffers(1, &gc->pipe[i].array.buffer);
-     }
+   _vbo_pool_clear(gc);
+//   if (glsym_glMapBuffer && glsym_glUnmapBuffer)
+//     {
+//        for (i = 0; i < MAX_PIPES; i++)
+//          glDeleteBuffers(1, &gc->pipe[i].array.buffer);
+//     }
 
    if (gc->shared)
      {
@@ -1186,6 +1330,8 @@ evas_gl_common_context_newframe(Evas_Engine_GL_Context *gc)
 {
    int i;
 
+   _vbo_pool_newframe(gc);
+   gc->frame++;
    if (_evas_gl_common_cutout_rects)
      {
         evas_common_draw_context_apply_clear_cutouts(_evas_gl_common_cutout_rects);
@@ -3313,6 +3459,7 @@ shader_array_flush(Evas_Engine_GL_Context *gc)
         if (glsym_glMapBuffer && glsym_glUnmapBuffer)
           {
              unsigned char *x;
+             unsigned int pad = 0;
 
 # define VERTEX_SIZE (gc->pipe[i].array.num * sizeof(GLshort) * VERTEX_CNT)
 # define COLOR_SIZE (gc->pipe[i].array.num * sizeof(GLubyte) * COLOR_CNT)
@@ -3320,7 +3467,11 @@ shader_array_flush(Evas_Engine_GL_Context *gc)
 # define SAM_SIZE (gc->pipe[i].array.num * sizeof(GLfloat) * SAM_CNT)
 # define MASK_SIZE (gc->pipe[i].array.num * sizeof(GLfloat) * MASK_CNT)
              vertex_ptr = NULL;
-             color_ptr = vertex_ptr + VERTEX_SIZE;
+             // purely for correctness handle alignment. since we do
+             // quads which is 6 points this ends up not needed, but just
+             // in case in future...
+             if (gc->pipe[i].array.num & 1) pad = 2;
+             color_ptr = vertex_ptr + VERTEX_SIZE + pad;
              texuv_ptr = color_ptr + COLOR_SIZE;
              texuv2_ptr = texuv_ptr + TEX_SIZE;
              texuv3_ptr = texuv2_ptr + TEX_SIZE;
@@ -3330,15 +3481,23 @@ shader_array_flush(Evas_Engine_GL_Context *gc)
              masksam_ptr = mask_ptr + MASK_SIZE;
 # define END_POINTER (masksam_ptr + SAM_SIZE)
 
-             glBindBuffer(GL_ARRAY_BUFFER, gc->pipe[i].array.buffer);
-             if ((gc->pipe[i].array.buffer_alloc < (long)END_POINTER) ||
-                 (gc->pipe[i].array.buffer_use >= (ARRAY_BUFFER_USE + ARRAY_BUFFER_USE_SHIFT * i)))
+             if (gc->pipe[i].array.buffer == 0)
                {
-                  glBufferData(GL_ARRAY_BUFFER, (long)END_POINTER, NULL, GL_STATIC_DRAW);
-                  gc->pipe[i].array.buffer_alloc = (long)END_POINTER;
-                  gc->pipe[i].array.buffer_use = 0;
+                  gc->pipe[i].array.buffer =
+                    _vbo_pool_buffer_find(gc, (size_t)END_POINTER);
                }
-             gc->pipe[i].array.buffer_use++;
+             glBindBuffer(GL_ARRAY_BUFFER, gc->pipe[i].array.buffer);
+//             glBufferData(GL_ARRAY_BUFFER, (long)0, NULL, GL_DYNAMIC_DRAW);
+//             glBufferData(GL_ARRAY_BUFFER, (long)END_POINTER, NULL, GL_DYNAMIC_DRAW);
+//             if ((gc->pipe[i].array.buffer_alloc < (long)END_POINTER) ||
+//                 (gc->pipe[i].array.buffer_use >= (ARRAY_BUFFER_USE + ARRAY_BUFFER_USE_SHIFT * i)))
+//               {
+//                  glBufferData(GL_ARRAY_BUFFER, (long)0, NULL, GL_DYNAMIC_DRAW);
+//                  glBufferData(GL_ARRAY_BUFFER, (long)END_POINTER, NULL, GL_DYNAMIC_DRAW);
+//                  gc->pipe[i].array.buffer_alloc = (long)END_POINTER;
+//                  gc->pipe[i].array.buffer_use = 0;
+//               }
+//             gc->pipe[i].array.buffer_use++;
 
              x = glsym_glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
              if (x)
@@ -3650,6 +3809,7 @@ shader_array_flush(Evas_Engine_GL_Context *gc)
         if (glsym_glMapBuffer && glsym_glUnmapBuffer)
           {
              glBindBuffer(GL_ARRAY_BUFFER, 0);
+             gc->pipe[i].array.buffer = 0;
           }
 
         gc->pipe[i].region.x = 0;
diff --git a/src/modules/evas/engines/gl_x11/evas_engine.c b/src/modules/evas/engines/gl_x11/evas_engine.c
index 94bfdedbb9..f4c58025ff 100644
--- a/src/modules/evas/engines/gl_x11/evas_engine.c
+++ b/src/modules/evas/engines/gl_x11/evas_engine.c
@@ -61,6 +61,7 @@ EVGL_Current_Native_Context_Get_Call glsym_evgl_current_native_context_get = NUL
 Evas_Gl_Symbols glsym_evas_gl_symbols = NULL;
 
 Evas_GL_Common_Context_New glsym_evas_gl_common_context_new = NULL;
+Evas_GL_Common_Context_Call glsym_evas_gl_common_context_idle_flush = NULL;
 Evas_GL_Common_Context_Call glsym_evas_gl_common_context_flush = NULL;
 Evas_GL_Common_Context_Call glsym_evas_gl_common_context_free = NULL;
 Evas_GL_Common_Context_Call glsym_evas_gl_common_context_use = NULL;
@@ -1283,6 +1284,7 @@ gl_symbols(void)
    LINK2GENERIC(evas_gl_common_image_free);
    LINK2GENERIC(evas_gl_common_image_native_enable);
    LINK2GENERIC(evas_gl_common_context_new);
+   LINK2GENERIC(evas_gl_common_context_idle_flush);
    LINK2GENERIC(evas_gl_common_context_flush);
    LINK2GENERIC(evas_gl_common_context_free);
    LINK2GENERIC(evas_gl_common_context_use);
@@ -1572,6 +1574,8 @@ eng_outbuf_idle_flush(Outbuf *ob)
 {
    if (glsym_evas_gl_common_shaders_flush)
      glsym_evas_gl_common_shaders_flush(ob->gl_context->shared);
+   if (glsym_evas_gl_common_context_idle_flush)
+     glsym_evas_gl_common_context_idle_flush(ob->gl_context);
 }
 
 static void

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.

Reply via email to