evas: Implement GL map/unmap for the simple case
authorJean-Philippe Andre <jp.andre@samsung.com>
Tue, 19 Jul 2016 12:08:02 +0000 (21:08 +0900)
committerJean-Philippe Andre <jp.andre@samsung.com>
Tue, 16 Aug 2016 07:14:21 +0000 (16:14 +0900)
Most of the code relies on the software generic engine
implementation, using inheritance between engines.

This fixes expedite image map RGBA test.

src/modules/evas/engines/gl_common/evas_gl_common.h
src/modules/evas/engines/gl_generic/evas_engine.c
src/modules/evas/engines/software_generic/evas_engine.c

index 92e968b..c390e33 100644 (file)
@@ -68,6 +68,7 @@ typedef struct _Evas_GL_Font_Texture          Evas_GL_Font_Texture;
 typedef struct _Evas_GL_Polygon               Evas_GL_Polygon;
 typedef struct _Evas_GL_Polygon_Point         Evas_GL_Polygon_Point;
 typedef struct _Evas_GL_Texture_Async_Preload Evas_GL_Texture_Async_Preload;
+typedef struct _Evas_GL_Image_Data_Map        Evas_GL_Image_Data_Map;
 
 typedef Eina_Bool (*evas_gl_make_current_cb)(void *engine_data, void *doit);
 
@@ -449,6 +450,8 @@ struct _Evas_GL_Image
    Eina_List         *targets;
    Evas_Image_Orient orient;
 
+   Eina_Inlist     *maps; /* Evas_GL_Image_Data_Map */
+
    unsigned char    dirty : 1;
    unsigned char    cached : 1;
    unsigned char    alpha : 1;
@@ -483,6 +486,18 @@ struct _Evas_GL_Texture_Async_Preload
    Eina_Bool unpack_row_length;
 };
 
+struct _Evas_GL_Image_Data_Map
+{
+   EINA_INLIST;
+   Evas_GL_Texture *tex; // one or the other
+   RGBA_Image      *im; // one or the other
+   unsigned char   *ptr;
+   int              size, stride; // in bytes
+   int              rx, ry, rw, rh; // actual map region
+   Evas_Colorspace  cspace;
+   Efl_Gfx_Buffer_Access_Mode mode;
+};
+
 /* GL_Common function that are used by gl_generic inherited module */
 EAPI void         evas_gl_common_image_all_unload(Evas_Engine_GL_Context *gc);
 EAPI void         evas_gl_common_image_ref(Evas_GL_Image *im);
