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