forked from enlightenment/efl
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:
parent
defcc1f2ac
commit
c0d990c724
|
@ -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 \
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue