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