summaryrefslogtreecommitdiff
path: root/src/lib/ecore_wl2/ecore_wl2_buffer.c
diff options
context:
space:
mode:
authorDerek Foreman <derekf@osg.samsung.com>2017-11-13 16:26:09 -0600
committerDerek Foreman <derekf@osg.samsung.com>2017-11-15 11:54:37 -0600
commit9fdcf7d0eb8cec792a84ac0f0aac9c2ea5389293 (patch)
tree9d0618096907252687ef54524afe8ac14d87728d /src/lib/ecore_wl2/ecore_wl2_buffer.c
parentf6ec5b961b4cec2b5784b4ecbd8f33159b786cbc (diff)
wayland_shm/ecore_wl2: Move buffer allocation into ecore_wl2
This moves all the platform specific buffer allocation into ecore_wl2 instead of the engine. Note that this makes an internal struct available in the header. This will be removed shortly.
Diffstat (limited to 'src/lib/ecore_wl2/ecore_wl2_buffer.c')
-rw-r--r--src/lib/ecore_wl2/ecore_wl2_buffer.c559
1 files changed, 559 insertions, 0 deletions
diff --git a/src/lib/ecore_wl2/ecore_wl2_buffer.c b/src/lib/ecore_wl2/ecore_wl2_buffer.c
new file mode 100644
index 0000000000..32e779ed00
--- /dev/null
+++ b/src/lib/ecore_wl2/ecore_wl2_buffer.c
@@ -0,0 +1,559 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include "ecore_wl2_private.h"
6
7#include <sys/types.h>
8#include <sys/stat.h>
9#include <fcntl.h>
10#include <dlfcn.h>
11#include <drm_fourcc.h>
12#include <intel_bufmgr.h>
13#include <i915_drm.h>
14
15#include <exynos_drm.h>
16#include <exynos_drmif.h>
17#include <sys/mman.h>
18
19#include "linux-dmabuf-unstable-v1-client-protocol.h"
20
21#define SYM(lib, xx) \
22 do { \
23 sym_## xx = dlsym(lib, #xx); \
24 if (!(sym_ ## xx)) { \
25 fail = EINA_TRUE; \
26 } \
27 } while (0)
28
29static int drm_fd = -1;
30
31typedef struct _Dmabuf_Surface Dmabuf_Surface;
32
33typedef struct _Ecore_Wl2_Buffer Ecore_Wl2_Buffer;
34typedef struct _Buffer_Handle Buffer_Handle;
35typedef struct _Buffer_Manager Buffer_Manager;
36struct _Buffer_Manager
37{
38 Buffer_Handle *(*alloc)(Buffer_Manager *self, const char *name, int w, int h, unsigned long *stride, int32_t *fd);
39 struct wl_buffer *(*to_buffer)(Ecore_Wl2_Display *ewd, Ecore_Wl2_Buffer *db);
40 void *(*map)(Ecore_Wl2_Buffer *buf);
41 void (*unmap)(Ecore_Wl2_Buffer *buf);
42 void (*discard)(Ecore_Wl2_Buffer *buf);
43 void (*manager_destroy)(void);
44 void *priv;
45 void *dl_handle;
46 int refcount;
47 Eina_Bool destroyed;
48};
49
50static Buffer_Manager *buffer_manager = NULL;
51
52static drm_intel_bufmgr *(*sym_drm_intel_bufmgr_gem_init)(int fd, int batch_size) = NULL;
53static int (*sym_drm_intel_bo_unmap)(drm_intel_bo *bo) = NULL;
54static int (*sym_drm_intel_bo_map)(drm_intel_bo *bo) = NULL;
55static drm_intel_bo *(*sym_drm_intel_bo_alloc_tiled)(drm_intel_bufmgr *mgr, const char *name, int x, int y, int cpp, uint32_t *tile, unsigned long *pitch, unsigned long flags) = NULL;
56static void (*sym_drm_intel_bo_unreference)(drm_intel_bo *bo) = NULL;
57static int (*sym_drmPrimeHandleToFD)(int fd, uint32_t handle, uint32_t flags, int *prime_fd) = NULL;
58static void (*sym_drm_intel_bufmgr_destroy)(drm_intel_bufmgr *) = NULL;
59
60static struct exynos_device *(*sym_exynos_device_create)(int fd) = NULL;
61static struct exynos_bo *(*sym_exynos_bo_create)(struct exynos_device *dev, size_t size, uint32_t flags) = NULL;
62static void *(*sym_exynos_bo_map)(struct exynos_bo *bo) = NULL;
63static void (*sym_exynos_bo_destroy)(struct exynos_bo *bo) = NULL;
64static void (*sym_exynos_device_destroy)(struct exynos_device *) = NULL;
65
66static void
67buffer_release(void *data, struct wl_buffer *buffer EINA_UNUSED)
68{
69 Ecore_Wl2_Buffer *b = data;
70
71 b->busy = EINA_FALSE;
72 if (b->orphaned) ecore_wl2_buffer_destroy(b);
73}
74
75static const struct wl_buffer_listener buffer_listener =
76{
77 buffer_release
78};
79
80static struct wl_buffer *
81_evas_dmabuf_wl_buffer_from_dmabuf(Ecore_Wl2_Display *ewd, Ecore_Wl2_Buffer *db)
82{
83 struct wl_buffer *buf;
84 struct zwp_linux_dmabuf_v1 *dmabuf;
85 struct zwp_linux_buffer_params_v1 *dp;
86 uint32_t flags = 0;
87 uint32_t format;
88
89 if (db->alpha)
90 format = DRM_FORMAT_ARGB8888;
91 else
92 format = DRM_FORMAT_XRGB8888;
93
94 dmabuf = ecore_wl2_display_dmabuf_get(ewd);
95 dp = zwp_linux_dmabuf_v1_create_params(dmabuf);
96 zwp_linux_buffer_params_v1_add(dp, db->fd, 0, 0, db->stride, 0, 0);
97 buf = zwp_linux_buffer_params_v1_create_immed(dp, db->w, db->h,
98 format, flags);
99 wl_buffer_add_listener(buf, &buffer_listener, db);
100 zwp_linux_buffer_params_v1_destroy(dp);
101
102 return buf;
103}
104
105static Buffer_Handle *
106_intel_alloc(Buffer_Manager *self, const char *name, int w, int h, unsigned long *stride, int32_t *fd)
107{
108 uint32_t tile = I915_TILING_NONE;
109 drm_intel_bo *out;
110
111 out = sym_drm_intel_bo_alloc_tiled(self->priv, name, w, h, 4, &tile,
112 stride, 0);
113
114 if (!out) return NULL;
115
116 if (tile != I915_TILING_NONE) goto err;
117 /* First try to allocate an mmapable buffer with O_RDWR,
118 * if that fails retry unmappable - if the compositor is
119 * using GL it won't need to mmap the buffer and this can
120 * work - otherwise it'll reject this buffer and we'll
121 * have to fall back to shm rendering.
122 */
123 if (sym_drmPrimeHandleToFD(drm_fd, out->handle,
124 DRM_CLOEXEC | O_RDWR, fd) != 0)
125 if (sym_drmPrimeHandleToFD(drm_fd, out->handle,
126 DRM_CLOEXEC, fd) != 0) goto err;
127
128 return (Buffer_Handle *)out;
129
130err:
131 sym_drm_intel_bo_unreference(out);
132 return NULL;
133}
134
135static void *
136_intel_map(Ecore_Wl2_Buffer *buf)
137{
138 drm_intel_bo *bo;
139
140 bo = (drm_intel_bo *)buf->bh;
141 if (sym_drm_intel_bo_map(bo) != 0) return NULL;
142 return bo->virtual;
143}
144
145static void
146_intel_unmap(Ecore_Wl2_Buffer *buf)
147{
148 drm_intel_bo *bo;
149
150 bo = (drm_intel_bo *)buf->bh;
151 sym_drm_intel_bo_unmap(bo);
152}
153
154static void
155_intel_discard(Ecore_Wl2_Buffer *buf)
156{
157 drm_intel_bo *bo;
158
159 bo = (drm_intel_bo *)buf->bh;
160 sym_drm_intel_bo_unreference(bo);
161}
162
163static void
164_intel_manager_destroy()
165{
166 sym_drm_intel_bufmgr_destroy(buffer_manager->priv);
167}
168
169static Eina_Bool
170_intel_buffer_manager_setup(int fd)
171{
172 Eina_Bool fail = EINA_FALSE;
173 void *drm_intel_lib;
174
175 drm_intel_lib = dlopen("libdrm_intel.so", RTLD_LAZY | RTLD_GLOBAL);
176 if (!drm_intel_lib) return EINA_FALSE;
177
178 SYM(drm_intel_lib, drm_intel_bufmgr_gem_init);
179 SYM(drm_intel_lib, drm_intel_bo_unmap);
180 SYM(drm_intel_lib, drm_intel_bo_map);
181 SYM(drm_intel_lib, drm_intel_bo_alloc_tiled);
182 SYM(drm_intel_lib, drm_intel_bo_unreference);
183 SYM(drm_intel_lib, drm_intel_bufmgr_destroy);
184 SYM(drm_intel_lib, drmPrimeHandleToFD);
185
186 if (fail) goto err;
187
188 buffer_manager->priv = sym_drm_intel_bufmgr_gem_init(fd, 32);
189 if (!buffer_manager->priv) goto err;
190
191 buffer_manager->alloc = _intel_alloc;
192 buffer_manager->to_buffer = _evas_dmabuf_wl_buffer_from_dmabuf;
193 buffer_manager->map = _intel_map;
194 buffer_manager->unmap = _intel_unmap;
195 buffer_manager->discard = _intel_discard;
196 buffer_manager->manager_destroy = _intel_manager_destroy;
197 buffer_manager->dl_handle = drm_intel_lib;
198
199 return EINA_TRUE;
200
201err:
202 dlclose(drm_intel_lib);
203 return EINA_FALSE;
204}
205
206static Buffer_Handle *
207_exynos_alloc(Buffer_Manager *self, const char *name EINA_UNUSED, int w, int h, unsigned long *stride, int32_t *fd)
208{
209 size_t size = w * h * 4;
210 struct exynos_bo *out;
211
212 *stride = w * 4;
213 out = sym_exynos_bo_create(self->priv, size, 0);
214 if (!out) return NULL;
215 /* First try to allocate an mmapable buffer with O_RDWR,
216 * if that fails retry unmappable - if the compositor is
217 * using GL it won't need to mmap the buffer and this can
218 * work - otherwise it'll reject this buffer and we'll
219 * have to fall back to shm rendering.
220 */
221 if (sym_drmPrimeHandleToFD(drm_fd, out->handle,
222 DRM_CLOEXEC | O_RDWR, fd) != 0)
223 if (sym_drmPrimeHandleToFD(drm_fd, out->handle,
224 DRM_CLOEXEC, fd) != 0) goto err;
225
226 return (Buffer_Handle *)out;
227
228err:
229 sym_exynos_bo_destroy(out);
230 return NULL;
231}
232
233static void *
234_exynos_map(Ecore_Wl2_Buffer *buf)
235{
236 struct exynos_bo *bo;
237 void *ptr;
238
239 bo = (struct exynos_bo *)buf->bh;
240 ptr = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, buf->fd, 0);
241 if (ptr == MAP_FAILED) return NULL;
242 return ptr;
243}
244
245static void
246_exynos_unmap(Ecore_Wl2_Buffer *buf)
247{
248 struct exynos_bo *bo;
249
250 bo = (struct exynos_bo *)buf->bh;
251 munmap(buf->mapping, bo->size);
252}
253
254static void
255_exynos_discard(Ecore_Wl2_Buffer *buf)
256{
257 struct exynos_bo *bo;
258
259 bo = (struct exynos_bo *)buf->bh;
260 sym_exynos_bo_destroy(bo);
261}
262
263static void
264_exynos_manager_destroy()
265{
266 sym_exynos_device_destroy(buffer_manager->priv);
267}
268
269static Eina_Bool
270_exynos_buffer_manager_setup(int fd)
271{
272 Eina_Bool fail = EINA_FALSE;
273 void *drm_exynos_lib;
274 struct exynos_bo *bo;
275
276 drm_exynos_lib = dlopen("libdrm_exynos.so", RTLD_LAZY | RTLD_GLOBAL);
277 if (!drm_exynos_lib) return EINA_FALSE;
278
279 SYM(drm_exynos_lib, exynos_device_create);
280 SYM(drm_exynos_lib, exynos_bo_create);
281 SYM(drm_exynos_lib, exynos_bo_map);
282 SYM(drm_exynos_lib, exynos_bo_destroy);
283 SYM(drm_exynos_lib, exynos_device_destroy);
284 SYM(drm_exynos_lib, drmPrimeHandleToFD);
285
286 if (fail) goto err;
287
288 buffer_manager->priv = sym_exynos_device_create(fd);
289 if (!buffer_manager->priv) goto err;
290
291 /* _device_create succeeds on any arch, test harder */
292 bo = sym_exynos_bo_create(buffer_manager->priv, 32, 0);
293 if (!bo) goto err;
294
295 sym_exynos_bo_destroy(bo);
296
297 buffer_manager->alloc = _exynos_alloc;
298 buffer_manager->to_buffer = _evas_dmabuf_wl_buffer_from_dmabuf;
299 buffer_manager->map = _exynos_map;
300 buffer_manager->unmap = _exynos_unmap;
301 buffer_manager->discard = _exynos_discard;
302 buffer_manager->manager_destroy = _exynos_manager_destroy;
303 buffer_manager->dl_handle = drm_exynos_lib;
304 return EINA_TRUE;
305
306err:
307 dlclose(drm_exynos_lib);
308 return EINA_FALSE;
309}
310
311static Buffer_Handle *
312_wl_shm_alloc(Buffer_Manager *self EINA_UNUSED, const char *name EINA_UNUSED, int w, int h, unsigned long *stride, int32_t *fd)
313{
314 Efl_Vpath_File *file_obj;
315 Eina_Tmpstr *fullname;
316 size_t size = w * h * 4;
317 void *out = NULL;
318
319 file_obj = efl_vpath_manager_fetch(EFL_VPATH_MANAGER_CLASS,
320 "(:run:)/evas-wayland_shm-XXXXXX");
321 *fd = eina_file_mkstemp(efl_vpath_file_result_get(file_obj), &fullname);
322 efl_del(file_obj);
323 if (*fd < 0) return NULL;
324
325 unlink(fullname);
326 eina_tmpstr_del(fullname);
327
328 *stride = w * 4;
329 if (ftruncate(*fd, size) < 0) goto err;
330
331 out = mmap(NULL, size, (PROT_READ | PROT_WRITE), MAP_SHARED, *fd, 0);
332 if (out == MAP_FAILED) goto err;
333
334 return out;
335
336err:
337 close(*fd);
338 return NULL;
339}
340
341static void *
342_wl_shm_map(Ecore_Wl2_Buffer *buf)
343{
344 return buf->bh;
345}
346
347static void
348_wl_shm_unmap(Ecore_Wl2_Buffer *buf EINA_UNUSED)
349{
350 /* wl_shm is mapped for its lifetime */
351}
352
353static void
354_wl_shm_discard(Ecore_Wl2_Buffer *buf)
355{
356 munmap(buf->bh, buf->size);
357}
358
359static void
360_wl_shm_manager_destroy()
361{
362 /* Nop. */
363}
364
365static struct wl_buffer *
366_wl_shm_to_buffer(Ecore_Wl2_Display *ewd, Ecore_Wl2_Buffer *db)
367{
368 struct wl_buffer *buf;
369 struct wl_shm_pool *pool;
370 struct wl_shm *shm;
371 uint32_t format;
372
373 if (db->alpha)
374 format = WL_SHM_FORMAT_ARGB8888;
375 else
376 format = WL_SHM_FORMAT_XRGB8888;
377
378 shm = ecore_wl2_display_shm_get(ewd);
379 pool = wl_shm_create_pool(shm, db->fd, db->size);
380 buf = wl_shm_pool_create_buffer(pool, 0, db->w, db->h, db->stride, format);
381 wl_shm_pool_destroy(pool);
382 close(db->fd);
383 db->fd = -1;
384 wl_buffer_add_listener(buf, &buffer_listener, db);
385 return buf;
386}
387
388static Eina_Bool
389_wl_shm_buffer_manager_setup(int fd EINA_UNUSED)
390{
391 buffer_manager->alloc = _wl_shm_alloc;
392 buffer_manager->to_buffer = _wl_shm_to_buffer;
393 buffer_manager->map = _wl_shm_map;
394 buffer_manager->unmap = _wl_shm_unmap;
395 buffer_manager->discard = _wl_shm_discard;
396 buffer_manager->manager_destroy = _wl_shm_manager_destroy;
397 return EINA_TRUE;
398}
399
400EAPI Eina_Bool
401ecore_wl2_buffer_init(Ecore_Wl2_Buffer_Type types)
402{
403 int fd;
404 Eina_Bool dmabuf = types & ECORE_WL2_BUFFER_DMABUF;
405 Eina_Bool shm = types & ECORE_WL2_BUFFER_SHM;
406 Eina_Bool success = EINA_FALSE;
407
408 if (buffer_manager)
409 {
410 buffer_manager->refcount++;
411 return EINA_TRUE;
412 }
413
414 buffer_manager = calloc(1, sizeof(Buffer_Manager));
415 if (!buffer_manager) goto err_alloc;
416
417 fd = open("/dev/dri/renderD128", O_RDWR | O_CLOEXEC);
418 if (fd < 0) goto err_drm;
419
420 if (!getenv("EVAS_WAYLAND_SHM_DISABLE_DMABUF"))
421 {
422 success = dmabuf && _intel_buffer_manager_setup(fd);
423 if (!success) success = dmabuf && _exynos_buffer_manager_setup(fd);
424 }
425 if (!success) success = shm && _wl_shm_buffer_manager_setup(fd);
426 if (!success) goto err_bm;
427
428 drm_fd = fd;
429 buffer_manager->refcount = 1;
430 return EINA_TRUE;
431
432err_bm:
433 close(fd);
434err_drm:
435 free(buffer_manager);
436err_alloc:
437 return EINA_FALSE;
438}
439
440static void
441_buffer_manager_ref(void)
442{
443 buffer_manager->refcount++;
444}
445
446static void
447_buffer_manager_deref(void)
448{
449 buffer_manager->refcount--;
450 if (buffer_manager->refcount || !buffer_manager->destroyed) return;
451
452 if (buffer_manager->manager_destroy) buffer_manager->manager_destroy();
453 free(buffer_manager);
454 buffer_manager = NULL;
455 close(drm_fd);
456}
457
458/* Currently no callers, but that will change...
459static void
460_buffer_manager_destroy(void)
461{
462 if (buffer_manager->destroyed) return;
463 buffer_manager->destroyed = EINA_TRUE;
464 _buffer_manager_deref();
465}
466*/
467
468static Buffer_Handle *
469_buffer_manager_alloc(const char *name, int w, int h, unsigned long *stride, int32_t *fd)
470{
471 Buffer_Handle *out;
472
473 _buffer_manager_ref();
474 out = buffer_manager->alloc(buffer_manager, name, w, h, stride, fd);
475 if (!out) _buffer_manager_deref();
476 return out;
477}
478
479EAPI struct wl_buffer *
480ecore_wl2_buffer_wl_buffer_get(Ecore_Wl2_Display *ewd, Ecore_Wl2_Buffer *buf)
481{
482 return buffer_manager->to_buffer(ewd, buf);
483}
484
485EAPI void *
486ecore_wl2_buffer_map(Ecore_Wl2_Buffer *buf)
487{
488 void *out;
489
490 _buffer_manager_ref();
491 out = buffer_manager->map(buf);
492 if (!out) _buffer_manager_deref();
493 return out;
494}
495
496EAPI void
497ecore_wl2_buffer_unmap(Ecore_Wl2_Buffer *buf)
498{
499 buffer_manager->unmap(buf);
500 _buffer_manager_deref();
501}
502
503EAPI void
504ecore_wl2_buffer_discard(Ecore_Wl2_Buffer *buf)
505{
506 buffer_manager->discard(buf);
507 _buffer_manager_deref();
508}
509
510EAPI void
511ecore_wl2_buffer_unlock(Ecore_Wl2_Buffer *b)
512{
513 ecore_wl2_buffer_unmap(b);
514 b->mapping = NULL;
515 b->locked = EINA_FALSE;
516}
517
518EAPI void
519ecore_wl2_buffer_destroy(Ecore_Wl2_Buffer *b)
520{
521 if (!b) return;
522
523 if (b->locked || b->busy)
524 {
525 b->orphaned = EINA_TRUE;
526 return;
527 }
528 if (b->fd != -1) close(b->fd);
529 if (b->mapping) ecore_wl2_buffer_unmap(b);
530 ecore_wl2_buffer_discard(b);
531 if (b->wl_buffer) wl_buffer_destroy(b->wl_buffer);
532 b->wl_buffer = NULL;
533 free(b);
534}
535
536EAPI Ecore_Wl2_Buffer *
537ecore_wl2_buffer_create(Ecore_Wl2_Display *ewd, int w, int h, Eina_Bool alpha)
538{
539 Ecore_Wl2_Buffer *out;
540
541 out = calloc(1, sizeof(Ecore_Wl2_Buffer));
542 if (!out) return NULL;
543
544 out->fd = -1;
545 out->alpha = alpha;
546 out->bh = _buffer_manager_alloc("name", w, h, &out->stride, &out->fd);
547 if (!out->bh)
548 {
549 free(out);
550 return NULL;
551 }
552 out->w = w;
553 out->h = h;
554 out->size = out->stride * h;
555
556 out->wl_buffer = ecore_wl2_buffer_wl_buffer_get(ewd, out);
557
558 return out;
559}