1 #include "evas_common_private.h"
2 #include "evas_private.h"
3 #include "evas_native_common.h"
4 
5 #if defined HAVE_DLSYM && ! defined _WIN32
6 # include <dlfcn.h>      /* dlopen,dlclose,etc */
7 #elif _WIN32
8 # include <evil_private.h> /* dlopen dlclose dlsym */
9 #else
10 # warning native_tbm should not get compiled if dlsym is not found on the system!
11 #endif
12 
13 #define EVAS_ROUND_UP_4(num) (((num)+3) & ~3)
14 #define EVAS_ROUND_UP_8(num) (((num)+7) & ~7)
15 
16 #define TBM_SURF_PLANE_MAX 4 /**< maximum number of the planes  */
17 
18 /* option to map the tbm_surface */
19 #define TBM_SURF_OPTION_READ      (1 << 0) /**< access option to read  */
20 #define TBM_SURF_OPTION_WRITE     (1 << 1) /**< access option to write */
21 
22 #define __tbm_fourcc_code(a,b,c,d) ((uint32_t)(a) | ((uint32_t)(b) << 8) | \
23 			      ((uint32_t)(c) << 16) | ((uint32_t)(d) << 24))
24 
25 #define TBM_FORMAT_ARGB8888 __tbm_fourcc_code('A', 'R', '2', '4')
26 #define TBM_FORMAT_ABGR8888 __tbm_fourcc_code('A', 'B', '2', '4')
27 #define TBM_FORMAT_RGBX8888	__tbm_fourcc_code('R', 'X', '2', '4') /* [31:0] R:G:B:x 8:8:8:8 little endian */
28 #define TBM_FORMAT_RGBA8888	__tbm_fourcc_code('R', 'A', '2', '4') /* [31:0] R:G:B:A 8:8:8:8 little endian */
29 #define TBM_FORMAT_BGRA8888	__tbm_fourcc_code('B', 'A', '2', '4') /* [31:0] B:G:R:A 8:8:8:8 little endian */
30 #define TBM_FORMAT_NV12		__tbm_fourcc_code('N', 'V', '1', '2') /* 2x2 subsampled Cr:Cb plane */
31 #define TBM_FORMAT_YUV420	__tbm_fourcc_code('Y', 'U', '1', '2') /* 2x2 subsampled Cb (1) and Cr (2) planes */
32 #define TBM_FORMAT_YVU420	__tbm_fourcc_code('Y', 'V', '1', '2') /* 2x2 subsampled Cr (1) and Cb (2) planes */
33 
34 static void *tbm_lib = NULL;
35 static int   tbm_ref = 0;
36 
37 typedef struct _tbm_surface * tbm_surface_h;
38 typedef uint32_t tbm_format;
39 
40 typedef struct _tbm_surface_plane
41 {
42     unsigned char *ptr;   /**< Plane pointer */
43     uint32_t size;        /**< Plane size */
44     uint32_t offset;      /**< Plane offset */
45     uint32_t stride;      /**< Plane stride */
46 
47     void *reserved1;      /**< Reserved pointer1 */
48     void *reserved2;      /**< Reserved pointer2 */
49     void *reserved3;      /**< Reserved pointer3 */
50 } tbm_surface_plane_s;
51 
52 typedef struct _tbm_surface_info
53 {
54     uint32_t width;      /**< TBM surface width */
55     uint32_t height;     /**< TBM surface height */
56     tbm_format format;   /**< TBM surface format*/
57     uint32_t bpp;        /**< TBM surface bbp */
58     uint32_t size;       /**< TBM surface size */
59 
60     uint32_t num_planes;                            /**< The number of planes */
61     tbm_surface_plane_s planes[TBM_SURF_PLANE_MAX]; /**< Array of planes */
62 
63     void *reserved4;   /**< Reserved pointer4 */
64     void *reserved5;   /**< Reserved pointer5 */
65     void *reserved6;   /**< Reserved pointer6 */
66 } tbm_surface_info_s;
67 
68 /* returns 0 on success */
69 static int (*sym_tbm_surface_map) (tbm_surface_h surface, int opt, tbm_surface_info_s *info) = NULL;
70 static int (*sym_tbm_surface_unmap) (tbm_surface_h surface) = NULL;
71 static int (*sym_tbm_surface_get_info) (tbm_surface_h surface, tbm_surface_info_s *info) = NULL;
72 
73 EAPI int
_evas_native_tbm_init(void)74 _evas_native_tbm_init(void)
75 {
76    if (tbm_lib)
77      {
78         tbm_ref++;
79         return tbm_ref;
80      }
81 
82    const char *tbm_libs[] =
83    {
84       "libtbm.so.1",
85       "libtbm.so.0",
86       NULL,
87    };
88    int i, fail;
89 #define SYM(lib, xx)                            \
90   do {                                          \
91        sym_ ## xx = dlsym(lib, #xx);            \
92        if (!(sym_ ## xx)) {                     \
93             ERR("%s", dlerror());               \
94             fail = 1;                           \
95          }                                      \
96     } while (0)
97 
98    for (i = 0; tbm_libs[i]; i++)
99      {
100         tbm_lib = dlopen(tbm_libs[i], RTLD_LOCAL | RTLD_LAZY);
101         if (tbm_lib)
102           {
103              fail = 0;
104              SYM(tbm_lib, tbm_surface_map);
105              SYM(tbm_lib, tbm_surface_unmap);
106              SYM(tbm_lib, tbm_surface_get_info);
107              if (fail)
108                {
109                   dlclose(tbm_lib);
110                   tbm_lib = NULL;
111                }
112              else break;
113           }
114      }
115    if (!tbm_lib) return 0;
116 
117    tbm_ref++;
118    return tbm_ref;
119 }
120 
121 EAPI void
_evas_native_tbm_shutdown(void)122 _evas_native_tbm_shutdown(void)
123 {
124    if (tbm_ref > 0)
125      {
126         tbm_ref--;
127 
128         if (tbm_ref == 0)
129           {
130              if (tbm_lib)
131                {
132                   dlclose(tbm_lib);
133                   tbm_lib = NULL;
134                }
135           }
136      }
137 }
138 
139 static void
_evas_video_yv12(unsigned char * evas_data,const unsigned char * source_data,unsigned int w,unsigned int h,unsigned int output_height)140 _evas_video_yv12(unsigned char *evas_data, const unsigned char *source_data, unsigned int w, unsigned int h, unsigned int output_height)
141 {
142    const unsigned char **rows;
143    unsigned int i, j;
144    unsigned int rh;
145    unsigned int stride_y, stride_uv;
146 
147    rh = output_height;
148 
149    rows = (const unsigned char **)evas_data;
150 
151    stride_y = EVAS_ROUND_UP_4(w);
152    stride_uv = EVAS_ROUND_UP_8(w) / 2;
153 
154    for (i = 0; i < rh; i++)
155      rows[i] = &source_data[i * stride_y];
156 
157    for (j = 0; j < (rh / 2); j++, i++)
158      rows[i] = &source_data[h * stride_y +
159                             (rh / 2) * stride_uv +
160                             j * stride_uv];
161 
162    for (j = 0; j < (rh / 2); j++, i++)
163      rows[i] = &source_data[h * stride_y + j * stride_uv];
164 }
165 
166 static void
_evas_video_i420(unsigned char * evas_data,const unsigned char * source_data,unsigned int w,unsigned int h,unsigned int output_height)167 _evas_video_i420(unsigned char *evas_data, const unsigned char *source_data, unsigned int w, unsigned int h, unsigned int output_height)
168 {
169    const unsigned char **rows;
170    unsigned int i, j;
171    unsigned int rh;
172    unsigned int stride_y, stride_uv;
173 
174    rh = output_height;
175 
176    rows = (const unsigned char **)evas_data;
177 
178    stride_y = w;
179    stride_uv = w / 2;
180 
181    for (i = 0; i < rh; i++)
182      rows[i] = &source_data[i * stride_y];
183 
184    for (j = 0; j < ((rh + 1) / 2); j++, i++)
185      rows[i] = &source_data[h * stride_y + j * stride_uv];
186 
187    for (j = 0; j < (rh / 2); j++, i++)
188      rows[i] = &source_data[h * stride_y +
189                             ((rh + 1) / 2) * stride_uv +
190                             j * stride_uv];
191 }
192 
193 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)194 _evas_video_nv12(unsigned char *evas_data, const unsigned char *source_data, unsigned int w, unsigned int h EINA_UNUSED, unsigned int output_height)
195 {
196    const unsigned char **rows;
197    unsigned int i, j;
198    unsigned int rh;
199 
200    rh = output_height;
201 
202    rows = (const unsigned char **)evas_data;
203 
204    for (i = 0; i < rh; i++)
205      rows[i] = &source_data[i * w];
206 
207    for (j = 0; j < (rh / 2); j++, i++)
208      rows[i] = &source_data[rh * w + j * w];
209 }
210 
211 static void
_native_bind_cb(void * image,int x EINA_UNUSED,int y EINA_UNUSED,int w EINA_UNUSED,int h EINA_UNUSED)212 _native_bind_cb(void *image, int x EINA_UNUSED, int y EINA_UNUSED, int w EINA_UNUSED, int h EINA_UNUSED)
213 {
214    RGBA_Image *im = image;
215    tbm_surface_info_s info;
216    tbm_surface_h tbm_surf;
217 
218    if (!im) return;
219    Native *n = im->native.data;
220    if (!n) return;
221    if (n->ns.type != EVAS_NATIVE_SURFACE_TBM)
222      return;
223 
224    tbm_surf = n->ns.data.tbm.buffer;
225    if (sym_tbm_surface_map(tbm_surf, TBM_SURF_OPTION_READ|TBM_SURF_OPTION_WRITE, &info))
226      return;
227 
228    im->image.data = (DATA32 *)info.planes[0].ptr;
229 }
230 
231 static void
_native_unbind_cb(void * image)232 _native_unbind_cb(void *image)
233 {
234    RGBA_Image *im = image;
235    tbm_surface_h tbm_surf;
236 
237    if (!im) return;
238    Native *n = im->native.data;
239    if (!n) return;
240    if (n->ns.type != EVAS_NATIVE_SURFACE_TBM)
241      return;
242 
243    tbm_surf = n->ns.data.tbm.buffer;
244    sym_tbm_surface_unmap(tbm_surf);
245 }
246 
247 static void
_native_free_cb(void * image)248 _native_free_cb(void *image)
249 {
250    RGBA_Image *im = image;
251 
252    if (!im) return;
253    Native *n = im->native.data;
254 
255    im->native.data        = NULL;
256    im->native.func.bind   = NULL;
257    im->native.func.unbind = NULL;
258    im->native.func.free   = NULL;
259 
260    free(n);
261 
262    _evas_native_tbm_shutdown();
263 }
264 
265 EAPI int
_evas_native_tbm_surface_stride_get(void * data EINA_UNUSED,void * native)266 _evas_native_tbm_surface_stride_get(void *data EINA_UNUSED, void *native)
267 {
268    Evas_Native_Surface *ns = native;
269    tbm_surface_info_s info;
270    int stride;
271 
272    if (!ns)
273      return -1;
274 
275    if (!_evas_native_tbm_init())
276      {
277         ERR("Could not initialize TBM!");
278         return -1;
279      }
280 
281    if (sym_tbm_surface_get_info(ns->data.tbm.buffer, &info))
282      return -1;
283 
284    stride = info.planes[0].stride;
285    return stride;
286  }
287 
288 EAPI void *
_evas_native_tbm_surface_image_set(void * data EINA_UNUSED,void * image,void * native)289 _evas_native_tbm_surface_image_set(void *data EINA_UNUSED, void *image, void *native)
290 {
291    Evas_Native_Surface *ns = native;
292    RGBA_Image *im = image;
293    tbm_surface_h tbm_surf;
294 
295    if (!im) return NULL;
296 
297    if (ns)
298      {
299         void *pixels_data;
300         int h, stride;
301         tbm_format format;
302         tbm_surface_info_s info;
303         Native *n;
304 
305         if (ns->type != EVAS_NATIVE_SURFACE_TBM)
306           return NULL;
307 
308         tbm_surf = ns->data.tbm.buffer;
309 /*
310         if (!_evas_native_tbm_init())
311           {
312              ERR("Could not initialize TBM!");
313              return NULL;
314           }
315 */
316         n = calloc(1, sizeof(Native));
317         if (!n) return NULL;
318 
319         if (sym_tbm_surface_map(tbm_surf, TBM_SURF_OPTION_READ|TBM_SURF_OPTION_WRITE, &info))
320           {
321              free(n);
322              return im;
323           }
324 
325         h = info.height;
326         stride = info.planes[0].stride;
327         format = info.format;
328         pixels_data = info.planes[0].ptr;
329         im->cache_entry.w = stride;
330         im->cache_entry.h = h;
331 
332         // Handle all possible format here :"(
333         switch (format)
334           {
335            case TBM_FORMAT_RGBA8888:
336            case TBM_FORMAT_RGBX8888:
337            case TBM_FORMAT_BGRA8888:
338            case TBM_FORMAT_ARGB8888:
339            case TBM_FORMAT_ABGR8888:
340               im->cache_entry.w = stride / 4;
341               evas_cache_image_colorspace(&im->cache_entry, EVAS_COLORSPACE_ARGB8888);
342               im->cache_entry.flags.alpha = (format == TBM_FORMAT_RGBX8888 ? 0 : 1);
343               im->image.data = pixels_data;
344               im->image.no_free = 1;
345               break;
346               /* borrowing code from emotion here */
347            case TBM_FORMAT_YVU420: /* EVAS_COLORSPACE_YCBCR422P601_PL */
348               evas_cache_image_colorspace(&im->cache_entry, EVAS_COLORSPACE_YCBCR422P601_PL);
349               _evas_video_yv12(im->cs.data, pixels_data, stride, h, h);
350               evas_common_image_colorspace_dirty(im);
351               break;
352            case TBM_FORMAT_YUV420: /* EVAS_COLORSPACE_YCBCR422P601_PL */
353               evas_cache_image_colorspace(&im->cache_entry, EVAS_COLORSPACE_YCBCR422P601_PL);
354               _evas_video_i420(im->cs.data, pixels_data, stride, h, h);
355               evas_common_image_colorspace_dirty(im);
356               break;
357            case TBM_FORMAT_NV12: /* EVAS_COLORSPACE_YCBCR420NV12601_PL */
358               evas_cache_image_colorspace(&im->cache_entry, EVAS_COLORSPACE_YCBCR420NV12601_PL);
359               _evas_video_nv12(im->cs.data, pixels_data, stride, h, h);
360               evas_common_image_colorspace_dirty(im);
361               break;
362               /* Not planning to handle those in software */
363            default:
364               sym_tbm_surface_unmap(ns->data.tbm.buffer);
365               free(n);
366               return im;
367           }
368 
369         memcpy(n, ns, sizeof(Evas_Native_Surface));
370         im->native.data = n;
371         im->native.func.bind   = _native_bind_cb;
372         im->native.func.unbind = _native_unbind_cb;
373         im->native.func.free   = _native_free_cb;
374 
375         sym_tbm_surface_unmap(tbm_surf);
376      }
377    return im;
378 }
379