evas: Implement support for external buffers
authorJean-Philippe Andre <jp.andre@samsung.com>
Mon, 5 Sep 2016 04:53:00 +0000 (13:53 +0900)
committerJean-Philippe Andre <jp.andre@samsung.com>
Tue, 6 Sep 2016 07:55:00 +0000 (16:55 +0900)
This brings support for the eo api for external buffers (like
the old data_set / data_get). The new API now works with slices
and planes.

The internal code still relies on the old cs.data array for
YUV color conversion. This makes the code a little bit too
complex to my taste.

Tested with expedite for RGBA and YUV 422 601 planar, both
SW and GL engines (x11).

src/lib/evas/canvas/efl_canvas_image.c
src/lib/evas/common/evas_image_main.c
src/lib/evas/include/evas_common_private.h
src/lib/evas/include/evas_private.h
src/modules/evas/engines/gl_common/evas_gl_image.c
src/modules/evas/engines/gl_generic/evas_engine.c
src/modules/evas/engines/software_generic/evas_engine.c

index d1932d3..6e0f7e0 100644 (file)
@@ -639,34 +639,30 @@ _image_pixels_set(Evas_Object_Protected_Data *obj,
           }
      }
 
-   if (copy && !slice)
+   if (!slice || !slice->mem)
      {
+        // note: we release all planes at once
         if (o->engine_data)
           ENFN->image_free(ENDT, o->engine_data);
         o->engine_data = ENFN->image_new_from_copied_data(ENDT, w, h, NULL, o->cur->has_alpha, cspace);
      }
-   else if (copy)
-     {
-#warning TODO
-        CRI("NOT IMPLEMENTED YET");
-        //o->engine_data = ENFN->image_copy_slice(ENDT, o->engine_data, slice, w, h, stride, cspace, plane, o->cur->has_alpha)
-     }
    else
      {
-#warning TODO
-        CRI("NOT IMPLEMENTED YET");
-        //o->engine_data = ENFN->image_set_slice(ENDT, o->engine_data, slice, w, h, stride, cspace, plane, o->cur->has_alpha);
+        o->buffer_data_set = EINA_TRUE;
+        o->engine_data = ENFN->image_data_slice_add(ENDT, o->engine_data,
+                                                    slice, copy, w, h, stride,
+                                                    cspace, plane, o->cur->has_alpha);
      }
 
-   if ((o->cur->image.w != w) || (o->cur->image.h != h))
-     resized = EINA_TRUE;
-
    if (!o->engine_data)
      {
         ERR("Failed to create internal image");
         goto end;
      }
 
+   if ((o->cur->image.w != w) || (o->cur->image.h != h))
+     resized = EINA_TRUE;
+
    if (ENFN->image_scale_hint_set)
      ENFN->image_scale_hint_set(ENDT, o->engine_data, o->scale_hint);
 
@@ -698,6 +694,7 @@ end:
    if (resized)
      evas_object_inform_call_image_resize(obj->object);
 
+   efl_gfx_buffer_update_add(obj->object, 0, 0, w, h);
    return ret;
 }
 
index df2e5e2..ade4b9c 100644 (file)
@@ -246,12 +246,12 @@ _evas_common_rgba_image_plane_get(const RGBA_Image *im, int plane, Eina_Slice *s
           }
         return EINA_FALSE;
 
-        // YUV, assume contiguous memory within a plane (and no padding)
-        // single interleaved plane
+        // YUV, assume contiguous memory within a plane - padding ok
+        // 1 plane
       case EVAS_COLORSPACE_YCBCR422601_PL:
         if (plane != 0) return EINA_FALSE;
         slice->mem = csdata[0];
-        slice->len = (w * h * 3) / 2;
+        slice->len = (h > 1) ? ((size_t) (csdata[1] - csdata[0]) * h * 2) : (w * 2);
         return EINA_TRUE;
 
         // 2 planes
