jpeg pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=c0d990c7246cde1c3b7286b22670e2fc01fce00b
commit c0d990c7246cde1c3b7286b22670e2fc01fce00b Author: Dongyeon Kim <dy5....@samsung.com> Date: Tue Feb 3 20:36:41 2015 +0900 evas/software_x11: implement tbm native surface type Summary: This native surface type is based on the tbm surface used for the tizen platform. For the software_x11 backend, image data is retrieved from tbm surface and color format converted appropriately. This will only work when libtbm.so is present in the system. @feature Test Plan: Local tests Reviewers: raster, cedric, jpeg, Hermet Subscribers: wonsik, cedric Signed-off-by: Jean-Philippe Andre <jp.an...@samsung.com> --- src/Makefile_Evas.am | 3 +- src/lib/evas/include/evas_common_private.h | 1 + .../evas/engines/software_generic/evas_engine.c | 2 + .../evas/engines/software_x11/evas_engine.c | 60 ++-- .../evas/engines/software_x11/evas_engine.h | 1 + .../evas/engines/software_x11/evas_native_tbm.c | 341 +++++++++++++++++++++ 6 files changed, 380 insertions(+), 28 deletions(-) diff --git a/src/Makefile_Evas.am b/src/Makefile_Evas.am index 9e8d040..0651d7f 100644 --- a/src/Makefile_Evas.am +++ b/src/Makefile_Evas.am @@ -980,7 +980,8 @@ SOFTWARE_X11_SOURCES = \ modules/evas/engines/software_x11/evas_engine.c \ modules/evas/engines/software_x11/evas_engine.h \ modules/evas/engines/software_x11/evas_x_egl.c \ -modules/evas/engines/software_x11/evas_x_egl.h +modules/evas/engines/software_x11/evas_x_egl.h \ +modules/evas/engines/software_x11/evas_native_tbm.c SOFTWARE_X11_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ -I$(top_srcdir)/src/lib/evas/include \ -I$(top_srcdir)/src/lib/evas/cserve2 \ diff --git a/src/lib/evas/include/evas_common_private.h b/src/lib/evas/include/evas_common_private.h index d41f24b..56dc039 100644 --- a/src/lib/evas/include/evas_common_private.h +++ b/src/lib/evas/include/evas_common_private.h @@ -839,6 +839,7 @@ struct _RGBA_Image void *data; //Evas_Native_Surface ns; struct { void (*bind) (void *data, void *image, int x, int y, int w, int h); + void (*unbind) (void *data, void *image); void (*free) (void *data, void *image); void *data; } func; diff --git a/src/modules/evas/engines/software_generic/evas_engine.c b/src/modules/evas/engines/software_generic/evas_engine.c index 3c13f80..a3b15b4 100644 --- a/src/modules/evas/engines/software_generic/evas_engine.c +++ b/src/modules/evas/engines/software_generic/evas_engine.c @@ -1508,6 +1508,8 @@ eng_image_draw(void *data EINA_UNUSED, void *context, void *surface, void *image evas_common_cpu_end_opt(); } + if (im->native.func.unbind) + im->native.func.unbind(data, image); return EINA_FALSE; } diff --git a/src/modules/evas/engines/software_x11/evas_engine.c b/src/modules/evas/engines/software_x11/evas_engine.c index fa74a38..acc4412 100644 --- a/src/modules/evas/engines/software_x11/evas_engine.c +++ b/src/modules/evas/engines/software_x11/evas_engine.c @@ -630,28 +630,31 @@ eng_image_native_set(void *data EINA_UNUSED, void *image, void *native) if (!im || !ns) return im; - if (ns) + if (ns->type == EVAS_NATIVE_SURFACE_X11) { - if (ns->type == EVAS_NATIVE_SURFACE_X11) + if (im->native.data) { - if (im->native.data) - { - //image have native surface already - Evas_Native_Surface *ens = im->native.data; - - if ((ens->type == ns->type) && - (ens->data.x11.visual == ns->data.x11.visual) && - (ens->data.x11.pixmap == ns->data.x11.pixmap)) - return im; - } - } - } - else - { - return im; - } - - if ((!ns) && (!im->native.data)) return im; + //image have native surface already + Evas_Native_Surface *ens = im->native.data; + + if ((ens->type == ns->type) && + (ens->data.x11.visual == ns->data.x11.visual) && + (ens->data.x11.pixmap == ns->data.x11.pixmap)) + return im; + } + } + else if (ns->type == EVAS_NATIVE_SURFACE_TBM) + { + if (im->native.data) + { + //image have native surface already + Evas_Native_Surface *ens = im->native.data; + + if ((ens->type == ns->type) && + (ens->data.tbm.buffer == ns->data.tbm.buffer)) + return im; + } + } //create new im and clean already existed im even though ns = NULL im2 = (RGBA_Image *)evas_cache_image_data(evas_common_image_cache_get(), @@ -664,21 +667,23 @@ eng_image_native_set(void *data EINA_UNUSED, void *image, void *native) } #ifdef EVAS_CSERVE2 - if (evas_cserve2_use_get() && evas_cache2_image_cached(&im->cache_entry)) - evas_cache2_image_close(&im->cache_entry); - else + if (evas_cserve2_use_get() && evas_cache2_image_cached(&im->cache_entry)) + evas_cache2_image_close(&im->cache_entry); + else #endif - evas_cache_image_drop(&im->cache_entry); + evas_cache_image_drop(&im->cache_entry); im = im2; - if (!ns) return im; - #ifdef BUILD_ENGINE_SOFTWARE_XLIB if (ns->type == EVAS_NATIVE_SURFACE_X11) { return evas_xlib_image_native_set(re->generic.ob, im, ns); } #endif + if (ns->type == EVAS_NATIVE_SURFACE_TBM) + { + return evas_native_tbm_image_set(re->generic.ob, im, ns); + } return im; } @@ -693,8 +698,9 @@ eng_image_native_get(void *data EINA_UNUSED, void *image) n = im->native.data; if (!n) return NULL; return &(n->ns); -#endif +#else return NULL; +#endif } diff --git a/src/modules/evas/engines/software_x11/evas_engine.h b/src/modules/evas/engines/software_x11/evas_engine.h index c29f62d..b561e2f 100644 --- a/src/modules/evas/engines/software_x11/evas_engine.h +++ b/src/modules/evas/engines/software_x11/evas_engine.h @@ -116,5 +116,6 @@ struct _Outbuf void evas_software_xlib_x_init(void); void evas_software_xcb_init(void); +void *evas_native_tbm_image_set(void *data, void *image, void *native); #endif diff --git a/src/modules/evas/engines/software_x11/evas_native_tbm.c b/src/modules/evas/engines/software_x11/evas_native_tbm.c new file mode 100644 index 0000000..ec7d037 --- /dev/null +++ b/src/modules/evas/engines/software_x11/evas_native_tbm.c @@ -0,0 +1,341 @@ +#include "evas_common_private.h" +#include "evas_xlib_image.h" +#include "evas_private.h" + +#include "Evas_Engine_Software_X11.h" +#include "evas_engine.h" + +#ifdef HAVE_DLSYM +# include <dlfcn.h> /* dlopen,dlclose,etc */ +#else +# warning native_tbm should not get compiled if dlsym is not found on the system! +#endif + +#define EVAS_ROUND_UP_4(num) (((num)+3) & ~3) +#define EVAS_ROUND_UP_8(num) (((num)+7) & ~7) + +#define TBM_SURF_PLANE_MAX 4 /**< maximum number of the planes */ + +/* option to map the tbm_surface */ +#define TBM_SURF_OPTION_READ (1 << 0) /**< access option to read */ +#define TBM_SURF_OPTION_WRITE (1 << 1) /**< access option to write */ + +#define __tbm_fourcc_code(a,b,c,d) ((uint32_t)(a) | ((uint32_t)(b) << 8) | \ + ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24)) + +#define TBM_FORMAT_RGBX8888 __tbm_fourcc_code('R', 'X', '2', '4') /* [31:0] R:G:B:x 8:8:8:8 little endian */ +#define TBM_FORMAT_RGBA8888 __tbm_fourcc_code('R', 'A', '2', '4') /* [31:0] R:G:B:A 8:8:8:8 little endian */ +#define TBM_FORMAT_BGRA8888 __tbm_fourcc_code('B', 'A', '2', '4') /* [31:0] B:G:R:A 8:8:8:8 little endian */ +#define TBM_FORMAT_NV12 __tbm_fourcc_code('N', 'V', '1', '2') /* 2x2 subsampled Cr:Cb plane */ +#define TBM_FORMAT_YUV420 __tbm_fourcc_code('Y', 'U', '1', '2') /* 2x2 subsampled Cb (1) and Cr (2) planes */ +#define TBM_FORMAT_YVU420 __tbm_fourcc_code('Y', 'V', '1', '2') /* 2x2 subsampled Cr (1) and Cb (2) planes */ + +static void *tbm_lib = NULL; +static int tbm_ref = 0; + +typedef struct _tbm_surface * tbm_surface_h; +typedef uint32_t tbm_format; + +typedef struct _tbm_surface_plane +{ + unsigned char *ptr; /**< Plane pointer */ + uint32_t size; /**< Plane size */ + uint32_t offset; /**< Plane offset */ + uint32_t stride; /**< Plane stride */ + + void *reserved1; /**< Reserved pointer1 */ + void *reserved2; /**< Reserved pointer2 */ + void *reserved3; /**< Reserved pointer3 */ +} tbm_surface_plane_s; + +typedef struct _tbm_surface_info +{ + uint32_t width; /**< TBM surface width */ + uint32_t height; /**< TBM surface height */ + tbm_format format; /**< TBM surface format*/ + uint32_t bpp; /**< TBM surface bbp */ + uint32_t size; /**< TBM surface size */ + + uint32_t num_planes; /**< The number of planes */ + tbm_surface_plane_s planes[TBM_SURF_PLANE_MAX]; /**< Array of planes */ + + void *reserved4; /**< Reserved pointer4 */ + void *reserved5; /**< Reserved pointer5 */ + void *reserved6; /**< Reserved pointer6 */ +} tbm_surface_info_s; + + +/* returns 0 on success */ +static int (*sym_tbm_surface_map) (tbm_surface_h surface, int opt, tbm_surface_info_s *info) = NULL; +static int (*sym_tbm_surface_unmap) (tbm_surface_h surface) = NULL; + +static Eina_Bool +tbm_init(void) +{ + if (tbm_lib) + { + tbm_ref++; + return EINA_TRUE; + } + + const char *tbm_libs[] = + { + "libtbm.so.1", + "libtbm.so.0", + NULL, + }; + int i, fail; +#define SYM(lib, xx) \ + do { \ + sym_ ## xx = dlsym(lib, #xx); \ + if (!(sym_ ## xx)) { \ + ERR("%s", dlerror()); \ + fail = 1; \ + } \ + } while (0) + + for (i = 0; tbm_libs[i]; i++) + { + tbm_lib = dlopen(tbm_libs[i], RTLD_LOCAL | RTLD_LAZY); + if (tbm_lib) + { + fail = 0; + SYM(tbm_lib, tbm_surface_map); + SYM(tbm_lib, tbm_surface_unmap); + if (fail) + { + dlclose(tbm_lib); + tbm_lib = NULL; + } + else break; + } + } + if (!tbm_lib) return EINA_FALSE; + + tbm_ref++; + return EINA_TRUE; +} + +static void +tbm_shutdown(void) +{ + if (tbm_ref > 0) + { + tbm_ref--; + + if (tbm_ref == 0) + { + if (tbm_lib) + { + dlclose(tbm_lib); + tbm_lib = NULL; + } + } + } +} + +static void +_evas_video_yv12(unsigned char *evas_data, const unsigned char *source_data, unsigned int w, unsigned int h, unsigned int output_height) +{ + const unsigned char **rows; + unsigned int i, j; + unsigned int rh; + unsigned int stride_y, stride_uv; + + rh = output_height; + + rows = (const unsigned char **)evas_data; + + stride_y = EVAS_ROUND_UP_4(w); + stride_uv = EVAS_ROUND_UP_8(w) / 2; + + for (i = 0; i < rh; i++) + rows[i] = &source_data[i * stride_y]; + + for (j = 0; j < (rh / 2); j++, i++) + rows[i] = &source_data[h * stride_y + + (rh / 2) * stride_uv + + j * stride_uv]; + + for (j = 0; j < (rh / 2); j++, i++) + rows[i] = &source_data[h * stride_y + j * stride_uv]; +} + +static void +_evas_video_i420(unsigned char *evas_data, const unsigned char *source_data, unsigned int w, unsigned int h, unsigned int output_height) +{ + const unsigned char **rows; + unsigned int i, j; + unsigned int rh; + unsigned int stride_y, stride_uv; + + rh = output_height; + + rows = (const unsigned char **)evas_data; + + stride_y = EVAS_ROUND_UP_4(w); + stride_uv = EVAS_ROUND_UP_8(w) / 2; + + for (i = 0; i < rh; i++) + rows[i] = &source_data[i * stride_y]; + + for (j = 0; j < (rh / 2); j++, i++) + rows[i] = &source_data[h * stride_y + j * stride_uv]; + + for (j = 0; j < (rh / 2); j++, i++) + rows[i] = &source_data[h * stride_y + + (rh / 2) * stride_uv + + j * stride_uv]; +} + +static void +_evas_video_nv12(unsigned char *evas_data, const unsigned char *source_data, unsigned int w, unsigned int h EINA_UNUSED, unsigned int output_height) +{ + const unsigned char **rows; + unsigned int i, j; + unsigned int rh; + + rh = output_height; + + rows = (const unsigned char **)evas_data; + + for (i = 0; i < rh; i++) + rows[i] = &source_data[i * w]; + + for (j = 0; j < (rh / 2); j++, i++) + rows[i] = &source_data[rh * w + j * w]; +} + +static void +_native_bind_cb(void *data EINA_UNUSED, void *image, int x EINA_UNUSED, int y EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED) +{ + RGBA_Image *im = image; + Native *n = im->native.data; + + if (!im) return; + if ((n) && (n->ns.type == EVAS_NATIVE_SURFACE_TBM)) + { + tbm_surface_info_s info; + + if (sym_tbm_surface_map(n->ns.data.tbm.buffer, TBM_SURF_OPTION_READ|TBM_SURF_OPTION_WRITE, &info)) return; + + im->image.data = (DATA32 *)info.planes[0].ptr; + } +} + +static void +_native_unbind_cb(void *data EINA_UNUSED, void *image) +{ + RGBA_Image *im = image; + Native *n = im->native.data; + + if (!im) return; + if ((n) && (n->ns.type == EVAS_NATIVE_SURFACE_TBM)) + { + sym_tbm_surface_unmap(n->ns.data.tbm.buffer); + } +} + +static void +_native_free_cb(void *data EINA_UNUSED, void *image) +{ + RGBA_Image *im = image; + Native *n = im->native.data; + + if (!im) return; + im->native.data = NULL; + im->native.func.bind = NULL; + im->native.func.unbind = NULL; + im->native.func.free = NULL; + im->native.func.data = NULL; + im->image.data = NULL; + + free(n); + + tbm_shutdown(); +} + +void * +evas_native_tbm_image_set(void *data EINA_UNUSED, void *image, void *native) +{ + Evas_Native_Surface *ns = native; + RGBA_Image *im = image; + + if (!im) return NULL; + if ((ns) && (ns->type == EVAS_NATIVE_SURFACE_TBM)) + { + void *pixels_data; + int w, h, stride; + tbm_format format; + tbm_surface_info_s info; + Native *n; + + if (!tbm_init()) + { + ERR("Could not initialize TBM!"); + return NULL; + } + + n = calloc(1, sizeof(Native)); + if (!n) return NULL; + + if (sym_tbm_surface_map(ns->data.tbm.buffer, TBM_SURF_OPTION_READ|TBM_SURF_OPTION_WRITE, &info)) + { + free(n); + return im; + } + + w = info.width; + h = info.height; + stride = info.planes[0].stride; + format = info.format; + pixels_data = info.planes[0].ptr; + im->cache_entry.w = stride; + im->cache_entry.h = h; + + // Handle all possible format here :"( + switch (format) + { + case TBM_FORMAT_RGBA8888: + case TBM_FORMAT_RGBX8888: + case TBM_FORMAT_BGRA8888: + im->cache_entry.w = stride / 4; + evas_cache_image_colorspace(&im->cache_entry, EVAS_COLORSPACE_ARGB8888); + im->cache_entry.flags.alpha = (format == TBM_FORMAT_RGBX8888 ? 0 : 1); + im->image.data = pixels_data; + im->image.no_free = 1; + break; + /* borrowing code from emotion here */ + case TBM_FORMAT_YVU420: /* EVAS_COLORSPACE_YCBCR422P601_PL */ + evas_cache_image_colorspace(&im->cache_entry, EVAS_COLORSPACE_YCBCR422P601_PL); + _evas_video_yv12(im->cs.data, pixels_data, w, h, h); + evas_common_image_colorspace_dirty(im); + break; + case TBM_FORMAT_YUV420: /* EVAS_COLORSPACE_YCBCR422P601_PL */ + evas_cache_image_colorspace(&im->cache_entry, EVAS_COLORSPACE_YCBCR422P601_PL); + _evas_video_i420(im->cs.data, pixels_data, w, h, h); + evas_common_image_colorspace_dirty(im); + break; + case TBM_FORMAT_NV12: /* EVAS_COLORSPACE_YCBCR420NV12601_PL */ + evas_cache_image_colorspace(&im->cache_entry, EVAS_COLORSPACE_YCBCR420NV12601_PL); + _evas_video_nv12(im->cs.data, pixels_data, w, h, h); + evas_common_image_colorspace_dirty(im); + break; + /* Not planning to handle those in software */ + default: + sym_tbm_surface_unmap(ns->data.tbm.buffer); + free(n); + return im; + } + + memcpy(n, ns, sizeof(Evas_Native_Surface)); + im->native.data = n; + im->native.func.bind = _native_bind_cb; + im->native.func.unbind = _native_unbind_cb; + im->native.func.free = _native_free_cb; + + sym_tbm_surface_unmap(ns->data.tbm.buffer); + } + return im; +} + --