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.andre@samsung.com>
This commit is contained in:
Dongyeon Kim 2015-02-03 20:36:41 +09:00 committed by Jean-Philippe Andre
parent defcc1f2ac
commit c0d990c724
6 changed files with 378 additions and 26 deletions

View File

@ -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 \

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
//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 ((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 ((!ns) && (!im->native.data)) return im;
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
}

View File

@ -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

View File

@ -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;
}