@@ -260,13 +260,13 @@ _evas_common_rgba_image_plane_get(const RGBA_Image *im, int plane, Eina_Slice *s
         if (plane == 0)
           {
              slice->mem = csdata[0];
-             slice->len = w * h;
+             slice->len = (h > 1) ? ((size_t) (csdata[1] - csdata[0]) * h) : w;
              return EINA_TRUE;
           }
         else if (plane == 1)
           {
              slice->mem = csdata[h];
-             slice->len = w * h / 4;
+             slice->len = (h > 1) ? ((size_t) (csdata[h+1] - csdata[h]) * h / 2) : w / 2;
              return EINA_TRUE;
           }
         return EINA_FALSE;
@@ -277,19 +277,19 @@ _evas_common_rgba_image_plane_get(const RGBA_Image *im, int plane, Eina_Slice *s
         if (plane == 0)
           {
              slice->mem = csdata[0];
-             slice->len = w * h;
+             slice->len = (h > 1) ? ((size_t) (csdata[1] - csdata[0]) * h) : w;
              return EINA_TRUE;
           }
         else if (plane == 1)
           {
              slice->mem = csdata[h];
-             slice->len = w * h / 4;
+             slice->len = (h > 1) ? ((size_t) (csdata[h+1] - csdata[h]) * h / 2) : w / 2;
              return EINA_TRUE;
           }
         else if (plane == 2)
           {
-             slice->mem = csdata[2 * h];
-             slice->len = w * h / 4;
+             slice->mem = csdata[h + h / 2];
+             slice->len = (h > 1) ? ((size_t) (csdata[h+h/2+1] - csdata[h+h/2]) * h / 2) : w / 2;
              return EINA_TRUE;
           }
         return EINA_FALSE;
index 8d66ad8..07ff291 100644 (file)
@@ -376,6 +376,8 @@ extern EAPI int _evas_log_dom_global;
 
 #define TILE_CACHE_LINE_SIZE      64
 
+#define RGBA_PLANE_MAX 3
+
 /*****************************************************************************/
 
 #define UNROLL2(op...) op op
@@ -422,7 +424,6 @@ typedef struct _RGBA_Pipe             RGBA_Pipe;
 typedef struct _RGBA_Pipe_Thread_Info RGBA_Pipe_Thread_Info;
 #endif
 typedef struct _RGBA_Image            RGBA_Image;
-typedef struct _RGBA_Image_Span       RGBA_Image_Span;
 typedef struct _RGBA_Draw_Context     RGBA_Draw_Context;
 typedef struct _RGBA_Polygon_Point    RGBA_Polygon_Point;
 typedef struct _RGBA_Map_Point        RGBA_Map_Point;
index 243c1fe..2b6c8df 100644 (file)
@@ -1373,6 +1373,9 @@ struct _Evas_Func
    Eina_Bool (*image_data_unmap)           (void *data, void *image, const Eina_Rw_Slice *slice);
    int (*image_data_maps_get)              (void *data, const void *image, const Eina_Rw_Slice **slices);
 
+   /* new api for direct data set (not put) */
+   void *(*image_data_slice_add)           (void *data, void *image, const Eina_Slice *slice, Eina_Bool copy, int w, int h, int stride, Evas_Colorspace space, int plane, Eina_Bool alpha);
+
    int (*image_native_init)                (void *data, Evas_Native_Surface_Type type);
    void (*image_native_shutdown)           (void *data, Evas_Native_Surface_Type type);
    void *(*image_native_set)               (void *data, void *image, void *native);
index d982fb4..b863bce 100644 (file)
@@ -360,13 +360,11 @@ evas_gl_common_image_new_from_data(Evas_Engine_GL_Context *gc, unsigned int w, u
         break;
       case EVAS_COLORSPACE_YCBCR422P601_PL:
       case EVAS_COLORSPACE_YCBCR422P709_PL:
-        if (im->tex) evas_gl_common_texture_free(im->tex, EINA_TRUE);
-       im->tex = NULL;
        im->cs.data = data;
        im->cs.no_free = 1;
        break;
       default:
-       abort();
+        ERR("color space not supported: %d", cspace);
        break;
      }
    return im;
@@ -414,16 +412,13 @@ evas_gl_common_image_new_from_copied_data(Evas_Engine_GL_Context *gc, unsigned i
         break;
       case EVAS_COLORSPACE_YCBCR422P601_PL:
       case EVAS_COLORSPACE_YCBCR422P709_PL:
-        if (im->tex) evas_gl_common_texture_free(im->tex, EINA_TRUE);
-        im->tex = NULL;
-        im->cs.no_free = 0;
         if (im->im->cache_entry.h > 0)
           im->cs.data = calloc(1, im->im->cache_entry.h * sizeof(unsigned char *) * 2);
         if ((data) && (im->cs.data))
           memcpy(im->cs.data, data, im->im->cache_entry.h * sizeof(unsigned char *) * 2);
         break;
       default:
-        abort();
+        ERR("color space not supported: %d", cspace);
         break;
      }
    return im;
index f383326..50c5f55 100644 (file)
@@ -245,7 +245,8 @@ eng_image_file_colorspace_get(void *data EINA_UNUSED, void *image)
 }
 
 static Eina_Bool
-eng_image_data_direct_get(void *data EINA_UNUSED, void *image, int plane, Eina_Slice *slice, Evas_Colorspace *cspace)
+eng_image_data_direct_get(void *data EINA_UNUSED, void *image, int plane,
+                          Eina_Slice *slice, Evas_Colorspace *cspace)
 {
    Evas_GL_Image *im = image;
 
@@ -2897,6 +2898,201 @@ eng_image_data_maps_get(void *engdata EINA_UNUSED, const void *image, const Eina
    return k;
 }
 
+static inline Eina_Bool
+_is_yuv(Efl_Gfx_Colorspace cspace)
+{
+   switch (cspace)
+     {
+      case EFL_GFX_COLORSPACE_YCBCR422P601_PL:
+      case EFL_GFX_COLORSPACE_YCBCR422P709_PL:
+      case EFL_GFX_COLORSPACE_YCBCR422601_PL:
+      case EFL_GFX_COLORSPACE_YCBCR420NV12601_PL:
+      case EFL_GFX_COLORSPACE_YCBCR420TM12601_PL:
+        return EINA_TRUE;
+
+      default:
+        return EINA_FALSE;
+     }
+}
+
+static void *
+eng_image_data_slice_add(void *engdata, void *image,
+                         const Eina_Slice *slice, Eina_Bool copy,
+                         int w, int h, int stride, Evas_Colorspace cspace,
+                         int plane, Eina_Bool alpha)
+{
+   const Eina_Bool use_cs = _is_yuv(cspace);
+   const unsigned char **cs_data;
+   Evas_GL_Image *im = image;
+   int bpp = 0;
+
+   // Note: This code is not very robust by choice. It should NOT be used
+   // in conjunction with data_put/data_get. Ever.
+   // Assume w,h,cspace,alpha to be correct.
+   // We still use cs.data for YUV.
+   // 'image' may be NULL, in that case create a new one. Otherwise, it must
+   // have been created by a previous call to this function.
+
+   if ((plane < 0) || (plane >= RGBA_PLANE_MAX)) goto fail;
+   if (!slice || !slice->mem) goto fail;
+   copy = !!copy;
+
+   // not implemented
+   if (use_cs && copy)
+     {
+        // To implement this, we should switch the internals to slices first,
+        // as this would give 3 planes rather than N rows of datas
+        ERR("Evas can not copy YUV data (not implemented yet).");
+        goto fail;
+     }
+
+   if (im && !im->im)
+     {
+        evas_gl_common_image_unref(im);
+        im = NULL;
+     }
+
+   // alloc
+   if (!im)
+     {
+        switch (cspace)
+          {
+           case EFL_GFX_COLORSPACE_ARGB8888:
+           case EFL_GFX_COLORSPACE_AGRY88:
+           case EFL_GFX_COLORSPACE_GRY8:
+             if (plane != 0) goto fail;
+             if (copy)
+               im = eng_image_new_from_copied_data(engdata, w, h, NULL, alpha, cspace);
+             else
+               im = eng_image_new_from_data(engdata, w, h, NULL, alpha, cspace);
+             break;
+
+           case EFL_GFX_COLORSPACE_YCBCR422P601_PL:
+           case EFL_GFX_COLORSPACE_YCBCR422P709_PL:
+           case EFL_GFX_COLORSPACE_YCBCR422601_PL:
+           case EFL_GFX_COLORSPACE_YCBCR420NV12601_PL:
+             im = eng_image_new_from_data(engdata, w, h, NULL, alpha, cspace);
+             break;
+
+           default:
+             // TODO: ETC, S3TC, YCBCR420TM12 (aka ST12 or tiled NV12)
+             goto fail;
+          }
+        if (!im) goto fail;
+     }
+
+   if (use_cs && (!im->cs.data || im->cs.no_free))
+     {
+        im->cs.data = calloc(1, h * sizeof(void *) * 2);
+        if (!im->cs.data) goto fail;
+        im->cs.no_free = EINA_FALSE;
+        if (!im->im->cs.no_free) free(im->im->cs.data);
+        im->im->cs.data = im->cs.data;
+        im->im->cs.no_free = EINA_TRUE;
+     }
+
+   // is this allocating image.data or cs.data?
+   evas_gl_common_image_alloc_ensure(im);
+   if (!im->im)
+     goto fail;
+
+   // assign
+   switch (cspace)
+     {
+      case EFL_GFX_COLORSPACE_ARGB8888:
+        bpp = 4;
+      case EFL_GFX_COLORSPACE_AGRY88:
+        if (!bpp) bpp = 2;
+      case EFL_GFX_COLORSPACE_GRY8:
+        if (!bpp) bpp = 1;
+        if (plane != 0) goto fail;
+        if (!im->im->image.data) goto fail;
+        if (!stride) stride = w * bpp;
+        if (copy)
+          {
+             for (int y = 0; y < h; y++)
+               {
+                  const unsigned char *src = slice->bytes + h * stride;
+                  unsigned char *dst = im->im->image.data8 + bpp * w;
+                  memcpy(dst, src, w * bpp);
+               }
+          }
+        else
+          {
+             if (stride != (bpp * w))
+               {
+                  ERR("invalid stride for zero-copy data set");
+                  goto fail;
+               }
+             im->im->image.data = (DATA32 *) slice->mem;
+             im->im->image.no_free = EINA_TRUE;
+          }
+        break;
+
+      case EFL_GFX_COLORSPACE_YCBCR422P601_PL:
+      case EFL_GFX_COLORSPACE_YCBCR422P709_PL:
+        /* YCbCr 4:2:2 Planar: Y rows, then the Cb, then Cr rows. */
+        cs_data = im->cs.data;
+        if (plane == 0)
+          {
+             if (!stride) stride = w;
+             for (int y = 0; y < h; y++)
+               cs_data[y] = slice->bytes + (y * stride);
+          }
+        else if (plane == 1)
+          {
+             if (!stride) stride = w / 2;
+             for (int y = 0; y < (h / 2); y++)
+               cs_data[h + y] = slice->bytes + (y * stride);
+          }
+        else if (plane == 2)
+          {
+             if (!stride) stride = w / 2;
+             for (int y = 0; y < (h / 2); y++)
+               cs_data[h + (h / 2) + y] = slice->bytes + (y * stride);
+          }
+        else goto fail;
+        break;
+
+      case EFL_GFX_COLORSPACE_YCBCR422601_PL:
+        /* YCbCr 4:2:2: lines of Y,Cb,Y,Cr bytes. */
+        if (plane != 0) goto fail;
+        if (!stride) stride = w * 2;
+        cs_data = im->cs.data;
+        for (int y = 0; y < h; y++)
+          cs_data[y] = slice->bytes + (y * stride);
+        break;
+
+      case EFL_GFX_COLORSPACE_YCBCR420NV12601_PL:
+        /* YCbCr 4:2:0: Y rows, then the Cb,Cr rows. */
+        if (!stride) stride = w;
+        cs_data = im->cs.data;
+        if (plane == 0)
+          {
+             for (int y = 0; y < h; y++)
+               cs_data[y] = slice->bytes + (y * stride);
+          }
+        else if (plane == 1)
+          {
+             for (int y = 0; y < (h / 2); y++)
+               cs_data[h + y] = slice->bytes + (y * stride);
+          }
+        break;
+
+        // ETC, S3TC, YCBCR420TM12 (aka ST12 or tiled NV12)
+      default:
+        ERR("unsupported color space %d", cspace);
+        goto fail;
+     }
+
+   evas_gl_common_image_dirty(im, 0, 0, 0, 0);
+   return im;
+
+fail:
+   if (im) eng_image_free(engdata, im);
+   return NULL;
+}
+
 static int
 module_open(Evas_Module *em)
 {
@@ -2980,6 +3176,7 @@ module_open(Evas_Module *em)
    ORD(image_data_map);
    ORD(image_data_unmap);
    ORD(image_data_maps_get);
+   ORD(image_data_slice_add);
 
    ORD(font_cache_flush);
    ORD(font_cache_set);
index e34463c..52505d8 100644 (file)
@@ -1749,6 +1749,194 @@ eng_image_data_maps_get(void *engdata EINA_UNUSED, const void *image, const Eina
    return k;
 }
 
+static inline Eina_Bool
+_is_yuv(Efl_Gfx_Colorspace cspace)
+{
+   switch (cspace)
+     {
+      case EFL_GFX_COLORSPACE_YCBCR422P601_PL:
+      case EFL_GFX_COLORSPACE_YCBCR422P709_PL:
+      case EFL_GFX_COLORSPACE_YCBCR422601_PL:
+      case EFL_GFX_COLORSPACE_YCBCR420NV12601_PL:
+      case EFL_GFX_COLORSPACE_YCBCR420TM12601_PL:
+        return EINA_TRUE;
+
+      default:
+        return EINA_FALSE;
+     }
+}
+
+static void *
+eng_image_data_slice_add(void *engdata, void *image,
+                         const Eina_Slice *slice, Eina_Bool copy,
+                         int w, int h, int stride, Evas_Colorspace cspace,
+                         int plane, Eina_Bool alpha)
+{
+   const Eina_Bool use_cs = _is_yuv(cspace);
+   const unsigned char **cs_data;
+   RGBA_Image *im = image;
+   int bpp = 0;
+
+   // Note: This code is not very robust by choice. It should NOT be used
+   // in conjunction with data_put/data_get. Ever.
+   // Assume w,h,cspace,alpha to be correct.
+   // We still use cs.data for YUV.
+   // 'image' may be NULL, in that case create a new one. Otherwise, it must
+   // have been created by a previous call to this function.
+
+   if ((plane < 0) || (plane >= RGBA_PLANE_MAX)) goto fail;
+   if (!slice || !slice->mem) goto fail;
+   copy = !!copy;
+
+   // not implemented
+   if (use_cs && copy)
+     {
+        // To implement this, we should switch the internals to slices first,
+        // as this would give 3 planes rather than N rows of datas
+        ERR("Evas can not copy YUV data (not implemented yet).");
+        goto fail;
+     }
+
+   // alloc
+   if (!im)
+     {
+        switch (cspace)
+          {
+           case EFL_GFX_COLORSPACE_ARGB8888:
+           case EFL_GFX_COLORSPACE_AGRY88:
+           case EFL_GFX_COLORSPACE_GRY8:
+             if (plane != 0) goto fail;
+             if (copy)
+               im = eng_image_new_from_copied_data(engdata, w, h, NULL, alpha, cspace);
+             else
+               im = eng_image_new_from_data(engdata, w, h, NULL, alpha, cspace);
+             break;
+
+           case EFL_GFX_COLORSPACE_YCBCR422P601_PL:
+           case EFL_GFX_COLORSPACE_YCBCR422P709_PL:
+           case EFL_GFX_COLORSPACE_YCBCR422601_PL:
+           case EFL_GFX_COLORSPACE_YCBCR420NV12601_PL:
+             // Use 'copied' to allocate the RGBA buffer
+             im = eng_image_new_from_copied_data(engdata, w, h, NULL, alpha, cspace);
+             break;
+
+           default:
+             // TODO: ETC, S3TC, YCBCR420TM12 (aka ST12 or tiled NV12)
+             goto fail;
+          }
+        if (!im) goto fail;
+     }
+   else
+     {
+        im = (RGBA_Image *) evas_cache_image_alone(&im->cache_entry);
+        if (!im) goto fail;
+     }
+
+   if (use_cs && (!im->cs.data || im->cs.no_free))
+     {
+        im->cs.data = calloc(1, h * sizeof(void *) * 2);
+        if (!im->cs.data) goto fail;
+        im->cs.no_free = EINA_FALSE;
+     }
+
+   // assign
+   switch (cspace)
+     {
+      case EFL_GFX_COLORSPACE_ARGB8888:
+        bpp = 4;
+      case EFL_GFX_COLORSPACE_AGRY88:
+        if (!bpp) bpp = 2;
+      case EFL_GFX_COLORSPACE_GRY8:
+        if (!bpp) bpp = 1;
+        if (plane != 0) goto fail;
+        if (!stride) stride = w * bpp;
+        if (copy)
+          {
+             for (int y = 0; y < h; y++)
+               {
+                  const unsigned char *src = slice->bytes + h * stride;
+                  unsigned char *dst = im->image.data8 + bpp * w;
+                  memcpy(dst, src, w * bpp);
+               }
+          }
+        else
+          {
+             if (stride != (bpp * w))
+               {
+                  ERR("invalid stride for zero-copy data set");
+                  goto fail;
+               }
+             im->image.data = (DATA32 *) slice->mem;
+             im->image.no_free = EINA_TRUE;
+          }
+        break;
+
+      case EFL_GFX_COLORSPACE_YCBCR422P601_PL:
+      case EFL_GFX_COLORSPACE_YCBCR422P709_PL:
+        /* YCbCr 4:2:2 Planar: Y rows, then the Cb, then Cr rows. */
+        cs_data = im->cs.data;
+        if (plane == 0)
+          {
+             if (!stride) stride = w;
+             for (int y = 0; y < h; y++)
+               cs_data[y] = slice->bytes + (y * stride);
+          }
+        else if (plane == 1)
+          {
+             if (!stride) stride = w / 2;
+             for (int y = 0; y < (h / 2); y++)
+               cs_data[h + y] = slice->bytes + (y * stride);
+          }
+        else if (plane == 2)
+          {
+             if (!stride) stride = w / 2;
+             for (int y = 0; y < (h / 2); y++)
+               cs_data[h + (h / 2) + y] = slice->bytes + (y * stride);
+          }
+        else goto fail;
+        evas_common_image_colorspace_dirty(im);
+        break;
+
+      case EFL_GFX_COLORSPACE_YCBCR422601_PL:
+        /* YCbCr 4:2:2: lines of Y,Cb,Y,Cr bytes. */
+        if (plane != 0) goto fail;
+        if (!stride) stride = w * 2;
+        cs_data = im->cs.data;
+        for (int y = 0; y < h; y++)
+          cs_data[y] = slice->bytes + (y * stride);
+        evas_common_image_colorspace_dirty(im);
+        break;
+
+      case EFL_GFX_COLORSPACE_YCBCR420NV12601_PL:
+        /* YCbCr 4:2:0: Y rows, then the Cb,Cr rows. */
+        if (!stride) stride = w;
+        cs_data = im->cs.data;
+        if (plane == 0)
+          {
+             for (int y = 0; y < h; y++)
+               cs_data[y] = slice->bytes + (y * stride);
+          }
+        else if (plane == 1)
+          {
+             for (int y = 0; y < (h / 2); y++)
+               cs_data[h + y] = slice->bytes + (y * stride);
+          }
+        evas_common_image_colorspace_dirty(im);
+        break;
+
+        // ETC, S3TC, YCBCR420TM12 (aka ST12 or tiled NV12)
+      default:
+        ERR("unsupported color space %d", cspace);
+        goto fail;
+     }
+
+   return im;
+
+fail:
+   if (im) eng_image_free(engdata, im);
+   return NULL;
+}
+
 static void
 _image_flip_horizontal(DATA32 *pixels_out, const DATA32 *pixels_in,
                        int iw, int ih)
@@ -4449,6 +4637,7 @@ static Evas_Func func =
      eng_image_data_map,
      eng_image_data_unmap,
      eng_image_data_maps_get,
+     eng_image_data_slice_add,
      eng_image_native_init,
      eng_image_native_shutdown,
      eng_image_native_set,