index 6eab384..3c88a86 100644 (file)
@@ -59,6 +59,8 @@ static Eina_Bool eng_gl_surface_read_pixels(void *data, void *surface, int x, in
 
 Eina_Bool _need_context_restore = EINA_FALSE;
 
+static Evas_Func func, pfunc;
+
 void
 _context_restore(void)
 {
@@ -1648,17 +1650,17 @@ eng_gl_proc_address_get(void *data, const char *name)
 {
    Render_Engine_GL_Generic *re = data;
    EVGLINIT(re, NULL);
-   void *func = NULL;
+   void *fun = NULL;
 
-   if (!evgl_safe_extension_get(name, &func))
+   if (!evgl_safe_extension_get(name, &fun))
      {
         DBG("The extension '%s' is not safe to use with Evas GL or is not "
             "supported on this platform.", name);
         return NULL;
      }
 
-   if (func)
-     return func;
+   if (fun)
+     return fun;
 
    if (re->evgl_funcs && re->evgl_funcs->proc_address_get)
      return re->evgl_funcs->proc_address_get(name);
@@ -2792,7 +2794,112 @@ eng_ector_end(void *data, void *context EINA_UNUSED, Ector_Surface *ector,
      }
 }
 
-static Evas_Func func, pfunc;
+static void *
+eng_image_data_map(void *engdata EINA_UNUSED, void **image,
+                   int *length, int *stride,
+                   int x, int y, int w, int h,
+                   Evas_Colorspace cspace, Efl_Gfx_Buffer_Access_Mode mode)
+{
+   Eina_Bool cow = EINA_FALSE, to_write = EINA_FALSE;
+   Evas_GL_Image_Data_Map *map = NULL;
+   Evas_GL_Image *im;
+   void *ret;
+
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(image && *image, NULL);
+   im = *image;
+
+   if (mode & EFL_GFX_BUFFER_ACCESS_MODE_COW)
+     cow = EINA_TRUE;
+
+   if (mode & EFL_GFX_BUFFER_ACCESS_MODE_WRITE)
+     to_write = EINA_TRUE;
+
+   if (im->im)
+     {
+        int len = 0, strid = 0;
+
+        // Call sw generic implementation. Should work for simple cases.
+        ret = pfunc.image_data_map(NULL, (void **) &im->im, &len, &strid,
+                                   x, y, w, h, cspace, mode);
+        if (ret)
+          {
+             map = calloc(1, sizeof(*map));
+             map->cspace = cspace;
+             map->rx = x;
+             map->ry = y;
+             map->rw = w;
+             map->rh = h;
+             map->mode = mode;
+             map->size = len;
+             map->stride = strid;
+             map->im = im->im; // ref?
+             map->ptr = ret;
+             im->maps = eina_inlist_prepend(im->maps, EINA_INLIST_GET(map));
+          }
+        if (length) *length = len;
+        if (stride) *stride = strid;
+        return ret;
+     }
+
+   // TODO: glReadPixels from FBO if possible
+
+   return NULL;
+}
+
+static Eina_Bool
+eng_image_data_unmap(void *engdata EINA_UNUSED, void *image, void *memory, int length)
+{
+   Evas_GL_Image_Data_Map *map;
+   Evas_GL_Image *im = image;
+   Eina_Bool found = EINA_FALSE;
+
+   if (!im || !memory)
+     return EINA_FALSE;
+
+   EINA_INLIST_FOREACH(im->maps, map)
+     {
+        if ((map->ptr == memory) && (map->size == length))
+          {
+             found = EINA_TRUE;
+             if (map->im)
+               found = pfunc.image_data_unmap(NULL, map->im, memory, length);
+             if (found)
+               {
+                  if (im->im && im->tex &&
+                      (map->mode & EFL_GFX_BUFFER_ACCESS_MODE_WRITE))
+                    evas_gl_common_texture_update(im->tex, im->im);
+                  im->maps = eina_inlist_remove(im->maps, EINA_INLIST_GET(map));
+                  free(map);
+               }
+             return found;
+          }
+     }
+
+   ERR("failed to unmap region %p (%u bytes)", memory, length);
+   return EINA_FALSE;
+}
+
+static int
+eng_image_data_maps_get(void *engdata EINA_UNUSED, const void *image, void **maps, int *lengths)
+{
+   Evas_GL_Image_Data_Map *map;
+   const Evas_GL_Image *im = image;
+   int k = 0;
+
+   if (!im) return -1;
+
+   if (!maps || !lengths)
+     return eina_inlist_count(im->maps);
+
+   EINA_INLIST_FOREACH(im->maps, map)
+     {
+        maps[k] = map->ptr;
+        lengths[k] = map->size;
+        k++;
+     }
+
+   return k;
+}
 
 static int
 module_open(Evas_Module *em)
@@ -2809,11 +2916,6 @@ module_open(Evas_Module *em)
         return 0;
      }
 
-   /* disable map/unmap for now as it's not implemented */
-   pfunc.image_data_map = NULL;
-   pfunc.image_data_unmap = NULL;
-   pfunc.image_data_maps_get = NULL;
-
    ector_init();
    ector_glsym_set(dlsym, RTLD_DEFAULT);
 
@@ -2879,6 +2981,10 @@ module_open(Evas_Module *em)
    ORD(image_cache_set);
    ORD(image_cache_get);
 
+   ORD(image_data_map);
+   ORD(image_data_unmap);
+   ORD(image_data_maps_get);
+
    ORD(font_cache_flush);
    ORD(font_cache_set);
    ORD(font_cache_get);
index 628ae5e..314415c 100644 (file)
@@ -1461,12 +1461,14 @@ eng_image_data_map(void *engdata EINA_UNUSED, void **image,
 {
    Eina_Bool cow = EINA_FALSE, to_write = EINA_FALSE;
    RGBA_Image_Data_Map *map;
-   RGBA_Image *im = *image;
-   Image_Entry *ie = &im->cache_entry;
+   RGBA_Image *im;
+   Image_Entry *ie;
    int src_stride, src_offset;
    void *data;
 
    EINA_SAFETY_ON_FALSE_RETURN_VAL(image && *image, NULL);
+   im = *image;
+   ie = &im->cache_entry;
 
    // FIXME: implement planes support (YUV, RGB565, ETC1+Alpha)
    // FIXME: implement YUV support (im->cs.data)
@@ -1711,18 +1713,16 @@ eng_image_data_unmap(void *engdata EINA_UNUSED, void *image, void *memory, int l
              im->maps = (RGBA_Image_Data_Map *)
                    eina_inlist_remove(EINA_INLIST_GET(im->maps), EINA_INLIST_GET(map));
              free(map);
-             break;
+             return EINA_TRUE;
           }
      }
 
-   if (!found)
-     ERR("failed to unmap region %p (%u bytes)", memory, length);
-
-   return found;
+   ERR("failed to unmap region %p (%u bytes)", memory, length);
+   return EINA_FALSE;
 }
 
 static int
-eng_image_data_maps_get(void *engdata EINA_UNUSED, const void *image, void **maps, int *lenghts)
+eng_image_data_maps_get(void *engdata EINA_UNUSED, const void *image, void **maps, int *lengths)
 {
    RGBA_Image_Data_Map *map;
    const RGBA_Image *im = image;
@@ -1730,13 +1730,13 @@ eng_image_data_maps_get(void *engdata EINA_UNUSED, const void *image, void **map
 
    if (!im) return -1;
 
-   if (!maps || !lenghts)
+   if (!maps || !lengths)
      return eina_inlist_count(EINA_INLIST_GET(im->maps));
 
    EINA_INLIST_FOREACH(EINA_INLIST_GET(im->maps), map)
      {
         maps[k] = map->ptr;
-        lenghts[k] = map->size;
+        lengths[k] = map->size;
         k++;
      }